Skip to content

Commit 1739528

Browse files
committed
Sema: Diagnose inconsistent use of @_weakLinked on import declarations.
1 parent 3e37452 commit 1739528

9 files changed

+127
-18
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

+7
Original file line numberDiff line numberDiff line change
@@ -2978,6 +2978,13 @@ ERROR(implementation_only_override_import_without_attr,none,
29782978
"override of %0 imported as implementation-only must be declared "
29792979
"'@_implementationOnly'", (DescriptiveDeclKind))
29802980

2981+
ERROR(import_attr_conflict,none,
2982+
"%0 inconsistently imported with %1",
2983+
(Identifier, DeclAttribute))
2984+
NOTE(import_attr_conflict_here,none,
2985+
"imported with %0 here",
2986+
(DeclAttribute))
2987+
29812988
// Derived conformances
29822989
ERROR(cannot_synthesize_init_in_extension_of_nonfinal,none,
29832990
"implementation of %0 for non-final class cannot be automatically "

Diff for: include/swift/AST/SourceFile.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ class SourceFile final : public FileUnit {
176176

177177
friend class HasImportsMatchingFlagRequest;
178178

179-
/// Indicates which import options have a valid caches. Storage for
179+
/// Indicates which import options have valid caches. Storage for
180180
/// \c HasImportsMatchingFlagRequest.
181181
ImportOptions validCachedImportOptions;
182182

@@ -352,9 +352,9 @@ class SourceFile final : public FileUnit {
352352
hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl,
353353
ImportQueryKind kind = TestableAndPrivate) const;
354354

355-
/// Does this source file have any implementation-only imports?
355+
/// Does this source file have any imports with \c flag?
356356
/// If not, we can fast-path module checks.
357-
bool hasImplementationOnlyImports() const;
357+
bool hasImportsWithFlag(ImportFlags flag) const;
358358

359359
/// Get the most permissive restriction applied to the imports of \p module.
360360
RestrictedImportKind getRestrictedImportKind(const ModuleDecl *module) const;

Diff for: include/swift/AST/TypeCheckRequests.h

+28-2
Original file line numberDiff line numberDiff line change
@@ -3263,15 +3263,15 @@ class ResolveTypeRequest
32633263
void simple_display(llvm::raw_ostream &out, const TypeResolution *resolution);
32643264
SourceLoc extractNearestSourceLoc(const TypeRepr *repr);
32653265

3266-
/// Checks to see if any of the imports in a module use `@_implementationOnly`
3266+
/// Checks to see if any of the imports in a module use \c @_implementationOnly
32673267
/// in one file and not in another.
32683268
///
32693269
/// Like redeclaration checking, but for imports.
32703270
///
32713271
/// This is a request purely to ensure that we don't need to perform the same
32723272
/// checking for each file we resolve imports for.
32733273
/// FIXME: Once import resolution operates at module-level, this checking can
3274-
/// integrated into it.
3274+
/// be integrated into it.
32753275
class CheckInconsistentImplementationOnlyImportsRequest
32763276
: public SimpleRequest<CheckInconsistentImplementationOnlyImportsRequest,
32773277
evaluator::SideEffect(ModuleDecl *),
@@ -3289,6 +3289,32 @@ class CheckInconsistentImplementationOnlyImportsRequest
32893289
bool isCached() const { return true; }
32903290
};
32913291

3292+
/// Checks to see if any of the imports in a module use \c @_weakLinked
3293+
/// in one file and not in another.
3294+
///
3295+
/// Like redeclaration checking, but for imports.
3296+
///
3297+
/// This is a request purely to ensure that we don't need to perform the same
3298+
/// checking for each file we resolve imports for.
3299+
/// FIXME: Once import resolution operates at module-level, this checking can
3300+
/// be integrated into it.
3301+
class CheckInconsistentWeakLinkedImportsRequest
3302+
: public SimpleRequest<CheckInconsistentWeakLinkedImportsRequest,
3303+
evaluator::SideEffect(ModuleDecl *),
3304+
RequestFlags::Cached> {
3305+
public:
3306+
using SimpleRequest::SimpleRequest;
3307+
3308+
private:
3309+
friend SimpleRequest;
3310+
3311+
evaluator::SideEffect evaluate(Evaluator &evaluator, ModuleDecl *mod) const;
3312+
3313+
public:
3314+
// Cached.
3315+
bool isCached() const { return true; }
3316+
};
3317+
32923318
/// Retrieves the primary source files in the main module.
32933319
// FIXME: This isn't really a type-checking request, if we ever split off a
32943320
// zone for more basic AST requests, this should be moved there.

Diff for: include/swift/AST/TypeCheckerTypeIDZone.def

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ SWIFT_REQUEST(TypeChecker, CallerSideDefaultArgExprRequest,
3333
Expr *(DefaultArgumentExpr *), SeparatelyCached, NoLocationInfo)
3434
SWIFT_REQUEST(TypeChecker, CheckInconsistentImplementationOnlyImportsRequest,
3535
evaluator::SideEffect(ModuleDecl *), Cached, NoLocationInfo)
36+
SWIFT_REQUEST(TypeChecker, CheckInconsistentWeakLinkedImportsRequest,
37+
evaluator::SideEffect(ModuleDecl *), Cached, NoLocationInfo)
3638
SWIFT_REQUEST(TypeChecker, CheckRedeclarationRequest,
3739
evaluator::SideEffect(ValueDecl *),
3840
Uncached, NoLocationInfo)

Diff for: lib/AST/Module.cpp

+3-5
Original file line numberDiff line numberDiff line change
@@ -2442,13 +2442,11 @@ void swift::simple_display(llvm::raw_ostream &out, ImportOptions options) {
24422442
out << " }";
24432443
}
24442444

2445-
bool SourceFile::hasImplementationOnlyImports() const {
2445+
bool SourceFile::hasImportsWithFlag(ImportFlags flag) const {
24462446
auto &ctx = getASTContext();
24472447
auto *mutableThis = const_cast<SourceFile *>(this);
2448-
return evaluateOrDefault(ctx.evaluator,
2449-
HasImportsMatchingFlagRequest{
2450-
mutableThis, ImportFlags::ImplementationOnly},
2451-
false);
2448+
return evaluateOrDefault(
2449+
ctx.evaluator, HasImportsMatchingFlagRequest{mutableThis, flag}, false);
24522450
}
24532451

24542452
bool SourceFile::hasTestableOrPrivateImport(

Diff for: lib/Sema/ImportResolution.cpp

+36-6
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,16 @@ void UnboundImport::diagnoseInvalidAttr(DeclAttrKind attrKind,
693693
attr->setInvalid();
694694
}
695695

696+
/// Returns true if any file in the module contains an import with \c flag.
697+
static bool moduleHasAnyImportsMatchingFlag(ModuleDecl *mod, ImportFlags flag) {
698+
for (const FileUnit *F : mod->getFiles()) {
699+
auto *SF = dyn_cast<SourceFile>(F);
700+
if (SF && SF->hasImportsWithFlag(flag))
701+
return true;
702+
}
703+
return false;
704+
}
705+
696706
/// Finds all import declarations for a single module that inconsistently match
697707
/// \c predicate and passes each pair of inconsistent imports to \c diagnose.
698708
template <typename Pred, typename Diag>
@@ -747,12 +757,7 @@ static void findInconsistentImports(ModuleDecl *mod, Pred predicate,
747757
evaluator::SideEffect
748758
CheckInconsistentImplementationOnlyImportsRequest::evaluate(
749759
Evaluator &evaluator, ModuleDecl *mod) const {
750-
bool hasAnyImplementationOnlyImports =
751-
llvm::any_of(mod->getFiles(), [](const FileUnit *F) -> bool {
752-
auto *SF = dyn_cast<SourceFile>(F);
753-
return SF && SF->hasImplementationOnlyImports();
754-
});
755-
if (!hasAnyImplementationOnlyImports)
760+
if (!moduleHasAnyImportsMatchingFlag(mod, ImportFlags::ImplementationOnly))
756761
return {};
757762

758763
auto diagnose = [mod](const ImportDecl *normalImport,
@@ -783,6 +788,31 @@ CheckInconsistentImplementationOnlyImportsRequest::evaluate(
783788
return {};
784789
}
785790

791+
evaluator::SideEffect
792+
CheckInconsistentWeakLinkedImportsRequest::evaluate(Evaluator &evaluator,
793+
ModuleDecl *mod) const {
794+
if (!moduleHasAnyImportsMatchingFlag(mod, ImportFlags::WeakLinked))
795+
return {};
796+
797+
auto diagnose = [mod](const ImportDecl *otherImport,
798+
const ImportDecl *weakLinkedImport) {
799+
auto attr = weakLinkedImport->getAttrs().getAttribute<WeakLinkedAttr>();
800+
auto &diags = mod->getDiags();
801+
diags
802+
.diagnose(otherImport, diag::import_attr_conflict,
803+
otherImport->getModule()->getName(), attr)
804+
.fixItInsert(otherImport->getStartLoc(), "@_weakLinked ");
805+
diags.diagnose(weakLinkedImport, diag::import_attr_conflict_here, attr);
806+
};
807+
808+
auto predicate = [](ImportDecl *decl) {
809+
return decl->getAttrs().hasAttribute<WeakLinkedAttr>();
810+
};
811+
812+
findInconsistentImports(mod, predicate, diagnose);
813+
return {};
814+
}
815+
786816
//===----------------------------------------------------------------------===//
787817
// MARK: Scoped imports
788818
//===----------------------------------------------------------------------===//

Diff for: lib/Sema/TypeCheckAccess.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1516,7 +1516,7 @@ swift::getDisallowedOriginKind(const Decl *decl,
15161516
// just in this case.
15171517
if (howImported == RestrictedImportKind::Implicit &&
15181518
!SF->getASTContext().isSwiftVersionAtLeast(6) &&
1519-
!SF->hasImplementationOnlyImports()) {
1519+
!SF->hasImportsWithFlag(ImportFlags::ImplementationOnly)) {
15201520
downgradeToWarning = DowngradeToWarning::Yes;
15211521
}
15221522

Diff for: lib/Sema/TypeChecker.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -329,12 +329,16 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const {
329329

330330
diagnoseUnnecessaryPreconcurrencyImports(*SF);
331331

332-
// Check to see if there's any inconsistent @_implementationOnly imports.
332+
// Check to see if there are any inconsistent imports.
333333
evaluateOrDefault(
334334
Ctx.evaluator,
335335
CheckInconsistentImplementationOnlyImportsRequest{SF->getParentModule()},
336336
{});
337337

338+
evaluateOrDefault(
339+
Ctx.evaluator,
340+
CheckInconsistentWeakLinkedImportsRequest{SF->getParentModule()}, {});
341+
338342
// Perform various AST transforms we've been asked to perform.
339343
if (!Ctx.hadError() && Ctx.LangOpts.DebuggerTestingTransform)
340344
performDebuggerTestingTransform(*SF);
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// Check that the diagnostics are produced regardless of what primary file we're using.
5+
// RUN: %target-swift-frontend -typecheck -primary-file %t/1.swift %t/2.swift %t/3.swift -I %S/Inputs/inconsistent-implementation-only/ -verify
6+
// RUN: %target-swift-frontend -typecheck %t/1.swift -primary-file %t/2.swift %t/3.swift -I %S/Inputs/inconsistent-implementation-only/ -verify
7+
// RUN: %target-swift-frontend -typecheck %t/1.swift %t/2.swift -primary-file %t/3.swift -I %S/Inputs/inconsistent-implementation-only/ -verify
8+
// RUN: %target-swift-frontend -typecheck -primary-file %t/1.swift -primary-file %t/2.swift -primary-file %t/3.swift -I %S/Inputs/inconsistent-implementation-only/ -verify
9+
// RUN: %target-swift-frontend -typecheck %t/1.swift %t/2.swift %t/3.swift -I %S/Inputs/inconsistent-implementation-only/ -verify
10+
11+
// UNSUPPORTED: OS=windows-msvc
12+
13+
//--- 1.swift
14+
15+
@_weakLinked import NotSoSecret // expected-note {{imported with @_weakLinked here}}
16+
import NotSoSecret2 // expected-error {{'NotSoSecret2' inconsistently imported with @_weakLinked}} {{1-1=@_weakLinked }}
17+
import NotSoSecret3 // expected-error {{'NotSoSecret3' inconsistently imported with @_weakLinked}} {{1-1=@_weakLinked }}
18+
19+
@_weakLinked import ActuallySecret // no-error
20+
import ActuallyOkay // no-error
21+
22+
@_exported import Contradictory // expected-error {{'Contradictory' inconsistently imported with @_weakLinked}} {{12-12=@_weakLinked }}
23+
24+
//--- 2.swift
25+
26+
import NotSoSecret // expected-error {{'NotSoSecret' inconsistently imported with @_weakLinked}}
27+
@_weakLinked import NotSoSecret2 // expected-note 2 {{imported with @_weakLinked here}}
28+
import NotSoSecret3 // expected-error {{'NotSoSecret3' inconsistently imported with @_weakLinked}}
29+
30+
@_weakLinked import ActuallySecret // no-error
31+
import ActuallyOkay // no-error
32+
33+
@_weakLinked import Contradictory // expected-note {{imported with @_weakLinked here}}
34+
35+
//--- 3.swift
36+
37+
@_weakLinked import NotSoSecret
38+
import NotSoSecret2 // expected-error {{'NotSoSecret2' inconsistently imported with @_weakLinked}}
39+
@_weakLinked import NotSoSecret3 // expected-note 2 {{imported with @_weakLinked here}}
40+
41+
@_weakLinked import ActuallySecret // no-error
42+
import ActuallyOkay // no-error

0 commit comments

Comments
 (0)