diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 20 | ||||
| -rw-r--r-- | clang/test/SemaCXX/return.cpp | 10 | 
3 files changed, 28 insertions, 4 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 20cdfdf545f..a22df2b1af6 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<InvalidNoreturn>; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 861d5cf240c..6bda42deaa2 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<CXXConstructorDecl>(CurDecl) || +              isa<CXXDestructorDecl>(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<CXXDestructorDecl>(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 580f0a7233e..98dbd51f580 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}} +  }; +}  | 

