Skip to content

[Clang][C++23] update constexpr diagnostics for missing return statements per P2448 #94123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 10, 2024
36 changes: 24 additions & 12 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1806,6 +1806,7 @@ static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) {
static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
Stmt *Body,
Sema::CheckConstexprKind Kind);
static bool CheckConstexprMissingReturn(Sema &SemaRef, const FunctionDecl *Dcl);

// Check whether a function declaration satisfies the requirements of a
// constexpr function definition or a constexpr constructor definition. If so,
Expand Down Expand Up @@ -2411,20 +2412,9 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
}
} else {
if (ReturnStmts.empty()) {
// C++1y doesn't require constexpr functions to contain a 'return'
// statement. We still do, unless the return type might be void, because
// otherwise if there's no return statement, the function cannot
// be used in a core constant expression.
bool OK = SemaRef.getLangOpts().CPlusPlus14 &&
(Dcl->getReturnType()->isVoidType() ||
Dcl->getReturnType()->isDependentType());
switch (Kind) {
case Sema::CheckConstexprKind::Diagnose:
SemaRef.Diag(Dcl->getLocation(),
OK ? diag::warn_cxx11_compat_constexpr_body_no_return
: diag::err_constexpr_body_no_return)
<< Dcl->isConsteval();
if (!OK)
if (!CheckConstexprMissingReturn(SemaRef, Dcl))
return false;
break;

Expand Down Expand Up @@ -2494,6 +2484,28 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
return true;
}

static bool CheckConstexprMissingReturn(Sema &SemaRef,
const FunctionDecl *Dcl) {
bool IsVoidOrDependentType = Dcl->getReturnType()->isVoidType() ||
Dcl->getReturnType()->isDependentType();
// Skip emitting a missing return error diagnostic for non-void functions
// since C++23 no longer mandates constexpr functions to yield constant
// expressions.
if (SemaRef.getLangOpts().CPlusPlus23 && !IsVoidOrDependentType)
return true;

// C++14 doesn't require constexpr functions to contain a 'return'
// statement. We still do, unless the return type might be void, because
// otherwise if there's no return statement, the function cannot
// be used in a core constant expression.
bool OK = SemaRef.getLangOpts().CPlusPlus14 && IsVoidOrDependentType;
SemaRef.Diag(Dcl->getLocation(),
OK ? diag::warn_cxx11_compat_constexpr_body_no_return
: diag::err_constexpr_body_no_return)
<< Dcl->isConsteval();
return OK;
}

bool Sema::CheckImmediateEscalatingFunctionDefinition(
FunctionDecl *FD, const sema::FunctionScopeInfo *FSI) {
if (!getLangOpts().CPlusPlus20 || !FD->isImmediateEscalating())
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ constexpr int ClassDecl3() {
return 0;
}

constexpr int NoReturn() {} // expected-error {{no return statement in constexpr function}}
constexpr int NoReturn() {} // beforecxx23-error {{no return statement in constexpr function}}
constexpr int MultiReturn() {
return 0; // beforecxx14-note {{return statement}}
return 0; // beforecxx14-warning {{multiple return statements in constexpr function}}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/constant-expression-cxx14.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ constexpr void k() {

// If the return type is not 'void', no return statements => never a constant
// expression, so still diagnose that case.
[[noreturn]] constexpr int fn() { // expected-error {{no return statement in constexpr function}}
[[noreturn]] constexpr int fn() { // cxx14_20-error {{no return statement in constexpr function}}
fn();
}

Expand Down
7 changes: 7 additions & 0 deletions clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s

constexpr int f() { } // expected-warning {{non-void function does not return a value}}
static_assert(__is_same(decltype([] constexpr -> int { }( )), int)); // expected-warning {{non-void lambda does not return a value}}

consteval int g() { } // expected-warning {{non-void function does not return a value}}
static_assert(__is_same(decltype([] consteval -> int { }( )), int)); // expected-warning {{non-void lambda does not return a value}}
Loading