Skip to content

Commit 85d2495

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

File tree

5 files changed

+75
-94
lines changed

5 files changed

+75
-94
lines changed

include/swift/AST/DeclContext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ namespace swift {
5757
class GenericTypeParamType;
5858
class InfixOperatorDecl;
5959
class InfixOperatorLookupResult;
60+
enum class PlatformKind: uint8_t;
6061
class PrecedenceGroupDecl;
6162
class ProtocolDecl;
6263
class Requirement;

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 61 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,22 @@
3838
using namespace swift;
3939

4040
ExportContext::ExportContext(DeclContext *DC, FragileFunctionKind kind,
41-
bool spi, bool exported, bool implicit,
42-
bool deprecated)
41+
bool spi, bool exported, bool implicit, bool deprecated,
42+
Optional<PlatformKind> unavailablePlatformKind)
4343
: DC(DC), FragileKind(kind) {
4444
SPI = spi;
4545
Exported = exported;
4646
Implicit = implicit;
4747
Deprecated = deprecated;
48-
Reason = ExportabilityReason::General;
48+
if (unavailablePlatformKind) {
49+
Unavailable = 1;
50+
Platform = unsigned(*unavailablePlatformKind);
51+
} else {
52+
Unavailable = 0;
53+
Platform = 0;
54+
}
55+
56+
Reason = unsigned(ExportabilityReason::General);
4957
}
5058

5159
bool swift::isExported(const ValueDecl *VD) {
@@ -141,28 +149,39 @@ static void forEachOuterDecl(DeclContext *DC, Fn fn) {
141149
}
142150

143151
static void computeExportContextBits(Decl *D,
144-
bool *implicit, bool *deprecated) {
152+
bool *implicit, bool *deprecated,
153+
Optional<PlatformKind> *unavailablePlatformKind) {
145154
if (D->isImplicit())
146155
*implicit = true;
147156

148-
if (D->getAttrs().getDeprecated(D->getASTContext()))
157+
auto &Ctx = D->getASTContext();
158+
159+
if (D->getAttrs().getDeprecated(Ctx))
149160
*deprecated = true;
150161

162+
if (auto *A = D->getAttrs().getUnavailable(Ctx)) {
163+
*unavailablePlatformKind = A->Platform;
164+
}
165+
151166
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
152167
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) {
153168
if (auto *VD = PBD->getAnchoringVarDecl(i))
154-
computeExportContextBits(VD, implicit, deprecated);
169+
computeExportContextBits(VD, implicit, deprecated,
170+
unavailablePlatformKind);
155171
}
156172
}
157173
}
158174

