[clang] cc4efa3 - [CIR] Lower static locals in C++ ctor and dtor bodies (#197089)
via cfe-commits
cfe-commits at lists.llvm.org
Thu May 14 08:40:26 PDT 2026
Author: adams381
Date: 2026-05-14T10:40:21-05:00
New Revision: cc4efa3992b11d85a7a57f58fc88a2bbde91a8b8
URL: https://github.com/llvm/llvm-project/commit/cc4efa3992b11d85a7a57f58fc88a2bbde91a8b8
DIFF: https://github.com/llvm/llvm-project/commit/cc4efa3992b11d85a7a57f58fc88a2bbde91a8b8.diff
LOG: [CIR] Lower static locals in C++ ctor and dtor bodies (#197089)
Static locals declared inside a C++ constructor or destructor body were
hitting `errorNYI("C++ constructors static var context")` (and the dtor
variant) in `CIRGenModule::getOrCreateStaticVarDecl`, even though the
rest of the static-local plumbing was already in place. The fix is to
mirror what classic CodeGen does at `CGDecl.cpp:328-334` — pick
`GlobalDecl(cd, Ctor_Base)` for ctors and `GlobalDecl(dd, Dtor_Base)`
for dtors instead of erroring.
Hit this trying to compile a couple of SPEC CPU 2026 benchmarks with
`-fclangir`: `flightdm` has a `static constexpr std::array` inside
`FGCondition::FGCondition`, and `gmsh` has a similar shape in
`MetaEl.cpp`. The minimum repro is the obvious one:
```c++
struct Foo { Foo() { static int x = 42; (void)x; } };
Foo f;
```
The new test cross-checks against OGCG so we catch any drift — both
backends emit `@_ZZN4CtorC1EvE1x = linkonce_odr global i32 42, comdat,
align 4` and the dtor analogue.
Both CIR test suites pass cleanly (`check-clang-cir-codegen` and
`check-clang-cir`).
Added:
clang/test/CIR/CodeGen/static-local-in-ctor.cpp
Modified:
clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 2bf90e99eb7d3..c2a0dd80407ca 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -487,10 +487,10 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &d,
}
GlobalDecl gd;
- if (isa<CXXConstructorDecl>(dc))
- errorNYI(d.getSourceRange(), "C++ constructors static var context");
- else if (isa<CXXDestructorDecl>(dc))
- errorNYI(d.getSourceRange(), "C++ destructors static var context");
+ if (const auto *cd = dyn_cast<CXXConstructorDecl>(dc))
+ gd = GlobalDecl(cd, Ctor_Base);
+ else if (const auto *dd = dyn_cast<CXXDestructorDecl>(dc))
+ gd = GlobalDecl(dd, Dtor_Base);
else if (const auto *fd = dyn_cast<FunctionDecl>(dc))
gd = GlobalDecl(fd);
else {
diff --git a/clang/test/CIR/CodeGen/static-local-in-ctor.cpp b/clang/test/CIR/CodeGen/static-local-in-ctor.cpp
new file mode 100644
index 0000000000000..6056d3a2cbfe1
--- /dev/null
+++ b/clang/test/CIR/CodeGen/static-local-in-ctor.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+
+struct Ctor {
+ Ctor() {
+ static int x = 42;
+ (void)x;
+ }
+};
+
+struct Dtor {
+ ~Dtor() {
+ static int y = 7;
+ (void)y;
+ }
+};
+
+void use() { Ctor c; Dtor d; }
+
+
+// Static local inside the constructor body.
+
+// CIR-DAG: cir.global linkonce_odr comdat @_ZZN4CtorC1EvE1x = #cir.int<42> : !s32i {alignment = 4 : i64}
+// LLVM-DAG: @_ZZN4CtorC1EvE1x = linkonce_odr global i32 42, comdat, align 4
+
+
+// Static local inside the destructor body.
+
+// CIR-DAG: cir.global linkonce_odr comdat @_ZZN4DtorD1EvE1y = #cir.int<7> : !s32i {alignment = 4 : i64}
+// LLVM-DAG: @_ZZN4DtorD1EvE1y = linkonce_odr global i32 7, comdat, align 4
+
+
+// The static local is loaded by cir.get_global inside the base-subobject
+// constructor / destructor body (Itanium ABI emits both C1/C2 and D1/D2;
+// both reference the same static).
+
+// CIR: cir.func{{.*}}@_ZN4CtorC2Ev
+// CIR: cir.get_global @_ZZN4CtorC1EvE1x : !cir.ptr<!s32i>
+
+// CIR: cir.func{{.*}}@_ZN4DtorD2Ev
+// CIR: cir.get_global @_ZZN4DtorD1EvE1y : !cir.ptr<!s32i>
More information about the cfe-commits
mailing list