diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index c6f3b0b50b..e115703a95 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1204,6 +1204,8 @@ def err_throw_incomplete : Error< "cannot throw object of incomplete type %0">; def err_throw_incomplete_ptr : Error< "cannot throw pointer to object of incomplete type %0">; +def err_return_in_constructor_handler : Error< + "return in the catch of a function try block of a constructor is illegal">; def err_invalid_use_of_function_type : Error< "a function type is not allowed here">; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 637804ce09..faaeb7989e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -60,6 +60,7 @@ namespace clang { class ArrayType; class LabelStmt; class SwitchStmt; + class CXXTryStmt; class ExtVectorType; class TypedefDecl; class TemplateDecl; @@ -1225,6 +1226,7 @@ public: virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock, MultiStmtArg Handlers); + void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 482c304603..7549c9c69c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3054,6 +3054,11 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) { if (CurFunctionNeedsScopeChecking) DiagnoseInvalidJumps(Body); + // C++ constructors that have function-try-blocks can't have return statements + // in the handlers of that block. (C++ [except.handle]p14) Verify this. + if (isa(dcl) && isa(Body)) + DiagnoseReturnInConstructorExceptionHandler(cast(Body)); + return D; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 87a518b558..71d2f80cfc 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2664,3 +2664,24 @@ void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) { } Fn->setDeleted(); } + +static void SearchForReturnInStmt(Sema &Self, Stmt *S) { + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; + ++CI) { + Stmt *SubStmt = *CI; + if (!SubStmt) + continue; + if (isa(SubStmt)) + Self.Diag(SubStmt->getSourceRange().getBegin(), + diag::err_return_in_constructor_handler); + if (!isa(SubStmt)) + SearchForReturnInStmt(Self, SubStmt); + } +} + +void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { + for (unsigned I = 0, E = TryBlock->getNumHandlers(); I != E; ++I) { + CXXCatchStmt *Handler = TryBlock->getHandler(I); + SearchForReturnInStmt(*this, Handler); + } +} diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp index 42973eba70..5882b9cb70 100644 --- a/test/SemaCXX/exceptions.cpp +++ b/test/SemaCXX/exceptions.cpp @@ -68,3 +68,32 @@ l5: goto l2; // expected-error {{illegal goto into protected scope}} goto l1; } + +struct BadReturn { + BadReturn() try { + } catch(...) { + // Try to hide + try { + } catch(...) { + { + if (0) + return; // expected-error {{return in the catch of a function try block of a constructor is illegal}} + } + } + } + BadReturn(int); +}; + +BadReturn::BadReturn(int) try { +} catch(...) { + // Try to hide + try { + } catch(int) { + return; // expected-error {{return in the catch of a function try block of a constructor is illegal}} + } catch(...) { + { + if (0) + return; // expected-error {{return in the catch of a function try block of a constructor is illegal}} + } + } +} diff --git a/www/cxx_status.html b/www/cxx_status.html index ab8171c4cf..e8547cd6bb 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -1664,7 +1664,7 @@ welcome!

N/A - Not all constraints are checked, such as existence of return statements in function-try-block handlers of constructors + Not all constraints are checked   15.4 [except.spec]