159175
ExportContext ExportContext::forDeclSignature(Decl *D) {
160176
bool implicit = false;
161177
bool deprecated = false;
162-
computeExportContextBits(D, &implicit, &deprecated);
178+
Optional<PlatformKind> unavailablePlatformKind;
179+
computeExportContextBits(D, &implicit, &deprecated,
180+
&unavailablePlatformKind);
163181
forEachOuterDecl(D->getDeclContext(),
164182
[&](Decl *D) {
165-
computeExportContextBits(D, &implicit, &deprecated);
183+
computeExportContextBits(D, &implicit, &deprecated,
184+
&unavailablePlatformKind);
166185
});
167186

168187
auto *DC = D->getInnermostDeclContext();
@@ -182,15 +201,18 @@ ExportContext ExportContext::forDeclSignature(Decl *D) {
182201

183202
bool exported = ::isExported(D);
184203

185-
return ExportContext(DC, fragileKind, spi, exported, implicit, deprecated);
204+
return ExportContext(DC, fragileKind, spi, exported, implicit, deprecated,
205+
unavailablePlatformKind);
186206
}
187207

188208
ExportContext ExportContext::forFunctionBody(DeclContext *DC) {
189209
bool implicit = false;
190210
bool deprecated = false;
211+
Optional<PlatformKind> unavailablePlatformKind;
191212
forEachOuterDecl(DC,
192213
[&](Decl *D) {
193-
computeExportContextBits(D, &implicit, &deprecated);
214+
computeExportContextBits(D, &implicit, &deprecated,
215+
&unavailablePlatformKind);
194216
});
195217

196218
auto fragileKind = DC->getFragileFunctionKind();
@@ -204,12 +226,13 @@ ExportContext ExportContext::forFunctionBody(DeclContext *DC) {
204226
assert(fragileKind.kind == FragileFunctionKind::None);
205227
}
206228

207-
return ExportContext(DC, fragileKind, spi, exported, implicit, deprecated);
229+
return ExportContext(DC, fragileKind, spi, exported, implicit, deprecated,
230+
unavailablePlatformKind);
208231
}
209232

210233
ExportContext ExportContext::withReason(ExportabilityReason reason) const {
211234
auto copy = *this;
212-
copy.Reason = reason;
235+
copy.Reason = unsigned(reason);
213236
return copy;
214237
}
215238

@@ -219,13 +242,19 @@ ExportContext ExportContext::withExported(bool exported) const {
219242
return copy;
220243
}
221244

245+
Optional<PlatformKind> ExportContext::getUnavailablePlatformKind() const {
246+
if (Unavailable)
247+
return PlatformKind(Platform);
248+
return None;
249+
}
250+
222251
bool ExportContext::mustOnlyReferenceExportedDecls() const {
223252
return Exported || FragileKind.kind != FragileFunctionKind::None;
224253
}
225254

226255
Optional<ExportabilityReason> ExportContext::getExportabilityReason() const {
227256
if (Exported)
228-
return Reason;
257+
return ExportabilityReason(Reason);
229258
return None;
230259
}
231260

@@ -1644,62 +1673,15 @@ const AvailableAttr *TypeChecker::getDeprecated(const Decl *D) {
16441673
return nullptr;
16451674
}
16461675

1647-
/// Returns true if some declaration lexically enclosing the reference
1648-
/// matches the passed in predicate and false otherwise.
1649-
static bool
1650-
someEnclosingDeclMatches(SourceRange ReferenceRange,
1651-
const DeclContext *ReferenceDC,
1652-
llvm::function_ref<bool(const Decl *)> Pred) {
1653-
// Climb the DeclContext hierarchy to see if any of the containing
1654-
// declarations matches the predicate.
1655-
const DeclContext *DC = ReferenceDC;
1656-
while (true) {
1657-
auto *D = DC->getInnermostDeclarationDeclContext();
1658-
if (!D)
1659-
break;
1660-
1661-
if (Pred(D)) {
1662-
return true;
1663-
}
1664-
1665-
// If we are in an accessor, check to see if the associated
1666-
// property matches the predicate.
1667-
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
1668-
if (Pred(accessor->getStorage()))
1669-
return true;
1670-
}
1671-
1672-
DC = D->getDeclContext();
1673-
}
1674-
1675-
// Search the AST starting from our innermost declaration context to see if
1676-
// if the reference is inside a property declaration but not inside an
1677-
// accessor (this can happen for the TypeRepr for the declared type of a
1678-
// property, for example).
1679-
// We can't rely on the DeclContext hierarchy climb above because properties
1680-
// do not introduce a new DeclContext.
1681-
1682-
// Don't search for a containing declaration if we don't have a source range.
1683-
if (ReferenceRange.isInvalid())
1684-
return false;
1685-
1686-
ASTContext &Ctx = ReferenceDC->getASTContext();
1687-
const Decl *DeclToSearch =
1688-
findContainingDeclaration(ReferenceRange, ReferenceDC, Ctx.SourceMgr);
1689-
1690-
// We may not be able to find a declaration to search if the ReferenceRange
1691-
// isn't useful (i.e., we are in synthesized code).
1692-
if (!DeclToSearch)
1693-
return false;
1694-
1695-
return Pred(abstractSyntaxDeclForAvailableAttribute(DeclToSearch));
1696-
}
1697-
16981676
/// Returns true if the reference or any of its parents is an
16991677
/// unconditional unavailable declaration for the same platform.
17001678
static bool isInsideCompatibleUnavailableDeclaration(
1701-
const ValueDecl *referencedD, SourceRange ReferenceRange,
1702-
const DeclContext *ReferenceDC, const AvailableAttr *attr) {
1679+
const ValueDecl *D, ExportContext where,
1680+
const AvailableAttr *attr) {
1681+
auto referencedPlatform = where.getUnavailablePlatformKind();
1682+
if (!referencedPlatform)
1683+
return false;
1684+
17031685
if (!attr->isUnconditionallyUnavailable()) {
17041686
return false;
17051687
}
@@ -1708,20 +1690,13 @@ static bool isInsideCompatibleUnavailableDeclaration(
17081690
// but allow the use of types.
17091691
PlatformKind platform = attr->Platform;
17101692
if (platform == PlatformKind::none &&
1711-
!isa<TypeDecl>(referencedD)) {
1693+
!isa<TypeDecl>(D)) {
17121694
return false;
17131695
}
17141696

1715-
auto IsUnavailable = [platform](const Decl *D) {
1716-
auto EnclosingUnavailable =
1717-
D->getAttrs().getUnavailable(D->getASTContext());
1718-
return EnclosingUnavailable &&
1719-
(EnclosingUnavailable->Platform == platform ||
1720-
inheritsAvailabilityFromPlatform(platform,
1721-
EnclosingUnavailable->Platform));
1722-
};
1723-
1724-
return someEnclosingDeclMatches(ReferenceRange, ReferenceDC, IsUnavailable);
1697+
return (*referencedPlatform == platform ||
1698+
inheritsAvailabilityFromPlatform(platform,
1699+
*referencedPlatform));
17251700
}
17261701

17271702
static void fixItAvailableAttrRename(InFlightDiagnostic &diag,
@@ -2201,8 +2176,8 @@ void swift::diagnoseUnavailableOverride(ValueDecl *override,
22012176
return;
22022177
}
22032178

2204-
diagnoseExplicitUnavailability(base, override->getLoc(),
2205-
override->getDeclContext(),
2179+
ExportContext where = ExportContext::forDeclSignature(override);
2180+
diagnoseExplicitUnavailability(base, override->getLoc(), where,
22062181
/*Flags*/None,
22072182
[&](InFlightDiagnostic &diag) {
22082183
ParsedDeclName parsedName = parseDeclName(attr->Rename);
@@ -2235,10 +2210,10 @@ void swift::diagnoseUnavailableOverride(ValueDecl *override,
22352210
/// marked as unavailable, either through "unavailable" or "obsoleted:".
22362211
bool swift::diagnoseExplicitUnavailability(const ValueDecl *D,
22372212
SourceRange R,
2238-
const DeclContext *DC,
2213+
ExportContext Where,
22392214
const ApplyExpr *call,
22402215
DeclAvailabilityFlags Flags) {
2241-
return diagnoseExplicitUnavailability(D, R, DC, Flags,
2216+
return diagnoseExplicitUnavailability(D, R, Where, Flags,
22422217
[=](InFlightDiagnostic &diag) {
22432218
fixItAvailableAttrRename(diag, R, D, AvailableAttr::isUnavailable(D),
22442219
call);
@@ -2309,7 +2284,7 @@ bool isSubscriptReturningString(const ValueDecl *D, ASTContext &Context) {
23092284
bool swift::diagnoseExplicitUnavailability(
23102285
const ValueDecl *D,
23112286
SourceRange R,
2312-
const DeclContext *DC,
2287+
ExportContext Where,
23132288
DeclAvailabilityFlags Flags,
23142289
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts) {
23152290
auto *Attr = AvailableAttr::isUnavailable(D);
@@ -2320,9 +2295,8 @@ bool swift::diagnoseExplicitUnavailability(
23202295
// unavailability is OK -- the eventual caller can't call the
23212296
// enclosing code in the same situations it wouldn't be able to
23222297
// call this code.
2323-
if (isInsideCompatibleUnavailableDeclaration(D, R, DC, Attr)) {
2298+
if (isInsideCompatibleUnavailableDeclaration(D, Where, Attr))
23242299
return false;
2325-
}
23262300

23272301
SourceLoc Loc = R.Start;
23282302
DeclName Name;
@@ -2776,9 +2750,7 @@ AvailabilityWalker::diagAvailability(ConcreteDeclRef declRef, SourceRange R,
27762750
}
27772751
}
27782752

2779-
auto *DC = Where.getDeclContext();
2780-
2781-
if (diagnoseExplicitUnavailability(D, R, DC, call, Flags))
2753+
if (diagnoseExplicitUnavailability(D, R, Where, call, Flags))
27822754
return true;
27832755

27842756
// Make sure not to diagnose an accessor's deprecation if we already
@@ -2794,6 +2766,8 @@ AvailabilityWalker::diagAvailability(ConcreteDeclRef declRef, SourceRange R,
27942766
&& isa<ProtocolDecl>(D))
27952767
return false;
27962768

2769+
auto *DC = Where.getDeclContext();
2770+
27972771
// Diagnose (and possibly signal) for potential unavailability
27982772
auto maybeUnavail = TypeChecker::checkDeclarationAvailability(D, R.Start, DC);
27992773
if (maybeUnavail.hasValue()) {

lib/Sema/TypeCheckAvailability.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,13 @@ class ExportContext {
9595
unsigned Exported : 1;
9696
unsigned Deprecated : 1;
9797
unsigned Implicit : 1;
98-
ExportabilityReason Reason;
98+
unsigned Unavailable : 1;
99+
unsigned Platform : 8;
100+
unsigned Reason : 2;
99101

100102
ExportContext(DeclContext *DC, FragileFunctionKind kind,
101-
bool spi, bool exported, bool implicit,
102-
bool deprecated);
103+
bool spi, bool exported, bool implicit, bool deprecated,
104+
Optional<PlatformKind> unavailablePlatformKind);
103105

104106
public:
105107

@@ -151,6 +153,8 @@ class ExportContext {
151153
/// reference other deprecated declarations without warning.
152154
bool isDeprecated() const { return Deprecated; }
153155

156+
Optional<PlatformKind> getUnavailablePlatformKind() const;
157+
154158
/// If true, the context can only reference exported declarations, either
155159
/// because it is the signature context of an exported declaration, or
156160
/// because it is the function body context of an inlinable function.
@@ -215,7 +219,7 @@ void diagnoseUnavailableOverride(ValueDecl *override,
215219
/// marked as unavailable, either through "unavailable" or "obsoleted:".
216220
bool diagnoseExplicitUnavailability(const ValueDecl *D,
217221
SourceRange R,
218-
const DeclContext *DC,
222+
ExportContext Where,
219223
const ApplyExpr *call,
220224
DeclAvailabilityFlags Flags = None);
221225

@@ -224,7 +228,7 @@ bool diagnoseExplicitUnavailability(const ValueDecl *D,
224228
bool diagnoseExplicitUnavailability(
225229
const ValueDecl *D,
226230
SourceRange R,
227-
const DeclContext *DC,
231+
ExportContext Where,
228232
DeclAvailabilityFlags Flags,
229233
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts);
230234

lib/Sema/TypeCheckPattern.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ using namespace swift;
3737
static EnumElementDecl *
3838
extractEnumElement(DeclContext *DC, SourceLoc UseLoc,
3939
const VarDecl *constant) {
40-
diagnoseExplicitUnavailability(constant, UseLoc, DC, nullptr);
40+
ExportContext where = ExportContext::forFunctionBody(DC);
41+
diagnoseExplicitUnavailability(constant, UseLoc, where, nullptr);
4142

4243
const FuncDecl *getter = constant->getAccessor(AccessorKind::Get);
4344
if (!getter)

lib/Sema/TypeCheckStorage.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,10 +785,11 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
785785
if (accessor->getAccessorKind() == AccessorKind::Get ||
786786
accessor->getAccessorKind() == AccessorKind::Read) {
787787
if (wrappedValue->getAttrs().getUnavailable(ctx)) {
788+
ExportContext where = ExportContext::forDeclSignature(var);
788789
diagnoseExplicitUnavailability(
789790
wrappedValue,
790791
var->getAttachedPropertyWrappers()[i]->getRangeWithAt(),
791-
var->getDeclContext(), nullptr);
792+
where, nullptr);
792793
}
793794
}
794795

0 commit comments

Comments
 (0)