https://github.com/schizophrenicmaniac updated https://github.com/llvm/llvm-project/pull/226645
>From 045a77f1533f3a4659c21565015753e3d8631ebc Mon Sep 17 00:00:00 2001 From: Divyansh <[email protected]> Date: Sat, 26 Sep 2026 11:56:14 +0530 Subject: [PATCH] [clang][CodeGen] Use guarded init for weak static locals without constant init (#226631) --- clang/lib/CodeGen/CGDecl.cpp | 22 ++++-- .../static-local-inline-non-constant-init.cpp | 77 +++++++++++++++++++ 2 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index e1ed66ae71243..bbf94e8c4ecce 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -224,10 +224,6 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { llvm::GlobalValue::LinkageTypes Linkage = CGM.getLLVMLinkageVarDefinition(&D); - // FIXME: We need to force the emission/use of a guard variable for - // some variables even if we can constant-evaluate them because - // we can't guarantee every translation unit will constant-evaluate them. - return EmitStaticVarDecl(D, Linkage); } @@ -360,8 +356,24 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( llvm::GlobalVariable * CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, llvm::GlobalVariable *GV) { + // A static local with vague linkage (e.g. one in an inline function) is + // shared by every translation unit that emits it, but only a constant + // initializer is guaranteed to be emitted as a constant in all of them. If + // we were to fold an initializer that another translation unit can't fold + // (say, because it reads a variable whose initializer is only visible here), + // that translation unit would perform a guarded initialization which could + // store to our copy of the variable (possibly placed in read-only memory) or + // race with our unguarded reads of it. Use a guarded initialization here as + // well, so that every translation unit agrees on how the variable is + // initialized. + bool NeedsGuardedInit = + getLangOpts().CPlusPlus && !getLangOpts().CUDAIsDevice && + GV->isWeakForLinker() && !D.hasConstantInitialization() && + !D.hasFlexibleArrayInit(getContext()); + ConstantEmitter emitter(*this); - llvm::Constant *Init = emitter.tryEmitForInitializer(D); + llvm::Constant *Init = + NeedsGuardedInit ? nullptr : emitter.tryEmitForInitializer(D); // If constant emission failed, then this should be a C++ static // initializer. diff --git a/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp b/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp new file mode 100644 index 0000000000000..ec78d2d90e360 --- /dev/null +++ b/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -o - %s | FileCheck %s --check-prefix=ITANIUM +// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++17 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSVC + +// A static local in an inline function is shared by every translation unit +// that uses the function. If its initializer isn't a constant initializer, +// another translation unit might not be able to fold it (here, one that can't +// see the initializer of kSize) and will initialize the variable dynamically, +// behind a guard variable. So it must not be emitted as a (possibly read-only) +// constant without a guard in this translation unit either. +// See https://github.com/llvm/llvm-project/issues/226631. + +extern const int kSize; + +inline const int &instance() { + static const int meta = kSize; + return meta; +} + +// Constant initializers are still emitted as constants, without a guard. +inline const int &constant() { + static const int c = 42; + return c; +} + +// A static local that isn't shared with other translation units can still be +// folded, even if its initializer isn't a constant initializer. +static const int &internal() { + static const int i = kSize; + return i; +} + +extern const int kSize = 3; + +const int *a() { return &instance(); } +const int *b() { return &constant(); } +const int *c() { return &internal(); } + +// ITANIUM-DAG: @_ZZ8instancevE4meta = linkonce_odr global i32 0, comdat, align 4 +// ITANIUM-DAG: @_ZGVZ8instancevE4meta = linkonce_odr global i64 0, comdat, align 8 +// ITANIUM-DAG: @_ZZ8constantvE1c = linkonce_odr constant i32 42, comdat, align 4 +// ITANIUM-DAG: @_ZZL8internalvE1i = internal constant i32 3, align 4 +// ITANIUM-NOT: @_ZGVZ8constantvE1c +// ITANIUM-NOT: @_ZGVZL8internalvE1i + +// ITANIUM-LABEL: define linkonce_odr {{.*}} ptr @_Z8instancev() +// ITANIUM: load atomic i8, ptr @_ZGVZ8instancevE4meta acquire +// ITANIUM: call i32 @__cxa_guard_acquire(ptr @_ZGVZ8instancevE4meta) +// ITANIUM: store i32 3, ptr @_ZZ8instancevE4meta +// ITANIUM: call void @__cxa_guard_release(ptr @_ZGVZ8instancevE4meta) +// ITANIUM: ret ptr @_ZZ8instancevE4meta + +// ITANIUM-LABEL: define linkonce_odr {{.*}} ptr @_Z8constantv() +// ITANIUM-NEXT: entry: +// ITANIUM-NEXT: ret ptr @_ZZ8constantvE1c + +// ITANIUM-LABEL: define internal {{.*}} ptr @_ZL8internalv() +// ITANIUM-NEXT: entry: +// ITANIUM-NEXT: ret ptr @_ZZL8internalvE1i + +// MSVC-DAG: @"?meta@?1??instance@@YAAEBHXZ@4HB" = linkonce_odr dso_local global i32 0, comdat, align 4 +// MSVC-DAG: @"?$TSS0@?1??instance@@YAAEBHXZ@4HA" = linkonce_odr global i32 0, comdat, align 4 +// MSVC-DAG: @"?c@?1??constant@@YAAEBHXZ@4HB" = linkonce_odr dso_local constant i32 42, comdat, align 4 +// MSVC-DAG: @"?i@?1??internal@@YAAEBHXZ@4HB" = internal constant i32 3, align 4 + +// MSVC-LABEL: define linkonce_odr {{.*}} ptr @"?instance@@YAAEBHXZ"() +// MSVC: call void @_Init_thread_header(ptr @"?$TSS0@?1??instance@@YAAEBHXZ@4HA") +// MSVC: store i32 3, ptr @"?meta@?1??instance@@YAAEBHXZ@4HB" +// MSVC: call void @_Init_thread_footer(ptr @"?$TSS0@?1??instance@@YAAEBHXZ@4HA") +// MSVC: ret ptr @"?meta@?1??instance@@YAAEBHXZ@4HB" + +// MSVC-LABEL: define linkonce_odr {{.*}} ptr @"?constant@@YAAEBHXZ"() +// MSVC-NEXT: entry: +// MSVC-NEXT: ret ptr @"?c@?1??constant@@YAAEBHXZ@4HB" + +// MSVC-LABEL: define internal {{.*}} ptr @"?internal@@YAAEBHXZ"() +// MSVC-NEXT: entry: +// MSVC-NEXT: ret ptr @"?i@?1??internal@@YAAEBHXZ@4HB" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
