From: David Majnemer Date: Sat, 13 Dec 2014 08:12:56 +0000 (+0000) Subject: Sema: Constexpr functions must have return statements which have an expr X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7fad38e6551160d87715ad126690292ce19ce5ae;p=clang Sema: Constexpr functions must have return statements which have an expr 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 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ec0c3f8f4f..48fdf6f826 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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, DefaultIgnore; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 78e33c3bf8..8f6c5c6fe3 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -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); diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 5fb6f2c5f8..cf317950c7 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -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}} +}