Skip to content

Commit 78d2cf2

Browse files
committed
Sema: Teach ExportContext to compute whether we're inside an implicit declaration
1 parent d579b69 commit 78d2cf2

File tree

6 files changed

+37
-108
lines changed

6 files changed

+37
-108
lines changed

lib/Sema/TypeCheckAccess.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,8 +1541,8 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
15411541
}
15421542

15431543
public:
1544-
explicit DeclAvailabilityChecker(Decl *D)
1545-
: Where(ExportContext::forDeclSignature(D)) {}
1544+
explicit DeclAvailabilityChecker(ExportContext where)
1545+
: Where(where) {}
15461546

15471547
// Force all kinds to be handled at a lower level.
15481548
void visitDecl(Decl *D) = delete;
@@ -1857,9 +1857,12 @@ void swift::checkAccessControl(Decl *D) {
18571857
checkExtensionGenericParamAccess(ED);
18581858
}
18591859

1860-
//ExportabilityChecker().visit(D);
1861-
if (D->isImplicit() || isa<AccessorDecl>(D))
1860+
if (isa<AccessorDecl>(D))
18621861
return;
18631862

1864-
DeclAvailabilityChecker(D).visit(D);
1863+
auto where = ExportContext::forDeclSignature(D);
1864+
if (where.isImplicit())
1865+
return;
1866+
1867+
DeclAvailabilityChecker(where).visit(D);
18651868
}

lib/Sema/TypeCheckAttr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "MiscDiagnostics.h"
18+
#include "TypeCheckAvailability.h"
1819
#include "TypeCheckConcurrency.h"
1920
#include "TypeCheckObjC.h"
2021
#include "TypeCheckType.h"
@@ -1980,6 +1981,9 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
19801981
mainFunction = viableCandidates[0];
19811982
}
19821983

