https://github.com/AhmedKamel10 created https://github.com/llvm/llvm-project/pull/219358
This patch diagnoses undefined behavior during constant evaluation when a member function is called for an object under construction before all base classes have been initialized. Fixes #211286 >From c0d58fd3b0c899031a5cca0b20422232de7de37b Mon Sep 17 00:00:00 2001 From: ahmedkamel10 <[email protected]> Date: Fri, 28 Aug 2026 06:33:09 +0300 Subject: [PATCH 1/2] [Clang][ConstExpr] Reject member function calls before base initialization This patch diagnoses undefined behavior during constant evaluation when a member function is called for an object under construction before all base classes have been initialized, per C++20 [class.base.init]/16. Fixes #211286 --- clang/lib/AST/ExprConstant.cpp | 6 ++++++ .../SemaCXX/constant-expression-cxx2a.cpp | 19 ++++++++++++++++++ test.cpp | 20 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 test.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9702105951b7b..34c1cb39dd8b1 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6625,6 +6625,12 @@ static bool checkNonVirtualMemberCallThisPointer(EvalInfo &Info, const Expr *E, const LValue &This, const CXXMethodDecl *NamedMember) { + ConstructionPhase Phase = + Info.isEvaluatingCtorDtor(This.getLValueBase(), This.Designator.Entries); + if (Phase == ConstructionPhase::Bases) { + Info.FFDiag(E); + return false; + } return checkDynamicType( Info, E, This, isa<CXXDestructorDecl>(NamedMember) ? AK_Destroy : AK_MemberCall, false); diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp index 870865646a61e..88b4808a4671e 100644 --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -1544,3 +1544,22 @@ namespace GH197403 { } static_assert(test() == 0); } + +namespace GH211286 { + struct A { + constexpr A(int x) : val(x) {} + int val; + }; + + struct B : A { + constexpr int f() const { return 42; } + constexpr B() : A(f()) {} // expected-note 2{{subexpression not valid in a constant expression}} + }; + + constexpr int foo() { + constexpr B b{}; // expected-error {{constexpr variable 'b' must be initialized by a constant expression}} expected-note 2{{in call to 'B()'}} + return b.val; + } + + constexpr auto x = foo(); // expected-error {{constexpr variable 'x' must be initialized by a constant expression}} expected-note {{in call to 'foo()'}} +} \ No newline at end of file diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000000000..a57b905cc317b --- /dev/null +++ b/test.cpp @@ -0,0 +1,20 @@ +struct A { + constexpr A(int x) : val(x) {} + int val; +}; + +struct B : A { + constexpr int f() const { return 42; } + + constexpr B() : A(f()) {} +}; + +constexpr int foo() { + constexpr B b{}; + return b.val; +} + +int main() { + constexpr auto x = foo(); + return 0; +} >From 675846539d5f23fb06814eebbe341e3e9c6dd2af Mon Sep 17 00:00:00 2001 From: ahmedkamel10 <[email protected]> Date: Fri, 28 Aug 2026 07:16:45 +0300 Subject: [PATCH 2/2] Remove test.cpp --- test.cpp | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 test.cpp diff --git a/test.cpp b/test.cpp deleted file mode 100644 index a57b905cc317b..0000000000000 --- a/test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -struct A { - constexpr A(int x) : val(x) {} - int val; -}; - -struct B : A { - constexpr int f() const { return 42; } - - constexpr B() : A(f()) {} -}; - -constexpr int foo() { - constexpr B b{}; - return b.val; -} - -int main() { - constexpr auto x = foo(); - return 0; -} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
