diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 20cdfdf545f5..a22df2b1af69 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6426,6 +6426,8 @@ def ext_return_has_void_expr : Extension< def err_return_init_list : Error< "%select{void function|void method|constructor|destructor}1 %0 " "must not return a value">; +def err_ctor_dtor_returns_void : Error< + "%select{constructor|destructor}1 %0 must not return void expression">; def warn_noreturn_function_has_return_expr : Warning< "function %0 declared 'noreturn' should not return">, InGroup; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 861d5cf240c8..6bda42deaa29 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2801,8 +2801,14 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } else if (!RetValExp->isTypeDependent()) { // C99 6.8.6.4p1 (ext_ since GCC warns) unsigned D = diag::ext_return_has_expr; - if (RetValExp->getType()->isVoidType()) - D = diag::ext_return_has_void_expr; + if (RetValExp->getType()->isVoidType()) { + NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); + if (isa(CurDecl) || + isa(CurDecl)) + D = diag::err_ctor_dtor_returns_void; + else + D = diag::ext_return_has_void_expr; + } else { ExprResult Result = Owned(RetValExp); Result = IgnoredValueConversions(Result.take()); @@ -2812,9 +2818,15 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { RetValExp = ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid).take(); } - + // return of void in constructor/destructor is illegal in C++. + if (D == diag::err_ctor_dtor_returns_void) { + NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); + Diag(ReturnLoc, D) + << CurDecl->getDeclName() << isa(CurDecl) + << RetValExp->getSourceRange(); + } // return (some void expression); is legal in C++. - if (D != diag::ext_return_has_void_expr || + else if (D != diag::ext_return_has_void_expr || !getLangOpts().CPlusPlus) { NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); diff --git a/clang/test/SemaCXX/return.cpp b/clang/test/SemaCXX/return.cpp index 580f0a7233e2..98dbd51f5806 100644 --- a/clang/test/SemaCXX/return.cpp +++ b/clang/test/SemaCXX/return.cpp @@ -102,3 +102,13 @@ namespace return_has_expr { } }; } + +// rdar://15366494 +// pr17759 +namespace ctor_returns_void { + void f() {} + struct S { + S() { return f(); }; // expected-error {{constructor 'S' must not return void expression}} + ~S() { return f(); } // expected-error {{destructor '~S' must not return void expression}} + }; +}