[clang] [llvm] [Clang][ConstExpr] Reject member function calls before base initialization (PR #219358)
ahmed mohamed kamel via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 21:25:19 PDT 2026
https://github.com/AhmedKamel10 updated https://github.com/llvm/llvm-project/pull/219358
>From c0d58fd3b0c899031a5cca0b20422232de7de37b Mon Sep 17 00:00:00 2001
From: ahmedkamel10 <amkzaher at gmail.com>
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 4f1eaf604a6c753465db4d8cccd506b2f32193a1 Mon Sep 17 00:00:00 2001
From: ahmedkamel10 <amkzaher at gmail.com>
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;
-}
More information about the llvm-commits
mailing list