Skip to content

Commit 5a2479c

Browse files
committed
Expand the no-return diagnostic
Turn on the noreturn diagnostic for cases where a reachable unreachable could be encountered. Previously, the diagnostic would not fire if the function was marked noreturn and any of its reachable unreachable calls were around. While this makes sense from a SILGen perspective (it Just Crashes tm), it is still wrong. We need to diagnose *everything* that has reachable unreachables.
1 parent fdaddcc commit 5a2479c

File tree

9 files changed

+39
-16
lines changed

9 files changed

+39
-16
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,11 @@ ERROR(assignment_to_immutable_value,none,
179179
ERROR(missing_return,none,
180180
"missing return in a %select{function|closure}1 expected to return %0",
181181
(Type, unsigned))
182-
ERROR(non_exhaustive_switch,none,
182+
ERROR(missing_never_call,none,
183+
"%select{function|closure}1 with uninhabited return type %0 is missing "
184+
"call to another never-returning function on all paths",
185+
(Type, unsigned))
186+
ERROR(non_exhaustive_switch,none,
183187
"switch must be exhaustive, consider adding a default clause", ())
184188
ERROR(guard_body_must_not_fallthrough,none,
185189
"'guard' body may not fall through, consider using 'return' or 'break'"

include/swift/AST/Types.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,8 @@ class alignas(1 << TypeAlignInBits) TypeBase {
393393
/// semantics?
394394
bool hasReferenceSemantics();
395395

396-
/// Is this 'Never'?
397-
bool isNever();
396+
/// Is this an uninhabited type, such as 'Never'?
397+
bool isUninhabited();
398398

399399
/// Is this the 'Any' type?
400400
bool isAny();

lib/AST/Type.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,11 @@ bool TypeBase::hasReferenceSemantics() {
8989
return getCanonicalType().hasReferenceSemantics();
9090
}
9191

92-
bool TypeBase::isNever() {
92+
bool TypeBase::isUninhabited() {
9393
if (auto nominalDecl = getAnyNominal())
9494
if (auto enumDecl = dyn_cast<EnumDecl>(nominalDecl))
95-
return enumDecl == getASTContext().getNeverDecl();
95+
if (enumDecl->getAllElements().empty())
96+
return true;
9697
return false;
9798
}
9899

lib/IRGen/GenClangType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ GenClangType::visitBoundGenericType(CanBoundGenericType type) {
493493
clang::CanQualType GenClangType::visitEnumType(CanEnumType type) {
494494
// Special case: Uninhabited enums are not @objc, so we don't
495495
// know what to do below, but we can just convert to 'void'.
496-
if (type->getDecl()->getAllElements().empty())
496+
if (type->isUninhabited())
497497
return Converter.convert(IGM, IGM.Context.TheEmptyTupleType);
498498

499499
assert(type->getDecl()->isObjC() && "not an @objc enum?!");

lib/SIL/SILType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ bool SILType::isReferenceCounted(SILModule &M) const {
7272

7373
bool SILType::isNoReturnFunction() const {
7474
if (auto funcTy = dyn_cast<SILFunctionType>(getSwiftRValueType()))
75-
return funcTy->getSILResult().getSwiftRValueType()->isNever();
75+
return funcTy->getSILResult().getSwiftRValueType()->isUninhabited();
7676

7777
return false;
7878
}

lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,13 @@ static void diagnoseMissingReturn(const UnreachableInst *UI,
4646
llvm_unreachable("unhandled case in MissingReturn");
4747
}
4848

49-
// No action required if the function returns 'Void' or that the
50-
// function is marked 'noreturn'.
51-
if (ResTy->isVoid() || F->isNoReturnFunction())
52-
return;
53-
5449
SILLocation L = UI->getLoc();
5550
assert(L && ResTy);
51+
auto diagID = F->isNoReturnFunction() ? diag::missing_never_call
52+
: diag::missing_return;
5653
diagnose(Context,
5754
L.getEndSourceLoc(),
58-
diag::missing_return, ResTy,
55+
diagID, ResTy,
5956
FLoc.isASTNode<ClosureExpr>() ? 1 : 0);
6057
}
6158

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ bool TypeChecker::typeCheckCatchPattern(CatchStmt *S, DeclContext *DC) {
10051005

10061006
static bool isDiscardableType(Type type) {
10071007
return (type->is<ErrorType>() ||
1008-
type->isNever() ||
1008+
type->isUninhabited() ||
10091009
type->lookThroughAllAnyOptionalTypes()->isVoid());
10101010
}
10111011

test/IRGen/dllexport.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public var ci : c = c()
2020

2121
open class d {
2222
private func m() -> Never {
23-
return fatalError()
23+
fatalError()
2424
}
2525
}
2626

test/SILOptimizer/return.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,28 @@ func singleBlock2() -> Int {
1212
enum NoCasesButNotNever {}
1313

1414
func diagnoseNoCaseEnumMissingReturn() -> NoCasesButNotNever {
15-
} // expected-error {{missing return in a function expected to return 'NoCasesButNotNever'}}
15+
} // expected-error {{function with uninhabited return type 'NoCasesButNotNever' is missing call to another never-returning function on all paths}}
16+
17+
func diagnoseNeverMissingBody() -> Never {
18+
} // expected-error {{function with uninhabited return type 'Never' is missing call to another never-returning function on all paths}}
19+
20+
_ = { () -> Never in
21+
}() // expected-error {{closure with uninhabited return type 'Never' is missing call to another never-returning function on all paths}}-
22+
23+
func diagnoseNeverWithBody(i : Int) -> Never {
24+
if (i == -1) {
25+
print("Oh no!")
26+
} else {
27+
switch i {
28+
case 0:
29+
exit()
30+
case 1:
31+
fatalError()
32+
default:
33+
repeat { } while true
34+
}
35+
}
36+
} // expected-error {{function with uninhabited return type 'Never' is missing call to another never-returning function on all paths}}
1637

1738
class MyClassWithClosure {
1839
var f : (_ s: String) -> String = { (_ s: String) -> String in } // expected-error {{missing return in a closure expected to return 'String'}}

0 commit comments

Comments
 (0)