From f6bded3e92814b7ec5f2c3427e9c61b3fa0775f2 Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Wed, 15 Oct 2025 20:09:36 -0700 Subject: [PATCH 1/4] [Clang][Sema] Fix err_constexpr_virtual_base diagnostic so that it only diagnoses on constructors and destructors When this diagnostic was implemented it fired for all non-static data members. I added checking so that it only fires for contructors and destructors before C++26 (which now allows this). Some special care was required for the destructor case since constexpr constuctors were not allowed in C++11. Modified existing test to cover the new conditions. Fixes: https://github.com/llvm/llvm-project/issues/97266 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/Sema/SemaDeclCXX.cpp | 10 ++++++---- clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp | 10 ++++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 40bc7b9a4e45e..0eae2b76ff9b9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3026,7 +3026,7 @@ def warn_cxx17_compat_constexpr_virtual : Warning< "virtual constexpr functions are incompatible with " "C++ standards before C++20">, InGroup, DefaultIgnore; def err_constexpr_virtual_base : Error< - "constexpr %select{member function|constructor}0 not allowed in " + "constexpr %select{destructor|constructor}0 not allowed in " "%select{struct|interface|class}1 with virtual base " "%plural{1:class|:classes}2">; def note_non_literal_incomplete : Note< diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d41ab126c426f..da94b0070dfcb 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1918,8 +1918,10 @@ static bool CheckConstexprMissingReturn(Sema &SemaRef, const FunctionDecl *Dcl); bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, CheckConstexprKind Kind) { - const CXXMethodDecl *MD = dyn_cast(NewFD); - if (MD && MD->isInstance()) { + if ((!getLangOpts().CPlusPlus26 && isa(NewFD)) || + ((getLangOpts().CPlusPlus20 && !getLangOpts().CPlusPlus26) && + isa(NewFD))) { + const CXXMethodDecl *MD = dyn_cast(NewFD); // C++11 [dcl.constexpr]p4: // The definition of a constexpr constructor shall satisfy the following // constraints: @@ -1933,8 +1935,8 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, return false; Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base) - << isa(NewFD) - << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases(); + << isa(NewFD) + << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases(); for (const auto &I : RD->vbases()) Diag(I.getBeginLoc(), diag::note_constexpr_virtual_base_here) << I.getSourceRange(); 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 51990ee4341d2..5a06d686b4c0f 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 @@ -84,10 +84,16 @@ struct T3 { struct U { constexpr U SelfReturn() const; constexpr int SelfParam(U) const; + constexpr ~U(); // beforecxx20-error {{destructor cannot be declared constexpr}} }; -struct V : virtual U { // expected-note {{here}} - constexpr int F() const { return 0; } // expected-error {{constexpr member function not allowed in struct with virtual base class}} +struct V : virtual U { // expected-note {{here}} //aftercxx20-note {{here}} + constexpr V() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}} + constexpr ~V() {} // aftercxx20-error {{constexpr destructor not allowed in struct with virtual base class}} + // beforecxx20-error@-1 {{destructor cannot be declared constexpr}} + // beforecxx14-error@-2 {{constexpr function's return type 'void' is not a literal type}} + // ^ FIXME this is just a bad diagnostic + constexpr int f() const { return 0; } }; // or a compound-statememt that contains only [CXX11] From 171fadb5404da240351d95c2cb2dcd4124dc8ef0 Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Wed, 15 Oct 2025 22:36:55 -0700 Subject: [PATCH 2/4] Fix test I missed updating and remove FIXME --- clang/lib/Sema/SemaDeclCXX.cpp | 3 --- clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index da94b0070dfcb..904316ad8ac8d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1926,9 +1926,6 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, // The definition of a constexpr constructor shall satisfy the following // constraints: // - the class shall not have any virtual base classes; - // - // FIXME: This only applies to constructors and destructors, not arbitrary - // member functions. const CXXRecordDecl *RD = MD->getParent(); if (RD->getNumVBases()) { if (Kind == CheckConstexprKind::CheckValid) diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp index 48bc8fb426bcb..a3d9d1181fef1 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp @@ -6,7 +6,7 @@ namespace vbase { struct A {}; struct B : virtual A { // expected-note {{virtual}} - constexpr ~B() {} // expected-error {{constexpr member function not allowed in struct with virtual base class}} + constexpr ~B() {} // expected-error {{constexpr destructor not allowed in struct with virtual base class}} }; } From 7e9ecfcc264cf8f1ffa9214e26619b1eb6314675 Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Thu, 16 Oct 2025 16:09:05 -0700 Subject: [PATCH 3/4] Switch from dyn_cast to cast since we assume we will have a valid pointer. --- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 904316ad8ac8d..b9db48df424f1 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1921,7 +1921,7 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, if ((!getLangOpts().CPlusPlus26 && isa(NewFD)) || ((getLangOpts().CPlusPlus20 && !getLangOpts().CPlusPlus26) && isa(NewFD))) { - const CXXMethodDecl *MD = dyn_cast(NewFD); + const CXXMethodDecl *MD = cast(NewFD); // C++11 [dcl.constexpr]p4: // The definition of a constexpr constructor shall satisfy the following // constraints: From 0daaba3dcc09230f1f9c471ba40a6de3370ec6be Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Thu, 16 Oct 2025 16:22:35 -0700 Subject: [PATCH 4/4] Add Release note. --- clang/docs/ReleaseNotes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4f62a679b8b21..e851667336c5e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -477,6 +477,7 @@ Bug Fixes to C++ Support - Fix for clang incorrectly rejecting the default construction of a union with nontrivial member when another member has an initializer. (#GH81774) - Diagnose unresolved overload sets in non-dependent compound requirements. (#GH51246) (#GH97753) +- Fix bug where we were diagnosing all constexpr member functions if the class had a virtual bases. (#GH97266) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^