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

Oleksandr T. via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 5 22:32:15 PDT 2024


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.tarasiuk at 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.tarasiuk at 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.tarasiuk at 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}}



More information about the cfe-commits mailing list