Skip to content

Commit cbfeb10

Browse files
authored
Merge pull request #29687 from slavapestov/fix-throws-in-defer-diagnostics-5.2
Sema: Only diagnose 'throws' in 'defer' as part of TypeCheckError [5.2]
2 parents fd192f4 + 7253052 commit cbfeb10

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
@@ -627,13 +627,6 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
627627
}
628628

629629
Stmt *visitThrowStmt(ThrowStmt *TS) {
630-
// If the throw is in a defer, then it isn't valid.
631-
if (isInDefer()) {
632-
getASTContext().Diags.diagnose(TS->getThrowLoc(),
633-
diag::jump_out_of_defer, "throw");
634-
return nullptr;
635-
}
636-
637630
// Coerce the operand to the exception type.
638631
auto E = TS->getSubExpr();
639632

test/stmt/statements.swift

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

373373
func throwInDefer() {
374-
defer { throw DeferThrowError.someError } // expected-error {{'throw' cannot transfer control out of a defer statement}}
374+
defer { throw DeferThrowError.someError } // expected-error {{errors cannot be thrown out of a defer body}}
375375
print("Foo")
376376
}
377377

378+
func throwInDeferOK1() {
379+
defer {
380+
do {
381+
throw DeferThrowError.someError
382+
} catch {}
383+
}
384+
print("Bar")
385+
}
386+
387+
func throwInDeferOK2() throws {
388+
defer {
389+
do {
390+
throw DeferThrowError.someError
391+
} catch {}
392+
}
393+
print("Bar")
394+
}
395+
378396
func throwingFuncInDefer1() throws {
379397
defer { try throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
380398
print("Bar")
381399
}
382400

401+
func throwingFuncInDefer1a() throws {
402+
defer {
403+
do {
404+
try throwingFunctionCalledInDefer()
405+
} catch {}
406+
}
407+
print("Bar")
408+
}
409+
383410
func throwingFuncInDefer2() throws {
384411
defer { throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
385412
print("Bar")
386413
}
387414

415+
func throwingFuncInDefer2a() throws {
416+
defer {
417+
do {
418+
throwingFunctionCalledInDefer()
419+
// expected-error@-1 {{call can throw but is not marked with 'try'}}
420+
// expected-note@-2 {{did you mean to use 'try'?}}
421+
// expected-note@-3 {{did you mean to handle error as optional value?}}
422+
// expected-note@-4 {{did you mean to disable error propagation?}}
423+
} catch {}
424+
}
425+
print("Bar")
426+
}
427+
388428
func throwingFuncInDefer3() {
389429
defer { try throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
390430
print("Bar")
391431
}
392432

433+
func throwingFuncInDefer3a() {
434+
defer {
435+
do {
436+
try throwingFunctionCalledInDefer()
437+
} catch {}
438+
}
439+
print("Bar")
440+
}
441+
393442
func throwingFuncInDefer4() {
394443
defer { throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
395444
print("Bar")
396445
}
397446

447+
func throwingFuncInDefer4a() {
448+
defer {
449+
do {
450+
throwingFunctionCalledInDefer()
451+
// expected-error@-1 {{call can throw but is not marked with 'try'}}
452+
// expected-note@-2 {{did you mean to use 'try'?}}
453+
// expected-note@-3 {{did you mean to handle error as optional value?}}
454+
// expected-note@-4 {{did you mean to disable error propagation?}}
455+
} catch {}
456+
}
457+
print("Bar")
458+
}
459+
398460
func throwingFunctionCalledInDefer() throws {
399461
throw DeferThrowError.someError
400462
}

0 commit comments

Comments
 (0)