Skip to content

Commit ead5b95

Browse files
authored
Merge pull request swiftlang#29668 from slavapestov/fix-throws-in-defer-diagnostics
Sema: Only diagnose 'throws' in 'defer' as part of TypeCheckError
2 parents 0cdaeb5 + db6eb27 commit ead5b95

File tree

3 files changed

+67
-20
lines changed

3 files changed

+67
-20
lines changed

lib/Sema/TypeCheckError.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,6 @@ class Context {
855855

856856
Kind TheKind;
857857
bool DiagnoseErrorOnTry = false;
858-
bool isInDefer = false;
859858
DeclContext *RethrowsDC = nullptr;
860859
InterpolatedStringLiteralExpr *InterpolatedString = nullptr;
861860

@@ -899,9 +898,7 @@ class Context {
899898
}
900899

901900
static Context forDeferBody() {
902-
Context result(Kind::DeferBody);
903-
result.isInDefer = true;
904-
return result;
901+
return Context(Kind::DeferBody);
905902
}
906903

907904
static Context forInitializer(Initializer *init) {
@@ -979,18 +976,13 @@ class Context {
979976

980977
static void diagnoseThrowInIllegalContext(DiagnosticEngine &Diags,
981978
ASTNode node,
982-
StringRef description,
983-
bool throwInDefer = false) {
984-
if (auto *e = node.dyn_cast<Expr*>())
979+
StringRef description) {
980+
if (auto *e = node.dyn_cast<Expr*>()) {
985981
if (isa<ApplyExpr>(e)) {
986982
Diags.diagnose(e->getLoc(), diag::throwing_call_in_illegal_context,
987983
description);
988984
return;
989985
}
990-
991-
if (throwInDefer) {
992-
// Return because this would've already been diagnosed in TypeCheckStmt.
993-
return;
994986
}
995987

996988
Diags.diagnose(node.getStartLoc(), diag::throw_in_illegal_context,
@@ -1156,7 +1148,7 @@ class Context {
11561148
diagnoseThrowInIllegalContext(Diags, E, "a catch guard expression");
11571149
return;
11581150
case Kind::DeferBody:
1159-
diagnoseThrowInIllegalContext(Diags, E, "a defer body", isInDefer);
1151+
diagnoseThrowInIllegalContext(Diags, E, "a defer body");
11601152
return;
11611153
}
11621154
llvm_unreachable("bad context kind");

lib/Sema/TypeCheckStmt.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -610,13 +610,6 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
610610
}
611611

612612
Stmt *visitThrowStmt(ThrowStmt *TS) {
613-
// If the throw is in a defer, then it isn't valid.
614-
if (isInDefer()) {
615-
getASTContext().Diags.diagnose(TS->getThrowLoc(),
616-
diag::jump_out_of_defer, "throw");
617-
return nullptr;
618-
}
619-
620613
// Coerce the operand to the exception type.
621614
auto E = TS->getSubExpr();
622615

test/stmt/statements.swift

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,30 +388,92 @@ enum DeferThrowError: Error {
388388
}
389389

390390
func throwInDefer() {
391-
defer { throw DeferThrowError.someError } // expected-error {{'throw' cannot transfer control out of a defer statement}}
391+
defer { throw DeferThrowError.someError } // expected-error {{errors cannot be thrown out of a defer body}}
392392
print("Foo")
393393
}
394394

395+
func throwInDeferOK1() {
396+
defer {
397+
do {
398+
throw DeferThrowError.someError
399+
} catch {}
400+
}
401+
print("Bar")
402+
}
403+
404+
func throwInDeferOK2() throws {
405+
defer {
406+
do {
407+
throw DeferThrowError.someError
408+
} catch {}
409+
}
410+
print("Bar")
411+
}
412+
395413
func throwingFuncInDefer1() throws {
396414
defer { try throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
397415
print("Bar")
398416
}
399417

418+
func throwingFuncInDefer1a() throws {
419+
defer {
420+
do {
421+
try throwingFunctionCalledInDefer()
422+
} catch {}
423+
}
424+
print("Bar")
425+
}
426+
400427
func throwingFuncInDefer2() throws {
401428
defer { throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
402429
print("Bar")
403430
}
404431

432+
func throwingFuncInDefer2a() throws {
433+
defer {
434+
do {
435+
throwingFunctionCalledInDefer()
436+
// expected-error@-1 {{call can throw but is not marked with 'try'}}
437+
// expected-note@-2 {{did you mean to use 'try'?}}
438+
// expected-note@-3 {{did you mean to handle error as optional value?}}
439+
// expected-note@-4 {{did you mean to disable error propagation?}}
440+
} catch {}
441+
}
442+
print("Bar")
443+
}
444+
405445
func throwingFuncInDefer3() {
406446
defer { try throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
407447
print("Bar")
408448
}
409449

450+
func throwingFuncInDefer3a() {
451+
defer {
452+
do {
453+
try throwingFunctionCalledInDefer()
454+
} catch {}
455+
}
456+
print("Bar")
457+
}
458+
410459
func throwingFuncInDefer4() {
411460
defer { throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
412461
print("Bar")
413462
}
414463

464+
func throwingFuncInDefer4a() {
465+
defer {
466+
do {
467+
throwingFunctionCalledInDefer()
468+
// expected-error@-1 {{call can throw but is not marked with 'try'}}
469+
// expected-note@-2 {{did you mean to use 'try'?}}
470+
// expected-note@-3 {{did you mean to handle error as optional value?}}
471+
// expected-note@-4 {{did you mean to disable error propagation?}}
472+
} catch {}
473+
}
474+
print("Bar")
475+
}
476+
415477
func throwingFunctionCalledInDefer() throws {
416478
throw DeferThrowError.someError
417479
}

0 commit comments

Comments
 (0)