[clang] [clang] Emit initializers for static const/constexpr variables once they're met (PR #156933)
Mariya Podchishchaeva via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 4 10:22:57 PDT 2025
https://github.com/Fznamznon created https://github.com/llvm/llvm-project/pull/156933
Do not wait until the body of the function is met. This helps with initializing static variables in conseval functions.
Fixes https://github.com/llvm/llvm-project/issues/82994
>From 3885133c5a2bafb8654f7b60e016c058705a21ee Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Thu, 4 Sep 2025 10:17:23 -0700
Subject: [PATCH] [clang] Emit static const/constexpr variables once they're
met
Do not wait until the body of the function is met. This helps with
initializing static variables in conseval functions.
Fixes https://github.com/llvm/llvm-project/issues/82994
---
clang/lib/CodeGen/CGDecl.cpp | 21 +++++-
clang/test/CodeGenCXX/pr47636.cpp | 2 +-
clang/test/CodeGenCXX/reference-init.cpp | 2 +-
.../static-constexpr-in-consteval.cpp | 73 +++++++++++++++++++
4 files changed, 92 insertions(+), 6 deletions(-)
create mode 100644 clang/test/CodeGenCXX/static-constexpr-in-consteval.cpp
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 29193e0c541b9..da030f4c73779 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -275,18 +275,31 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
LangAS AS = GetGlobalVarAddressSpace(&D);
unsigned TargetAS = getContext().getTargetAddressSpace(AS);
+ Expr::EvalResult EvalResult;
+ llvm::Constant *Init = nullptr;
+ std::optional<ConstantEmitter> Emitter;
// OpenCL variables in local address space and CUDA shared
// variables cannot have an initializer.
- llvm::Constant *Init = nullptr;
if (Ty.getAddressSpace() == LangAS::opencl_local ||
- D.hasAttr<CUDASharedAttr>() || D.hasAttr<LoaderUninitializedAttr>())
+ D.hasAttr<CUDASharedAttr>() || D.hasAttr<LoaderUninitializedAttr>()) {
Init = llvm::UndefValue::get(LTy);
- else
+ } else if (D.isUsableInConstantExpressions(getContext())) {
+ const Expr *InitExpr = D.getInit();
+ assert(InitExpr && "Usable in constant expressions without initializer?");
+ Emitter.emplace(*this);
+ llvm::Constant *Initializer = Emitter->tryEmitForInitializer(D);
+ Init = Initializer;
+ } else {
Init = EmitNullConstant(Ty);
+ }
llvm::GlobalVariable *GV = new llvm::GlobalVariable(
- getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name,
+ getModule(), Init->getType(), Ty.isConstant(getContext()), Linkage, Init, Name,
nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
+
+ if (Emitter)
+ Emitter->finalize(GV);
+
GV->setAlignment(getContext().getDeclAlign(&D).getAsAlign());
if (supportsCOMDAT() && GV->isWeakForLinker())
diff --git a/clang/test/CodeGenCXX/pr47636.cpp b/clang/test/CodeGenCXX/pr47636.cpp
index 597e94695ca5f..022e085e28845 100644
--- a/clang/test/CodeGenCXX/pr47636.cpp
+++ b/clang/test/CodeGenCXX/pr47636.cpp
@@ -5,8 +5,8 @@ int(&&intu_rvref)[] {1,2,3,4};
void foo() {
static const int(&&intu_rvref)[] {1,2,3,4};
- // CHECK: @_ZZ3foovE10intu_rvref = internal constant ptr @_ZGRZ3foovE10intu_rvref_
// CHECK: @_ZGRZ3foovE10intu_rvref_ = internal constant [4 x i32] [i32 1, i32 2, i32 3, i32 4]
+ // CHECK: @_ZZ3foovE10intu_rvref = internal constant ptr @_ZGRZ3foovE10intu_rvref_
}
// Example given on review, ensure this doesn't crash as well.
diff --git a/clang/test/CodeGenCXX/reference-init.cpp b/clang/test/CodeGenCXX/reference-init.cpp
index a98d400eb17a2..67a901dfe6fa3 100644
--- a/clang/test/CodeGenCXX/reference-init.cpp
+++ b/clang/test/CodeGenCXX/reference-init.cpp
@@ -4,8 +4,8 @@
// expected-no-diagnostics
#if __cplusplus >= 201103L
-// CHECK-CXX11: @_ZZ15InitRefWithListvE1r = internal constant ptr @_ZGRZ15InitRefWithListvE1r_
// CHECK-CXX11: @_ZGRZ15InitRefWithListvE1r_ = internal constant i32 123
+// CHECK-CXX11: @_ZZ15InitRefWithListvE1r = internal constant ptr @_ZGRZ15InitRefWithListvE1r_
int InitRefWithList() { static const int &r = {123}; return r; }
#endif
diff --git a/clang/test/CodeGenCXX/static-constexpr-in-consteval.cpp b/clang/test/CodeGenCXX/static-constexpr-in-consteval.cpp
new file mode 100644
index 0000000000000..d818f9725f196
--- /dev/null
+++ b/clang/test/CodeGenCXX/static-constexpr-in-consteval.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++23 %s -emit-llvm -o - | FileCheck %s
+
+consteval const int* a() {
+ static constexpr int b = 3;
+ return &b;
+}
+
+consteval const int returns42() {
+ static constexpr long c = 42;
+ return c;
+}
+
+struct S {
+ int a;
+ constexpr S(int _a) : a(_a){};
+};
+
+consteval auto returns48viastruct() {
+ static constexpr S s{ 48 };
+ return s;
+}
+
+consteval int why() {
+ static constexpr int a = 10;
+ {
+ static constexpr int a = 20;
+ return a;
+ }
+
+}
+
+consteval const int* returnsarray() {
+ static constexpr int a[] = {10, 20, 30};
+ return a;
+}
+
+// CHECK: @_ZZ1avE1b = linkonce_odr constant i32 3, comdat, align 4
+// CHECK: @_ZZ12returnsarrayvE1a = linkonce_odr constant [3 x i32] [i32 10, i32 20, i32 30], comdat, align 4
+
+// CHECK: define dso_local noundef i32 @_Z1cv()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %0 = load i32, ptr @_ZZ1avE1b, align 4
+// CHECK-NEXT: ret i32 %0
+// CHECK-NEXT: }
+int c() { return *a(); }
+
+// CHECK: define dso_local noundef i32 @_Z1dv()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: ret i32 42
+// CHECK-NEXT: }
+int d() { return returns42(); }
+
+int e() { return returns48viastruct().a; }
+// CHECK: define dso_local noundef i32 @_Z1ev()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %ref.tmp = alloca %struct.S, align 4
+// CHECK-NEXT: %0 = getelementptr inbounds nuw %struct.S, ptr %ref.tmp, i32 0, i32 0
+// CHECK-NEXT: store i32 48, ptr %0, align 4
+// CHECK-NEXT: ret i32 48
+// CHECK-NEXT: }
+
+int f() { return why(); }
+// CHECK: define dso_local noundef i32 @_Z1fv()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: ret i32 20
+// CHECK-NEXT: }
+
+int g() { return returnsarray()[2]; }
+// CHECK: define dso_local noundef i32 @_Z1gv()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %0 = load i32, ptr getelementptr inbounds (i32, ptr @_ZZ12returnsarrayvE1a, i64 2), align 4
+// CHECK-NEXT: ret i32 %0
+// CHECK-NEXT: }
More information about the cfe-commits
mailing list