@@ -181,7 +181,7 @@ ExportContext ExportContext::forDeclSignature(Decl *D) {
181
181
auto runningOSVersion =
182
182
(Ctx.LangOpts .DisableAvailabilityChecking
183
183
? AvailabilityContext::alwaysAvailable ()
184
- : TypeChecker::overApproximateAvailabilityAtLocation (D->getEndLoc (), DC));
184
+ : TypeChecker::overApproximateAvailabilityAtLocation (D->getLoc (), DC));
185
185
bool spi = Ctx.LangOpts .LibraryLevel == LibraryLevel::SPI;
186
186
bool implicit = false ;
187
187
bool deprecated = false ;
@@ -288,6 +288,27 @@ static bool hasActiveAvailableAttribute(Decl *D,
288
288
return getActiveAvailableAttribute (D, AC);
289
289
}
290
290
291
+ static bool bodyIsResilienceBoundary (Decl *D) {
292
+ // The declaration contains code...
293
+ if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
294
+ // And it has a location so we can check it...
295
+ if (!afd->isImplicit () && afd->getBodySourceRange ().isValid ()) {
296
+ // And the code is within our resilience domain, so it should be
297
+ // compiled with the minimum deployment target, not the minimum inlining
298
+ // target.
299
+ return afd->getResilienceExpansion () != ResilienceExpansion::Minimal;
300
+ }
301
+ }
302
+
303
+ return false ;
304
+ }
305
+
306
+ static bool computeContainedByDeploymentTarget (TypeRefinementContext *TRC,
307
+ ASTContext &ctx) {
308
+ return TRC->getAvailabilityInfo ()
309
+ .isContainedIn (AvailabilityContext::forDeploymentTarget (ctx));
310
+ }
311
+
291
312
namespace {
292
313
293
314
// / A class to walk the AST to build the type refinement context hierarchy.
@@ -302,6 +323,8 @@ class TypeRefinementContextBuilder : private ASTWalker {
302
323
// / indicating that custom logic elsewhere will handle removing
303
324
// / the context when needed.
304
325
ParentTy ScopeNode;
326
+
327
+ bool ContainedByDeploymentTarget;
305
328
};
306
329
307
330
std::vector<ContextInfo> ContextStack;
@@ -318,10 +341,24 @@ class TypeRefinementContextBuilder : private ASTWalker {
318
341
return ContextStack.back ().TRC ;
319
342
}
320
343
344
+ bool isCurrentTRCContainedByDeploymentTarget () {
345
+ return ContextStack.back ().ContainedByDeploymentTarget ;
346
+ }
347
+
321
348
void pushContext (TypeRefinementContext *TRC, ParentTy PopAfterNode) {
322
349
ContextInfo Info;
323
350
Info.TRC = TRC;
324
351
Info.ScopeNode = PopAfterNode;
352
+
353
+ if (!ContextStack.empty () && isCurrentTRCContainedByDeploymentTarget ()) {
354
+ assert (computeContainedByDeploymentTarget (TRC, Context) &&
355
+ " incorrectly skipping computeContainedByDeploymentTarget()" );
356
+ Info.ContainedByDeploymentTarget = true ;
357
+ } else {
358
+ Info.ContainedByDeploymentTarget =
359
+ computeContainedByDeploymentTarget (TRC, Context);
360
+ }
361
+
325
362
ContextStack.push_back (Info);
326
363
}
327
364
@@ -367,11 +404,16 @@ class TypeRefinementContextBuilder : private ASTWalker {
367
404
pushContext (DeclTRC, D);
368
405
}
369
406
407
+ // Adds in a TRC that covers only the body of the declaration.
408
+ if (auto BodyTRC = getNewContextForBodyOfDecl (D)) {
409
+ pushContext (BodyTRC, D);
410
+ }
411
+
370
412
return true ;
371
413
}
372
414
373
415
bool walkToDeclPost (Decl *D) override {
374
- // As seen above, we could have up to two TRCs in the stack for a single
416
+ // As seen above, we could have up to three TRCs in the stack for a single
375
417
// declaration.
376
418
while (ContextStack.back ().ScopeNode .getAsDecl () == D) {
377
419
ContextStack.pop_back ();
@@ -510,6 +552,39 @@ class TypeRefinementContextBuilder : private ASTWalker {
510
552
return D->getSourceRange ();
511
553
}
512
554
555
+ TypeRefinementContext *getNewContextForBodyOfDecl (Decl *D) {
556
+ if (bodyIntroducesNewContext (D))
557
+ return buildBodyRefinementContext (D);
558
+
559
+ return nullptr ;
560
+ }
561
+
562
+ bool bodyIntroducesNewContext (Decl *D) {
563
+ // Are we already effectively in a resilience boundary? If not, adding one
564
+ // wouldn't change availability.
565
+ if (isCurrentTRCContainedByDeploymentTarget ())
566
+ return false ;
567
+
568
+ // If we're in a function, is its body a resilience boundary?
569
+ if (auto afd = dyn_cast<AbstractFunctionDecl>(D))
570
+ return bodyIsResilienceBoundary (afd);
571
+
572
+ return false ;
573
+ }
574
+
575
+ TypeRefinementContext *buildBodyRefinementContext (Decl *D) {
576
+ auto afd = cast<AbstractFunctionDecl>(D);
577
+ SourceRange range = afd->getBodySourceRange ();
578
+
579
+ AvailabilityContext DeploymentTargetInfo =
580
+ AvailabilityContext::forDeploymentTarget (Context);
581
+ DeploymentTargetInfo.intersectWith (getCurrentTRC ()->getAvailabilityInfo ());
582
+
583
+ return TypeRefinementContext::createForResilienceBoundary (
584
+ Context, D, getCurrentTRC (),
585
+ DeploymentTargetInfo, range);
586
+ }
587
+
513
588
std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
514
589
if (auto *IS = dyn_cast<IfStmt>(S)) {
515
590
buildIfStmtRefinementContext (IS);
@@ -927,8 +1002,8 @@ void TypeChecker::buildTypeRefinementContextHierarchy(SourceFile &SF) {
927
1002
if (!RootTRC) {
928
1003
// The root type refinement context reflects the fact that all parts of
929
1004
// the source file are guaranteed to be executing on at least the minimum
930
- // platform version.
931
- auto MinPlatformReq = AvailabilityContext::forDeploymentTarget (Context);
1005
+ // platform version for inlining .
1006
+ auto MinPlatformReq = AvailabilityContext::forInliningTarget (Context);
932
1007
RootTRC = TypeRefinementContext::createRoot (&SF, MinPlatformReq);
933
1008
SF.setTypeRefinementContext (RootTRC);
934
1009
}
@@ -993,9 +1068,8 @@ TypeChecker::overApproximateAvailabilityAtLocation(SourceLoc loc,
993
1068
// refined. For now, this is fine -- but if we ever synthesize #available(),
994
1069
// this will be a real problem.
995
1070
996
- // We can assume we are running on at least the minimum deployment target.
997
- auto OverApproximateContext =
998
- AvailabilityContext::forDeploymentTarget (Context);
1071
+ // We can assume we are running on at least the minimum inlining target.
1072
+ auto OverApproximateContext = AvailabilityContext::forInliningTarget (Context);
999
1073
auto isInvalidLoc = [SF](SourceLoc loc) {
1000
1074
return SF ? loc.isInvalid () : true ;
1001
1075
};
0 commit comments