1984+
auto where = ExportContext::forDeclSignature(D);
1985+
diagnoseDeclAvailability(mainFunction, attr->getRange(), where, None);
1986+
19831987
auto *const func = FuncDecl::createImplicit(
19841988
context, StaticSpellingKind::KeywordStatic,
19851989
DeclName(context, DeclBaseName(context.Id_MainEntryPoint),

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 19 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@
3838
using namespace swift;
3939

4040
ExportContext::ExportContext(DeclContext *DC, FragileFunctionKind kind,
41-
bool spi, bool exported, bool deprecated)
41+
bool spi, bool exported, bool implicit,
42+
bool deprecated)
4243
: DC(DC), FragileKind(kind) {
4344
SPI = spi;
4445
Exported = exported;
46+
Implicit = implicit;
4547
Deprecated = deprecated;
4648
Reason = ExportabilityReason::General;
4749
}
@@ -180,12 +182,10 @@ ExportContext ExportContext::forDeclSignature(Decl *D) {
180182

181183
bool exported = ::isExported(D);
182184

183-
return ExportContext(DC, fragileKind, spi, exported, deprecated);
185+
return ExportContext(DC, fragileKind, spi, exported, implicit, deprecated);
184186
}
185187

186188
ExportContext ExportContext::forFunctionBody(DeclContext *DC) {
187-
assert(DC && "Use ExportContext::forImplicit() for implicit decls");
188-
189189
bool implicit = false;
190190
bool deprecated = false;
191191
forEachOuterDecl(DC,
@@ -204,12 +204,7 @@ ExportContext ExportContext::forFunctionBody(DeclContext *DC) {
204204
assert(fragileKind.kind == FragileFunctionKind::None);
205205
}
206206

207-
return ExportContext(DC, fragileKind, spi, exported, deprecated);
208-
}
209-
210-
ExportContext ExportContext::forImplicit() {
211-
return ExportContext(nullptr, FragileFunctionKind(),
212-
false, false, false);
207+
return ExportContext(DC, fragileKind, spi, exported, implicit, deprecated);
213208
}
214209

215210
ExportContext ExportContext::withReason(ExportabilityReason reason) const {
@@ -1700,29 +1695,6 @@ someEnclosingDeclMatches(SourceRange ReferenceRange,
17001695
return Pred(abstractSyntaxDeclForAvailableAttribute(DeclToSearch));
17011696
}
17021697

1703-
/// Returns true if the reference or any of its parents is an
1704-
/// implicit function.
1705-
static bool isInsideImplicitFunction(SourceRange ReferenceRange,
1706-
const DeclContext *DC) {
1707-
auto IsInsideImplicitFunc = [](const Decl *D) {
1708-
auto *AFD = dyn_cast<AbstractFunctionDecl>(D);
1709-
return AFD && AFD->isImplicit();
1710-
};
1711-
1712-
return someEnclosingDeclMatches(ReferenceRange, DC, IsInsideImplicitFunc);
1713-
}
1714-
1715-
/// Returns true if the reference or any of its parents is an
1716-
/// unavailable (or obsoleted) declaration.
1717-
static bool isInsideUnavailableDeclaration(SourceRange ReferenceRange,
1718-
const DeclContext *ReferenceDC) {
1719-
auto IsUnavailable = [](const Decl *D) {
1720-
return D->getAttrs().getUnavailable(D->getASTContext());
1721-
};
1722-
1723-
return someEnclosingDeclMatches(ReferenceRange, ReferenceDC, IsUnavailable);
1724-
}
1725-
17261698
/// Returns true if the reference or any of its parents is an
17271699
/// unconditional unavailable declaration for the same platform.
17281700
static bool isInsideCompatibleUnavailableDeclaration(
@@ -2135,21 +2107,14 @@ void TypeChecker::diagnoseIfDeprecated(SourceRange ReferenceRange,
21352107
if (!Attr)
21362108
return;
21372109

2138-
auto *ReferenceDC = Where.getDeclContext();
2139-
2140-
// We don't want deprecated declarations to trigger warnings
2141-
// in synthesized code.
2142-
if (ReferenceRange.isInvalid() &&
2143-
isInsideImplicitFunction(ReferenceRange, ReferenceDC)) {
2144-
return;
2145-
}
21462110
// We match the behavior of clang to not report deprecation warnings
21472111
// inside declarations that are themselves deprecated on all deployment
21482112
// targets.
21492113
if (Where.isDeprecated()) {
21502114
return;
21512115
}
21522116

2117+
auto *ReferenceDC = Where.getDeclContext();
21532118
auto &Context = ReferenceDC->getASTContext();
21542119
if (!Context.LangOpts.DisableAvailabilityChecking) {
21552120
AvailabilityContext RunningOSVersions =
@@ -2351,16 +2316,6 @@ bool swift::diagnoseExplicitUnavailability(
23512316
if (!Attr)
23522317
return false;
23532318

2354-
// Suppress the diagnostic if we are in synthesized code inside
2355-
// a synthesized function and the reference is lexically
2356-
// contained in a declaration that is itself marked unavailable.
2357-
// The right thing to do here is to not synthesize that code in the
2358-
// first place. rdar://problem/20491640
2359-
if (R.isInvalid() && isInsideImplicitFunction(R, DC) &&
2360-
isInsideUnavailableDeclaration(R, DC)) {
2361-
return false;
2362-
}
2363-
23642319
// Calling unavailable code from within code with the same
23652320
// unavailability is OK -- the eventual caller can't call the
23662321
// enclosing code in the same situations it wouldn't be able to
@@ -2512,20 +2467,6 @@ class AvailabilityWalker : public ASTWalker {
25122467
SmallVector<const Expr *, 16> ExprStack;
25132468
ExportContext Where;
25142469

2515-
/// Returns true if DC is an \c init(rawValue:) declaration and it is marked
2516-
/// implicit.
2517-
bool inSynthesizedInitRawValue() {
2518-
auto *DC = Where.getDeclContext();
2519-
auto init = dyn_cast_or_null<ConstructorDecl>(
2520-
DC->getInnermostDeclarationDeclContext());
2521-
2522-
return init &&
2523-
init->isImplicit() &&
2524-
init->getParameters()->size() == 1 &&
2525-
init->getParameters()->get(0)->getArgumentName() ==
2526-
Context.Id_rawValue;
2527-
}
2528-
25292470
public:
25302471
AvailabilityWalker(ExportContext Where)
25312472
: Context(Where.getDeclContext()->getASTContext()), Where(Where) {}
@@ -2548,20 +2489,8 @@ class AvailabilityWalker : public ASTWalker {
25482489
};
25492490

25502491
if (auto DR = dyn_cast<DeclRefExpr>(E)) {
2551-
DeclAvailabilityFlags flags = None;
2552-
if (inSynthesizedInitRawValue())
2553-
// HACK: If a raw-value enum has cases with `@available(introduced:)`
2554-
// attributes, the auto-derived `init(rawValue:)` will contain
2555-
// DeclRefExprs which reference those cases. It will also contain
2556-
// appropriate `guard #available` statements to keep them from running
2557-
// on older versions, but the availability checker can't verify that
2558-
// because the synthesized code uses invalid SourceLocs. Don't diagnose
2559-
// these errors; instead, take it on faith that
2560-
// DerivedConformanceRawRepresentable will do the right thing.
2561-
flags |= DeclAvailabilityFlag::AllowPotentiallyUnavailable;
2562-
25632492
diagAvailability(DR->getDeclRef(), DR->getSourceRange(),
2564-
getEnclosingApplyExpr(), flags);
2493+
getEnclosingApplyExpr(), None);
25652494
maybeDiagStorageAccess(DR->getDecl(), DR->getSourceRange(), DC);
25662495
}
25672496
if (auto MR = dyn_cast<MemberRefExpr>(E)) {
@@ -2861,9 +2790,6 @@ AvailabilityWalker::diagAvailability(ConcreteDeclRef declRef, SourceRange R,
28612790
if (!isAccessorWithDeprecatedStorage)
28622791
TypeChecker::diagnoseIfDeprecated(R, Where, D, call);
28632792

2864-
if (Flags.contains(DeclAvailabilityFlag::AllowPotentiallyUnavailable))
2865-
return false;
2866-
28672793
if (Flags.contains(DeclAvailabilityFlag::AllowPotentiallyUnavailableProtocol)
28682794
&& isa<ProtocolDecl>(D))
28692795
return false;
@@ -3041,7 +2967,10 @@ AvailabilityWalker::diagnoseMemoryLayoutMigration(const ValueDecl *D,
30412967

30422968
/// Diagnose uses of unavailable declarations.
30432969
void swift::diagAvailability(const Expr *E, DeclContext *DC) {
3044-
AvailabilityWalker walker(ExportContext::forFunctionBody(DC));
2970+
auto where = ExportContext::forFunctionBody(DC);
2971+
if (where.isImplicit())
2972+
return;
2973+
AvailabilityWalker walker(where);
30452974
const_cast<Expr*>(E)->walk(walker);
30462975
}
30472976

@@ -3051,8 +2980,8 @@ class StmtAvailabilityWalker : public ASTWalker {
30512980
ExportContext Where;
30522981

30532982
public:
3054-
explicit StmtAvailabilityWalker(DeclContext *DC)
3055-
: Where(ExportContext::forFunctionBody(DC)) {}
2983+
explicit StmtAvailabilityWalker(ExportContext where)
2984+
: Where(where) {}
30562985

30572986
/// We'll visit the expression from performSyntacticExprDiagnostics().
30582987
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
@@ -3079,7 +3008,11 @@ void swift::diagAvailability(const Stmt *S, DeclContext *DC) {
30793008
if (isa<BraceStmt>(S))
30803009
return;
30813010

3082-
StmtAvailabilityWalker walker(DC);
3011+
auto where = ExportContext::forFunctionBody(DC);
3012+
if (where.isImplicit())
3013+
return;
3014+
3015+
StmtAvailabilityWalker walker(where);
30833016
const_cast<Stmt*>(S)->walk(walker);
30843017
}
30853018

@@ -3281,6 +3214,7 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *Decl,
32813214
ExportContext Where,
32823215
DeclAvailabilityFlags Flags)
32833216
{
3217+
assert(!Where.isImplicit());
32843218
AvailabilityWalker AW(Where);
32853219
return AW.diagAvailability(const_cast<ValueDecl *>(Decl), R, nullptr, Flags);
32863220
}

lib/Sema/TypeCheckAvailability.h

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,9 @@ enum class DeclAvailabilityFlag : uint8_t {
4949
/// is inout and both the getter and setter must be available.
5050
ForInout = 1 << 2,
5151

52-
/// Do not diagnose uses of declarations in versions before they were
53-
/// introduced. Used to work around availability-checker bugs.
54-
AllowPotentiallyUnavailable = 1 << 3,
55-
5652
/// If an error diagnostic would normally be emitted, demote the error to a
5753
/// warning. Used for ObjC key path components.
58-
ForObjCKeyPath = 1 << 4
54+
ForObjCKeyPath = 1 << 3
5955
};
6056
using DeclAvailabilityFlags = OptionSet<DeclAvailabilityFlag>;
6157

@@ -98,10 +94,12 @@ class ExportContext {
9894
unsigned SPI : 1;
9995
unsigned Exported : 1;
10096
unsigned Deprecated : 1;
97+
unsigned Implicit : 1;
10198
ExportabilityReason Reason;
10299

103100
ExportContext(DeclContext *DC, FragileFunctionKind kind,
104-
bool spi, bool exported, bool deprecated);
101+
bool spi, bool exported, bool implicit,
102+
bool deprecated);
105103

106104
public:
107105

@@ -121,11 +119,6 @@ class ExportContext {
121119
/// it can reference anything.
122120
static ExportContext forFunctionBody(DeclContext *DC);
123121

124-
/// Produce a new context describing an implicit declaration. Implicit code
125-
/// does not have source locations. We simply trust the compiler synthesizes
126-
/// implicit declarations correctly, and skip the checks.
127-
static ExportContext forImplicit();
128-
129122
/// Produce a new context with the same properties as this one, except
130123
/// changing the ExportabilityReason. This only affects diagnostics.
131124
ExportContext withReason(ExportabilityReason reason) const;
@@ -138,17 +131,14 @@ class ExportContext {
138131
/// That is, this will perform a 'bitwise and' on the 'exported' bit.
139132
ExportContext withExported(bool exported) const;
140133

141-
DeclContext *getDeclContext() const {
142-
assert(DC != nullptr && "This is an implicit context");
143-
return DC;
144-
}
134+
DeclContext *getDeclContext() const { return DC; }
145135

146136
/// If not 'None', the context has the inlinable function body restriction.
147137
FragileFunctionKind getFragileFunctionKind() const { return FragileKind; }
148138

149139
/// If true, the context is part of a synthesized declaration, and
150140
/// availability checking should be disabled.
151-
bool isImplicit() const { return DC == nullptr; }
141+
bool isImplicit() const { return Implicit; }
152142

153143
/// If true, the context is SPI and can reference SPI declarations.
154144
bool isSPI() const { return SPI; }

test/Sema/implementation-only-import-in-decls.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ public protocol TestAssocTypeWhereClause {
7373

7474
public enum TestRawType: IntLike { // expected-error {{cannot use struct 'IntLike' here; 'BADLibrary' has been imported as implementation-only}}
7575
case x = 1
76-
// FIXME: expected-error@-1 {{cannot use conformance of 'IntLike' to 'Equatable' here; 'BADLibrary' has been imported as implementation-only}}
7776
}
7877

7978
public class TestSubclass: BadClass { // expected-error {{cannot use class 'BadClass' here; 'BADLibrary' has been imported as implementation-only}}

test/Sema/spi-in-decls.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ public protocol TestAssocTypeWhereClause {
107107

108108
public enum TestRawType: IntLike { // expected-error {{cannot use struct 'IntLike' here; it is SPI}}
109109
case x = 1
110-
// FIXME: expected-error@-1 {{cannot use conformance of 'IntLike' to 'Equatable' here; the conformance is declared as SPI}}
111110
}
112111

113112
public class TestSubclass: BadClass { // expected-error {{cannot use class 'BadClass' here; it is SPI}}

0 commit comments

Comments
 (0)