Skip to content

Commit 375f4d2

Browse files
committed
SILOptimizer: Suppress unreachable code diagnostics for unavailable stubs.
User code should not be diagnosed as "unreachable" by the SIL optimizer when the no-return function that made the code unreachable is a compiler inserted call to `_diagnoseUnavailableCodeReached()`. Part of rdar://107388493
1 parent 5df0fd6 commit 375f4d2

File tree

5 files changed

+48
-0
lines changed

5 files changed

+48
-0
lines changed

include/swift/SIL/ApplySite.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,12 @@ class ApplySite {
241241
FOREACH_IMPL_RETURN(isCalleeKnownProgramTerminationPoint());
242242
}
243243

244+
/// Returns true if the callee function is annotated with
245+
/// @_semantics("unavailable_code_reached")
246+
bool isCalleeUnavailableCodeReached() const {
247+
FOREACH_IMPL_RETURN(isCalleeUnavailableCodeReached());
248+
}
249+
244250
/// Check if this is a call of a never-returning function.
245251
bool isCalleeNoReturn() const { FOREACH_IMPL_RETURN(isCalleeNoReturn()); }
246252

include/swift/SIL/SILInstruction.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,6 +2777,14 @@ class ApplyInstBase<Impl, Base, false> : public Base {
27772777
return calleeFn->hasSemanticsAttr(SEMANTICS_PROGRAMTERMINATION_POINT);
27782778
}
27792779

2780+
/// Returns true if the callee function is annotated with
2781+
/// @_semantics("unavailable_code_reached")
2782+
bool isCalleeUnavailableCodeReached() const {
2783+
auto calleeFn = getCalleeFunction();
2784+
if (!calleeFn) return false;
2785+
return calleeFn->hasSemanticsAttr(SEMANTICS_UNAVAILABLE_CODE_REACHED);
2786+
}
2787+
27802788
/// True if this application has generic substitutions.
27812789
bool hasSubstitutions() const {
27822790
return Substitutions.hasAnySubstitutableParams();

include/swift/Strings.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ constexpr static const StringLiteral SEMANTICS_PROGRAMTERMINATION_POINT =
6060
constexpr static const StringLiteral SEMANTICS_DEFAULT_ACTOR =
6161
"defaultActor";
6262

63+
constexpr static const StringLiteral SEMANTICS_UNAVAILABLE_CODE_REACHED =
64+
"unavailable_code_reached";
65+
6366
constexpr static const StringLiteral DEFAULT_ACTOR_STORAGE_FIELD_NAME =
6467
"$defaultActor";
6568

lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,14 @@ static SILInstruction *getPrecedingCallToNoReturn(SILBasicBlock &BB) {
724724
return first;
725725
}
726726

727+
static bool isUnavailableCodeReachedCall(SILInstruction *I) {
728+
if (auto *AI = dyn_cast<ApplyInst>(I))
729+
if (AI->hasSemantics(SEMANTICS_UNAVAILABLE_CODE_REACHED))
730+
return true;
731+
732+
return false;
733+
}
734+
727735
static bool simplifyBlocksWithCallsToNoReturn(SILBasicBlock &BB,
728736
UnreachableUserCodeReportingState *State) {
729737
auto I = BB.begin(), E = BB.end();
@@ -766,6 +774,13 @@ static bool simplifyBlocksWithCallsToNoReturn(SILBasicBlock &BB,
766774
noReturnCall->getLoc().isASTNode<ExplicitCastExpr>())
767775
return false;
768776

777+
// If the no-return instruction is a call to the unavailable code reached
778+
// diagnostic function then we assume that the call was inserted by the
779+
// compiler because the function is semantically unavailable. Diagnosing the
780+
// user written body of the function as unreachable would be redundant.
781+
if (isUnavailableCodeReachedCall(noReturnCall))
782+
return false;
783+
769784
diagnose(BB.getModule().getASTContext(), currInst->getLoc().getSourceLoc(),
770785
diag::unreachable_code);
771786
diagnose(BB.getModule().getASTContext(),
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-emit-sil -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=stub | %FileCheck %s --check-prefixes=CHECK
2+
3+
public struct S {}
4+
5+
// CHECK-LABEL: sil {{.*}} @$s4Test15unavailableFuncAA1SVyF
6+
// CHECK: [[FNREF:%.*]] = function_ref @$ss31_diagnoseUnavailableCodeReacheds5NeverOyF
7+
// CHECK-NEXT: [[APPLY:%.*]] = apply [[FNREF]]()
8+
// CHECK-NEXT: unreachable
9+
// CHECK-NEXT: end sil function '$s4Test15unavailableFuncAA1SVyF'
10+
@available(*, unavailable)
11+
public func unavailableFunc() -> S {
12+
13+
// No warning should be produced for this code even though the compiler
14+
// inserted call to _diagnoseUnavailableCodeReached() makes it unreachable.
15+
return S()
16+
}

0 commit comments

Comments
 (0)