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.podchishcha...@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: }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to