Skip to content

Commit 090704f

Browse files
authored
Merge pull request swiftlang#63406 from xedin/rdar-104931999-5.8
[5.8][SILOptimizer] Don't diagnose unreachable instructions that belong to…
2 parents 48799c8 + 2389ed0 commit 090704f

File tree

7 files changed

+165
-28
lines changed

7 files changed

+165
-28
lines changed

SwiftCompilerSources/Sources/SIL/Location.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,24 @@
1212

1313
import SILBridging
1414

15-
public struct Location {
15+
public struct Location: Equatable, CustomStringConvertible {
1616
let bridged: swift.SILDebugLocation
17-
17+
18+
public var description: String {
19+
let stdString = SILLocation_debugDescription(bridged)
20+
return String(_cxxString: stdString)
21+
}
22+
1823
/// Keeps the debug scope but marks it as auto-generated.
1924
public var autoGenerated: Location {
2025
Location(bridged: SILLocation_getAutogeneratedLocation(bridged))
2126
}
27+
28+
public static func ==(lhs: Location, rhs: Location) -> Bool {
29+
SILLocation_equal(lhs.bridged, rhs.bridged)
30+
}
31+
32+
public func hasSameSourceLocation(as other: Location) -> Bool {
33+
SILLocation_hasSameSourceLocation(bridged, other.bridged)
34+
}
2235
}

include/swift/SIL/SILBridging.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,11 @@ llvm::StringRef SILType_getNominalFieldName(BridgedType type, SwiftInt index);
331331
SwiftInt SILType_getCaseIdxOfEnumType(BridgedType type,
332332
llvm::StringRef caseName);
333333

334+
std::string SILLocation_debugDescription(swift::SILDebugLocation loc);
334335
swift::SILDebugLocation
335336
SILLocation_getAutogeneratedLocation(swift::SILDebugLocation loc);
337+
bool SILLocation_equal(swift::SILDebugLocation lhs, swift::SILDebugLocation rhs);
338+
bool SILLocation_hasSameSourceLocation(swift::SILDebugLocation lhs, swift::SILDebugLocation rhs);
336339

337340
BridgedBasicBlock SILArgument_getParent(BridgedArgument argument);
338341
BridgedArgumentConvention SILArgument_getConvention(BridgedArgument argument);

include/swift/SIL/SILLocation.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ class SILLocation {
427427
/// Pretty-print the value.
428428
void dump() const;
429429
void print(raw_ostream &OS, const SourceManager &SM) const;
430+
void print(raw_ostream &OS) const;
430431

431432
inline bool operator==(const SILLocation& R) const {
432433
return kindAndFlags.packedKindAndFlags == R.kindAndFlags.packedKindAndFlags
@@ -435,6 +436,15 @@ class SILLocation {
435436

436437
inline bool operator!=(const SILLocation &R) const { return !(*this == R); }
437438

439+
bool hasSameSourceLocation(const SILLocation &rhs) {
440+
if (*this == rhs)
441+
return true;
442+
if (isASTNode() && rhs.isASTNode()) {
443+
return getSourceLoc(getPrimaryASTNode()) == rhs.getSourceLoc(rhs.getPrimaryASTNode());
444+
}
445+
return false;
446+
}
447+
438448
friend llvm::hash_code hash_value(const SILLocation &);
439449
};
440450

lib/SIL/IR/SILLocation.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,17 @@ SILLocation::FilenameAndLocation *SILLocation::getCompilerGeneratedLoc() {
151151
return &compilerGenerated;
152152
}
153153

154-
static void dumpSourceLoc(SourceLoc loc) {
154+
static void printSourceLoc(SourceLoc loc, raw_ostream &OS) {
155155
if (!loc.isValid()) {
156-
llvm::dbgs() << "<invalid loc>";
156+
OS << "<invalid loc>";
157157
return;
158158
}
159159
const char *srcPtr = (const char *)loc.getOpaquePointerValue();
160160
unsigned len = strnlen(srcPtr, 20);
161161
if (len < 20) {
162-
llvm::dbgs() << '"' << StringRef(srcPtr, len) << '"';
162+
OS << '"' << StringRef(srcPtr, len) << '"';
163163
} else {
164-
llvm::dbgs() << '"' << StringRef(srcPtr, 20) << "[...]\"";
164+
OS << '"' << StringRef(srcPtr, 20) << "[...]\"";
165165
}
166166
}
167167

@@ -182,7 +182,7 @@ void SILLocation::dump() const {
182182
if (isFilenameAndLocation()) {
183183
getFilenameAndLocation()->dump();
184184
} else {
185-
dumpSourceLoc(getSourceLoc());
185+
printSourceLoc(getSourceLoc(), llvm::dbgs());
186186
}
187187

188188
if (isAutoGenerated()) llvm::dbgs() << ":auto";
@@ -191,7 +191,7 @@ void SILLocation::dump() const {
191191
if (isSILFile()) llvm::dbgs() << ":sil";
192192
if (hasASTNodeForDebugging()) {
193193
llvm::dbgs() << ":debug[";
194-
dumpSourceLoc(getSourceLocForDebugging());
194+
printSourceLoc(getSourceLocForDebugging(), llvm::dbgs());
195195
llvm::dbgs() << "]\n";
196196
}
197197
}
@@ -206,6 +206,18 @@ void SILLocation::print(raw_ostream &OS, const SourceManager &SM) const {
206206
}
207207
}
208208

209+
void SILLocation::print(raw_ostream &OS) const {
210+
if (isNull()) {
211+
OS << "<no loc>";
212+
} else if (isFilenameAndLocation()) {
213+
getFilenameAndLocation()->print(OS);
214+
} else if (DeclContext *dc = getAsDeclContext()){
215+
getSourceLoc().print(OS, dc->getASTContext().SourceMgr);
216+
} else {
217+
printSourceLoc(getSourceLoc(), OS);
218+
}
219+
}
220+
209221
RegularLocation::RegularLocation(Stmt *S, Pattern *P, SILModule &Module) :
210222
SILLocation(new (Module) ExtendedASTNodeLoc(S, P), RegularKind) {}
211223

lib/SIL/Utils/SILBridging.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,12 +607,39 @@ SwiftInt SILType_getCaseIdxOfEnumType(BridgedType type,
607607
// SILLocation
608608
//===----------------------------------------------------------------------===//
609609

610+
std::string SILLocation_debugDescription(swift::SILDebugLocation dloc) {
611+
std::string str;
612+
llvm::raw_string_ostream os(str);
613+
SILLocation loc = dloc.getLocation();
614+
loc.print(os);
615+
#ifndef NDEBUG
616+
if (const SILDebugScope *scope = dloc.getScope()) {
617+
if (DeclContext *dc = loc.getAsDeclContext()) {
618+
os << ", scope=";
619+
scope->print(dc->getASTContext().SourceMgr, os, /*indent*/ 2);
620+
} else {
621+
os << ", scope=?";
622+
}
623+
}
624+
#endif
625+
return str;
626+
}
627+
610628
SILDebugLocation SILLocation_getAutogeneratedLocation(SILDebugLocation loc) {
611629
SILDebugLocation autoGenLoc(RegularLocation::getAutoGeneratedLocation(),
612630
loc.getScope());
613631
return autoGenLoc;
614632
}
615633

634+
bool SILLocation_equal(swift::SILDebugLocation lhs, swift::SILDebugLocation rhs) {
635+
return lhs.getLocation() == rhs.getLocation() && lhs.getScope() == rhs.getScope();
636+
}
637+
638+
bool SILLocation_hasSameSourceLocation(swift::SILDebugLocation lhs, swift::SILDebugLocation rhs) {
639+
return lhs.getLocation().hasSameSourceLocation(rhs.getLocation()) &&
640+
lhs.getScope() == rhs.getScope();
641+
}
642+
616643
//===----------------------------------------------------------------------===//
617644
// SILGlobalVariable
618645
//===----------------------------------------------------------------------===//

lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,44 @@ static bool simplifyBlocksWithCallsToNoReturn(SILBasicBlock &BB,
745745
// function, the entire block is dead.
746746
NoReturnCall = getPrecedingCallToNoReturn(BB);
747747

748+
// Diagnose the unreachable code within the same block as the call to
749+
// noreturn.
750+
auto diagnoseUnreachableCode = [&](SILInstruction *noReturnCall,
751+
SILInstruction *currInst) {
752+
if (DiagnosedUnreachableCode)
753+
return false;
754+
755+
// If current instruction belongs to the no-return call itself, skip it.
756+
//
757+
// It could happen when i.e. result has to be copied to be passed to
758+
// some call.
759+
if (currInst->getLoc().hasSameSourceLocation(noReturnCall->getLoc()))
760+
return false;
761+
762+
if (!isUserCode(currInst))
763+
return false;
764+
765+
// If we have an instruction that is an end_borrow, ignore it. This
766+
// happens when passing a guaranteed argument through generic code paths
767+
// to no return functions.
768+
if (isa<EndBorrowInst>(currInst))
769+
return false;
770+
771+
// If no-return instruction is not something we can point in code or
772+
// it's an explicit cast, skip it.
773+
if (!noReturnCall->getLoc().is<RegularLocation>() ||
774+
noReturnCall->getLoc().isASTNode<ExplicitCastExpr>())
775+
return false;
776+
777+
diagnose(BB.getModule().getASTContext(), currInst->getLoc().getSourceLoc(),
778+
diag::unreachable_code);
779+
diagnose(BB.getModule().getASTContext(),
780+
noReturnCall->getLoc().getSourceLoc(),
781+
diag::call_to_noreturn_note);
782+
783+
return true;
784+
};
785+
748786
// Does this block contain a call to a noreturn function?
749787
while (I != E) {
750788
auto *CurrentInst = &*I;
@@ -758,26 +796,8 @@ static bool simplifyBlocksWithCallsToNoReturn(SILBasicBlock &BB,
758796
// We will need to delete the instruction later on.
759797
ToBeDeleted.push_back(CurrentInst);
760798

761-
// Diagnose the unreachable code within the same block as the call to
762-
// noreturn.
763-
if (isUserCode(CurrentInst) && !DiagnosedUnreachableCode) {
764-
// If we have an instruction that is an end_borrow, ignore it. This
765-
// happens when passing a guaranteed argument through generic code paths
766-
// to no return functions.
767-
if (!isa<EndBorrowInst>(CurrentInst)) {
768-
if (NoReturnCall->getLoc().is<RegularLocation>()) {
769-
if (!NoReturnCall->getLoc().isASTNode<ExplicitCastExpr>()) {
770-
diagnose(BB.getModule().getASTContext(),
771-
CurrentInst->getLoc().getSourceLoc(),
772-
diag::unreachable_code);
773-
diagnose(BB.getModule().getASTContext(),
774-
NoReturnCall->getLoc().getSourceLoc(),
775-
diag::call_to_noreturn_note);
776-
DiagnosedUnreachableCode = true;
777-
}
778-
}
779-
}
780-
}
799+
DiagnosedUnreachableCode |=
800+
diagnoseUnreachableCode(NoReturnCall, CurrentInst);
781801

782802
// We are going to bluntly remove these instructions. Change uses in
783803
// different basic blocks to undef. This is safe because all control flow

test/SILOptimizer/diagnose_unreachable.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,3 +518,55 @@ func keypathWithDynamicLookup() {
518518
// when used in conjunction with a dynamicMemberLookup enum.
519519
let _ = \DynamicLookupEnum.innerEnum // no warning
520520
}
521+
522+
func test_no_warnings_with_fatalError_when_wrapped_in_buildExpression() {
523+
enum Either<T,U> {
524+
case first(T)
525+
case second(U)
526+
}
527+
528+
@resultBuilder
529+
struct MyBuilder {
530+
static func buildExpression<T>(_ e: T) -> T { e }
531+
static func buildBlock() -> () { }
532+
533+
static func buildBlock<T1>(_ t1: T1) -> T1 {
534+
return t1
535+
}
536+
537+
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
538+
return (t1, t2)
539+
}
540+
541+
static func buildBlock<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3) -> (T1, T2, T3) {
542+
return (t1, t2, t3)
543+
}
544+
545+
static func buildEither<T,U>(first value: T) -> Either<T, U> {
546+
return .first(value)
547+
}
548+
549+
static func buildEither<T,U>(second value: U) -> Either<T, U> {
550+
return .second(value)
551+
}
552+
}
553+
554+
func test<T>(@MyBuilder _: (Int) -> T) {}
555+
556+
test {
557+
if $0 < 0 {
558+
fatalError() // ok, no warning even though fatalError() is wrapped
559+
} else if $0 > 0 {
560+
42
561+
} else {
562+
0
563+
}
564+
}
565+
566+
test {
567+
switch $0 {
568+
case 0: "0"
569+
default: fatalError() // Ok, no warning even though fatalError() is wrapped
570+
}
571+
}
572+
}

0 commit comments

Comments
 (0)