https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/94123
>From 90eeafc82ee08129c2d290e6382f42ec89680049 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Sun, 2 Jun 2024 00:07:35 +0300 Subject: [PATCH 1/3] feat(92583): [C++23] update constexpr diagnostics for missing return statements per P2448 --- clang/lib/Sema/SemaDeclCXX.cpp | 34 ++++++++++++------- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp | 2 +- .../SemaCXX/constant-expression-cxx14.cpp | 2 +- .../constexpr-return-non-void-cxx2b.cpp | 7 ++++ 4 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 631fd4e354927..d4401a427282c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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, @@ -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; @@ -2487,6 +2477,26 @@ 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(); + + if (SemaRef.getLangOpts().CPlusPlus23 && !IsVoidOrDependentType) + return true; + + // 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 && 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()) diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp index 4416c82522649..51990ee4341d2 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -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}} diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp index 80a7a2dd31531..70ab5dcd357c1 100644 --- a/clang/test/SemaCXX/constant-expression-cxx14.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp @@ -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(); } diff --git a/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp b/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp new file mode 100644 index 0000000000000..91a8bb656b317 --- /dev/null +++ b/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -Wno-return-type -std=c++23 -fsyntax-only -verify %s +// expected-no-diagnostics +constexpr int f() { } +static_assert(__is_same(decltype([] constexpr -> int { }( )), int)); + +consteval int g() { } +static_assert(__is_same(decltype([] consteval -> int { }( )), int)); >From 6eca5eeec395ecbbb74aec5e5234a2d4ad30b2e3 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Tue, 4 Jun 2024 21:52:55 +0300 Subject: [PATCH 2/3] add additional comments --- clang/lib/Sema/SemaDeclCXX.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d4401a427282c..3ee59a4a9a423 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2481,11 +2481,13 @@ 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++1y doesn't require constexpr functions to contain a 'return' + // 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. >From 63935cf3c22732575b8f8c5f67395fd5d08c6196 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Tue, 4 Jun 2024 21:54:28 +0300 Subject: [PATCH 3/3] adjust test for validating warnings --- .../test/SemaCXX/constexpr-return-non-void-cxx2b.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp b/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp index 91a8bb656b317..25d1f8df7f716 100644 --- a/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp +++ b/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -Wno-return-type -std=c++23 -fsyntax-only -verify %s -// expected-no-diagnostics -constexpr int f() { } -static_assert(__is_same(decltype([] constexpr -> int { }( )), int)); +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s -consteval int g() { } -static_assert(__is_same(decltype([] consteval -> int { }( )), int)); +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}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits