]> granicus.if.org Git - clang/commitdiff
Sema: Constexpr functions must have return statements which have an expr
authorDavid Majnemer <david.majnemer@gmail.com>
Sat, 13 Dec 2014 08:12:56 +0000 (08:12 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Sat, 13 Dec 2014 08:12:56 +0000 (08:12 +0000)
clang lets programmers be pretty cavalier when it comes to void return
statements in functions which have non-void return types.  However, we
cannot be so forgiving in constexpr functions: evaluation will go off
the rails very quickly.

Instead, keep the return statement in the AST but mark the function as
invalid.  Doing so gives us nice diagnostics while making constexpr
evaluation halt.

This fixes PR21859.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@224189 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaStmt.cpp
test/SemaCXX/constant-expression-cxx11.cpp

index ec0c3f8f4ff4cd4ab4dcdf18e9516f9a037fce83..48fdf6f826e8aaadbba90c9915bdffa97cf6628f 100644 (file)
@@ -1875,6 +1875,8 @@ def err_enable_if_never_constant_expr : Error<
   "'enable_if' attribute expression never produces a constant expression">;
 def err_constexpr_body_no_return : Error<
   "no return statement in constexpr function">;
+def err_constexpr_return_missing_expr : Error<
+  "non-void constexpr function %0 should return a value">;
 def warn_cxx11_compat_constexpr_body_no_return : Warning<
   "constexpr function with no return statements is incompatible with C++ "
   "standards before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
index 78e33c3bf8c7d707d5b17d9535c12a7072b3c671..8f6c5c6fe3491931db1826ee9ac693d02316a9ea 100644 (file)
@@ -3039,14 +3039,26 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
 
     Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
   } else if (!RetValExp && !HasDependentReturnType) {
-    unsigned DiagID = diag::warn_return_missing_expr;  // C90 6.6.6.4p4
-    // C99 6.8.6.4p1 (ext_ since GCC warns)
-    if (getLangOpts().C99) DiagID = diag::ext_return_missing_expr;
+    FunctionDecl *FD = getCurFunctionDecl();
 
-    if (FunctionDecl *FD = getCurFunctionDecl())
+    unsigned DiagID;
+    if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) {
+      // C++11 [stmt.return]p2
+      DiagID = diag::err_constexpr_return_missing_expr;
+      FD->setInvalidDecl();
+    } else if (getLangOpts().C99) {
+      // C99 6.8.6.4p1 (ext_ since GCC warns)
+      DiagID = diag::ext_return_missing_expr;
+    } else {
+      // C90 6.6.6.4p4
+      DiagID = diag::warn_return_missing_expr;
+    }
+
+    if (FD)
       Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
     else
       Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
+
     Result = new (Context) ReturnStmt(ReturnLoc);
   } else {
     assert(RetValExp || HasDependentReturnType);
index 5fb6f2c5f81c5bed2b3ee12960faea3a43f152b9..cf317950c7724ceb3ee4d822da7c8139b25ace2d 100644 (file)
@@ -1969,3 +1969,8 @@ namespace PR21786 {
   static_assert(&Bar::x != nullptr, "");
   static_assert(&Bar::x != &Bar::y, ""); // expected-error {{constant expression}}
 }
+
+namespace PR21859 {
+  constexpr int Fun() { return; } // expected-error {{non-void constexpr function 'Fun' should return a value}}
+  constexpr int Var = Fun(); // expected-error {{constexpr variable 'Var' must be initialized by a constant expression}}
+}