summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/lib/Sema/SemaStmt.cpp20
-rw-r--r--clang/test/SemaCXX/return.cpp10
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}}
+ };
+}
OpenPOWER on IntegriCloud