Index: clang/include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticCommonKinds.td +++ clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -251,6 +251,10 @@ def err_unimplemented_conversion_with_fixed_point_type : Error< "conversion between fixed point and %0 is not yet supported">; +def warn_for_global_ctor_for_dllimport : Warning< + "global constructor is generated for dllimport global var %0">, + InGroup; + // SEH def err_seh_expected_handler : Error< "expected '__except' or '__finally' block">; Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -2217,11 +2217,12 @@ // FIXME: Diagnostic! return false; - // A dllimport variable never acts like a constant, unless we're - // evaluating a value for use only in name mangling. - if (!isForManglingOnly(Kind) && Var->hasAttr()) - // FIXME: Diagnostic! - return false; + // In C mode, a dllimport variable never acts like a constant, unless + // we're evaluating a value for use only in name mangling. + if (!Info.getCtx().getLangOpts().CPlusPlus) + if (!isForManglingOnly(Kind) && Var->hasAttr()) + // FIXME: Diagnostic! + return false; // In CUDA/HIP device compilation, only device side variables have // constant addresses. Index: clang/lib/CodeGen/CGDeclCXX.cpp =================================================================== --- clang/lib/CodeGen/CGDeclCXX.cpp +++ clang/lib/CodeGen/CGDeclCXX.cpp @@ -175,7 +175,8 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::GlobalVariable *GV, - bool PerformInit) { + bool PerformInit, + bool PerformDtor) { const Expr *Init = D.getInit(); QualType T = D.getType(); @@ -218,7 +219,7 @@ EmitDeclInit(*this, D, DeclAddr); if (CGM.isTypeConstant(D.getType(), true)) EmitDeclInvariant(*this, D, DeclPtr); - else + else if (PerformDtor) EmitDeclDestroy(*this, D, DeclAddr); return; } @@ -504,6 +505,37 @@ PtrArray->setComdat(C); } +void CodeGenModule::EmitCXXCtorInit(const VarDecl *D, + llvm::GlobalVariable *Addr, + bool PerformInit, int Priority, + llvm::StringLiteral FuncName, + bool PerformDtor) { + if (getLangOpts().CUDAIsDevice && !getLangOpts().GPUAllowDeviceInit && + (D->hasAttr() || D->hasAttr() || + D->hasAttr())) + return; + + if (getLangOpts().OpenMP && + getOpenMPRuntime().emitDeclareTargetVarDefinition(D, Addr, PerformInit)) + return; + + auto I = DelayedCXXInitPosition.find(D); + if (I != DelayedCXXInitPosition.end() && I->second == ~0U) + return; + + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction( + FTy, FuncName.str(), getTypes().arrangeNullaryFunction()); + CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc( + Fn, D, Addr, PerformInit, PerformDtor); + AddGlobalCtor(Fn, Priority); + + if (D->getTLSKind()) { + CXXThreadLocalInits.push_back(Fn); + CXXThreadLocalInitVars.push_back(D); + } +} + void CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, llvm::GlobalVariable *Addr, @@ -976,10 +1008,9 @@ } /// Emit the code necessary to initialize the given global variable. -void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, - const VarDecl *D, - llvm::GlobalVariable *Addr, - bool PerformInit) { +void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc( + llvm::Function *Fn, const VarDecl *D, llvm::GlobalVariable *Addr, + bool PerformInit, bool PerformDtor) { // Check if we need to emit debug info for variable initializer. if (D->hasAttr()) DebugInfo = nullptr; // disable debug info indefinitely for this function @@ -1004,7 +1035,7 @@ isTemplateInstantiation(D->getTemplateSpecializationKind()))) { EmitCXXGuardedInit(*D, Addr, PerformInit); } else { - EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit); + EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit, PerformDtor); } if (getLangOpts().HLSL) Index: clang/lib/CodeGen/CGExprConstant.cpp =================================================================== --- clang/lib/CodeGen/CGExprConstant.cpp +++ clang/lib/CodeGen/CGExprConstant.cpp @@ -1921,8 +1921,11 @@ if (auto VD = dyn_cast(D)) { // We can never refer to a variable with local storage. if (!VD->hasLocalStorage()) { - if (VD->isFileVarDecl() || VD->hasExternalStorage()) + if (VD->isFileVarDecl() || VD->hasExternalStorage()) { + if (VD->hasAttr()) + return nullptr; return CGM.GetAddrOfGlobalVar(VD); + } if (VD->isLocalVarDecl()) { return CGM.getOrCreateStaticVarDecl( Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -4453,7 +4453,7 @@ /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++ /// variable with global storage. void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::GlobalVariable *GV, - bool PerformInit); + bool PerformInit, bool PerformDtor = true); llvm::Function *createAtExitStub(const VarDecl &VD, llvm::FunctionCallee Dtor, llvm::Constant *Addr); @@ -4505,10 +4505,10 @@ llvm::Constant *>> DtorsOrStermFinalizers); - void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, - const VarDecl *D, + void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, llvm::GlobalVariable *Addr, - bool PerformInit); + bool PerformInit, + bool PerformDtor = true); void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest); Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -1624,6 +1624,9 @@ void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, llvm::GlobalVariable *Addr, bool PerformInit); + void EmitCXXCtorInit(const VarDecl *D, llvm::GlobalVariable *Addr, + bool PerformInit, int Priority, + llvm::StringLiteral FnName, bool PerformDtor); void EmitPointerToInitFunc(const VarDecl *VD, llvm::GlobalVariable *Addr, llvm::Function *InitFunc, InitSegAttr *ISA); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -4811,6 +4811,10 @@ GO.setComdat(TheModule.getOrInsertComdat(GO.getName())); } +bool isStaticInit(const VarDecl *D, const LangOptions Opts) { + return Opts.CPlusPlus && D->hasConstantInitialization(); +} + /// Pass IsTentative as true if you want to create a tentative definition. void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative) { @@ -4836,6 +4840,7 @@ bool NeedsGlobalDtor = !IsDefinitionAvailableExternally && D->needsDestruction(getContext()) == QualType::DK_cxx_destructor; + bool NeedsInit = true; const VarDecl *InitDecl; const Expr *InitExpr = D->getAnyInitializer(InitDecl); @@ -4888,9 +4893,12 @@ if (InitDecl->hasFlexibleArrayInit(getContext())) ErrorUnsupported(D, "flexible array initializer"); Init = EmitNullConstant(T); - if (!IsDefinitionAvailableExternally) NeedsGlobalCtor = true; + if (isStaticInit(D, getLangOpts())) { + DiagnosticsEngine &Diags = getContext().getDiagnostics(); + Diags.Report(diag::warn_for_global_ctor_for_dllimport) << D; + } } else { ErrorUnsupported(D, "static initializer"); Init = llvm::UndefValue::get(getTypes().ConvertType(T)); @@ -4902,6 +4910,11 @@ // also don't need to register a destructor. if (getLangOpts().CPlusPlus && !NeedsGlobalDtor) DelayedCXXInitPosition.erase(D); + if (isStaticInit(D, getLangOpts()) && !NeedsGlobalCtor && + NeedsGlobalDtor) { + NeedsGlobalCtor = true; + NeedsInit = false; + } #ifndef NDEBUG CharUnits VarSize = getContext().getTypeSizeInChars(ASTTy) + @@ -5055,9 +5068,19 @@ maybeSetTrivialComdat(*D, *GV); // Emit the initializer function if necessary. - if (NeedsGlobalCtor || NeedsGlobalDtor) - EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); + if (isStaticInit(D, getLangOpts()) && NeedsGlobalCtor) { + EmitCXXCtorInit(D, GV, NeedsInit, 201, llvm::StringLiteral("__ctor"), + false); + if (NeedsGlobalDtor) + EmitCXXCtorInit(D, GV, NeedsInit, 65535, llvm::StringLiteral("__dtor"), + true); + if (NeedsGlobalCtor || NeedsGlobalDtor) + DelayedCXXInitPosition[D] = ~0U; + } else { + if (NeedsGlobalCtor || NeedsGlobalDtor) + EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); + } SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); // Emit global variable debug information. Index: clang/test/CodeGenCXX/PR19955.cpp =================================================================== --- clang/test/CodeGenCXX/PR19955.cpp +++ clang/test/CodeGenCXX/PR19955.cpp @@ -1,27 +1,34 @@ // RUN: %clang_cc1 -triple i686-windows-msvc -fms-extensions -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s | FileCheck %s --check-prefix X64 +// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s | FileCheck %s --check-prefix=CHECK-X64 extern int __declspec(dllimport) var; extern void __declspec(dllimport) fun(); extern int *varp; int *varp = &var; -// CHECK-DAG: @"?varp@@3PAHA" = dso_local global ptr null -// X64-DAG: @"?varp@@3PEAHEA" = dso_local global ptr null +// CHECK: @"?varp@@3PAHA" = dso_local global ptr null +// CHECK-X64: @"?varp@@3PEAHEA" = dso_local global ptr null +// CHECK: @"?var@@3HA" = external dllimport global i32 +// CHECK: @"?funp@@3P6AXXZA" = dso_local global ptr null -extern void (*funp)(); -void (*funp)() = &fun; -// CHECK-DAG: @"?funp@@3P6AXXZA" = dso_local global ptr null -// X64-DAG: @"?funp@@3P6AXXZEA" = dso_local global ptr null - -// CHECK-LABEL: @"??__Evarp@@YAXXZ" -// CHECK-DAG: store ptr @"?var@@3HA", ptr @"?varp@@3PAHA" +// CHECK-X64: @"?funp@@3P6AXXZEA" = dso_local global ptr null +// CHECK: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 201, ptr @__ctor, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_PR19955.cpp, ptr null }] -// X64-LABEL: @"??__Evarp@@YAXXZ" -// X64-DAG: store ptr @"?var@@3HA", ptr @"?varp@@3PEAHEA" +// CHECK-LABEL: define internal void @__ctor() +// CHECK: entry +// CHECK: store ptr @"?var@@3HA", ptr @"?varp@@3PAHA" +// CHECK-X64: store ptr @"?var@@3HA", ptr @"?varp@@3PEAHEA" +// CHECK: ret void -// CHECK-LABEL: @"??__Efunp@@YAXXZ"() -// CHECK-DAG: store ptr @"?fun@@YAXXZ", ptr @"?funp@@3P6AXXZA" +extern void (*funp)(); +void (*funp)() = &fun; +// CHECK-LABEL: define internal void @"??__Efunp@@YAXXZ" +// CHECK: entry +// CHECK: store ptr @"?fun@@YAXXZ", ptr @"?funp@@3P6AXXZA" +// CHECK-X64: store ptr @"?fun@@YAXXZ", ptr @"?funp@@3P6AXXZEA" +// CHECK: ret void -// X64-LABEL: @"??__Efunp@@YAXXZ"() -// X64-DAG: store ptr @"?fun@@YAXXZ", ptr @"?funp@@3P6AXXZEA" +// CHECK-LABEL: define internal void @_GLOBAL__sub_I_PR19955.cpp() +// CHECK: entry: +// CHECK: call void @"??__Efunp@@YAXXZ"() +// CHECK: ret void Index: clang/test/CodeGenCXX/aix-static-init.cpp =================================================================== --- clang/test/CodeGenCXX/aix-static-init.cpp +++ clang/test/CodeGenCXX/aix-static-init.cpp @@ -39,7 +39,7 @@ } // namespace test4 // CHECK: @_ZGVZN5test41fEvE11staticLocal = internal global i64 0, align 8 -// CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }] +// CHECK: @llvm.global_ctors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 201, ptr @__ctor, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__dtor, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }] // CHECK: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }] // CHECK: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] { @@ -108,9 +108,8 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__cxx_global_var_init.3() [[ATTR:#[0-9]+]] { +// CHECK: define internal void @__ctor() [[ATTR:#[0-9]+]] { // CHECK: entry: -// CHECK: %0 = call i32 @atexit(ptr @__dtor__ZN5test31tE) // CHECK: ret void // CHECK: } @@ -180,7 +179,6 @@ // CHECK: call void @__cxx_global_var_init() // CHECK: call void @__cxx_global_var_init.1() // CHECK: call void @__cxx_global_var_init.2() -// CHECK: call void @__cxx_global_var_init.3() // CHECK: ret void // CHECK: } Index: clang/test/CodeGenCXX/call-conv-thru-alias.cpp =================================================================== --- clang/test/CodeGenCXX/call-conv-thru-alias.cpp +++ clang/test/CodeGenCXX/call-conv-thru-alias.cpp @@ -13,9 +13,9 @@ // CHECK: @"??1Derived@@UAE@XZ" = dso_local unnamed_addr alias void (ptr), ptr @"??1Base@@UAE@XZ" // CHECK: define dso_local x86_thiscallcc void @"??1Base@@UAE@XZ" -// CHECK: define internal void @"??__E?inst@Derived@@2U1@A@@YAXXZ" -// CHECK: call i32 @atexit(ptr @"??__F?inst@Derived@@2U1@A@@YAXXZ" +// CHECK: define internal void @__ctor() +// CHECK: define internal void @__dtor() +// CHECK: call i32 @atexit(ptr @"??__F?inst@Derived@@2U1@A@@YAXXZ") // // CHECK: define internal void @"??__F?inst@Derived@@2U1@A@@YAXXZ" -// CHECK-NEXT: entry: -// CHECK-NEXT: call x86_thiscallcc void @"??1Derived@@UAE@XZ" +// CHECK: call x86_thiscallcc void @"??1Derived@@UAE@XZ" Index: clang/test/CodeGenCXX/const-init-cxx11.cpp =================================================================== --- clang/test/CodeGenCXX/const-init-cxx11.cpp +++ clang/test/CodeGenCXX/const-init-cxx11.cpp @@ -430,7 +430,7 @@ // We must emit a constant initializer for NonLiteralConstexpr::ntd, but also // emit an initializer to register its destructor. -// CHECK: define {{.*}}cxx_global_var_init{{.*}} +// CHECK: define internal void @__dtor() // CHECK-NOT: NonLiteralConstexpr // CHECK: call {{.*}}cxa_atexit{{.*}} @_ZN19NonLiteralConstexpr14NonTrivialDtorD1Ev {{.*}} @_ZN19NonLiteralConstexpr3ntdE // CHECK-NEXT: ret void @@ -440,7 +440,7 @@ // We must emit a constant initializer for NonLiteralConstexpr::b, but also // emit an initializer to register its destructor. -// CHECK: define {{.*}}cxx_global_var_init{{.*}} +// CHECK: define internal void @__dtor.2() // CHECK-NOT: NonLiteralConstexpr // CHECK: call {{.*}}cxa_atexit{{.*}} @_ZN19NonLiteralConstexpr4BothD1Ev {{.*}} @_ZN19NonLiteralConstexpr1bE // CHECK-NEXT: ret void Index: clang/test/CodeGenCXX/constant-init.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/constant-init.cpp @@ -0,0 +1,140 @@ +// RUN: %clang_cc1 -triple i686-windows-msvc -fms-extensions -fno-rtti \ +// RUN: -emit-llvm -std=c++2a -O0 -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-I686 + +// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -fno-rtti \ +// RUN: -emit-llvm -std=c++2a -O0 -o - %s | FileCheck %s + +// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -std=c++2a -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-OMP + +// CHECK: @"__tls_init$initializer$" = internal constant ptr @__tls_init +// CHECK: appending global [6 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 201, ptr @__ctor, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__dtor, ptr null }, { i32, ptr, ptr } { i32 201, ptr @__ctor.2, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__dtor.3, ptr null }, { i32, ptr, ptr } { i32 201, ptr @__ctor.4, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__dtor.5, ptr null }] +// CHECK-OMP: @llvm.global_ctors = appending global [7 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 201, ptr @__ctor, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__dtor, ptr null }, { i32, ptr, ptr } { i32 201, ptr @__ctor.1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__dtor.2, ptr null }, { i32, ptr, ptr } { i32 201, ptr @__ctor.3, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__dtor.4, ptr null }, { i32, ptr, ptr } { i32 0, ptr @.omp_offloading.requires_reg, ptr null }] +// CHECK: @llvm.used = appending global [1 x ptr] [ptr @"__tls_init$initializer$"], section "llvm.metadata" + +// CHECK-LABEL: define linkonce_odr dso_local void @__ctor() +// CHECK-OMP-LABEL: define internal void @__ctor() +// CHECK-NEXT: entry: +// CHECK-NEXT: call i32 @atexit(ptr @"??__Ft2@@YAXXZ") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define internal void @"??__Ft2@@YAXXZ"() #0 { +// CHECK-NEXT: entry: +// CHECK-I686: call x86_thiscallcc void @"??1Test1@@QAE@XZ"(ptr @"?t2@@3UTest1@@A") +// CHECK: call void @"??1Test1@@QEAA@XZ"(ptr @"?t2@@3UTest1@@A") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define linkonce_odr dso_local void @__dtor() +// CHECK-OMP-LABEL: define internal void @__dtor() +// CHECK-NEXT: entry: +// CHECK-NEXT: call i32 @atexit(ptr @"??__Ft2@@YAXXZ.1") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define internal void @"??__Ft2@@YAXXZ.1"() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @"??1Test1@@QEAA@XZ"(ptr @"?t2@@3UTest1@@A") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-OMP-LABEL: define internal void @__ctor.1() +// CHECK-OMP-NEXT: entry: +// CHECK-OMP-NEXT: ret void +// CHECK-OMP-NEXT: } + +// CHECK-OMP-LABEL: define internal void @__dtor.2() +// CHECK-OMP: entry: +// CHECK-OMP-NEXT: call i32 @__cxa_thread_atexit(ptr @_ZN5Test2D1Ev, ptr @t, ptr @__dso_handle) #1 +// CHECK-OMP-NEXT: ret void +// CHECK-OMP-NEXT: } + +// CHECK-OMP-LABEL: define internal void @__ctor.3() +// CHECK-OMP: entry: +// CHECK-OMP-NEXT: ret void +// CHECK-OMP-NEXT: } + +// CHECK-OMP-LABEL: define internal void @__dtor.4() #0 { +// CHECK-OMP-NEXT: entry: +// CHECK-OMP-NEXT: call i32 @__cxa_atexit(ptr @_ZN5Test3D1Ev, ptr @t3, ptr @__dso_handle) +// CHECK-OMP-NEXT: ret void +// CHECK-OMP-NEXT: } + +// CHECK-LABEL: define internal void @__ctor.2() +// CHECK-NEXT: entry: +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define internal void @__dtor.3() +// CHECK-NEXT: entry: +// CHECK-NEXT: call i32 @__tlregdtor(ptr @"??__Ft@@YAXXZ") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define internal void @"??__Ft@@YAXXZ"() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @"??1Test2@@QEAA@XZ"(ptr @"?t@@3UTest2@@A") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define internal void @__ctor.4() +// CHECK-NEXT: entry: +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define internal void @__dtor.5() +// CHECK-NEXT: entry: +// CHECK-NEXT: call i32 @atexit(ptr @"??__Ft3@@YAXXZ") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define internal void @"??__Ft3@@YAXXZ"() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @"??1Test3@@QEAA@XZ"(ptr @"?t3@@3UTest3@@A") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define dso_local void @"?G@@YAXXZ"() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @"?F@@YAXAEBH@Z"(ptr noundef nonnull align 4 dereferenceable(4) @"?bar@Test3@@2HB") +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define internal void @__tls_init() +// CHECK-OMP-LABEL: define internal void @__tls_init() +// CHECK-OMP: call void @__ctor.1() +// CHECK-OMP: call void @__dtor.2() +// CHECK: entry: +// CHECK-NEXT: call void @__ctor.2() +// CHECK-NEXT: call void @__dtor.3() +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +struct Test1 { + constexpr Test1(int) {} + ~Test1() {} +}; +inline constinit Test1 t2 = 2; + + +struct Test2 { + constexpr Test2() {}; + ~Test2() {}; +}; +thread_local constinit Test2 t; + +#pragma omp declare target +struct Test3 { + constexpr Test3(int) {} + static constexpr int bar = 1; + ~Test3() {} +}; + +Test3 t3 = 2; + +void F(const int &); +void G() { F(t3.bar); } + +constexpr int Test3::bar; +#pragma omp end declare target Index: clang/test/CodeGenCXX/ctor-dtor-alias.cpp =================================================================== --- clang/test/CodeGenCXX/ctor-dtor-alias.cpp +++ clang/test/CodeGenCXX/ctor-dtor-alias.cpp @@ -54,7 +54,7 @@ // test that instead of an internal alias we just use the other destructor // directly. -// CHECK1: define internal void @__cxx_global_var_init.1() +// CHECK1: define internal void @__dtor() // CHECK1: call i32 @__cxa_atexit{{.*}}_ZN5test312_GLOBAL__N_11AD2Ev // CHECK1: define internal void @_ZN5test312_GLOBAL__N_11AD2Ev( namespace { @@ -73,13 +73,13 @@ // guarantee that they will be present in every TU. Instead, we just call // A's destructor directly. - // CHECK1: define internal void @__cxx_global_var_init.2() + // CHECK1: define internal void @__dtor.2() // CHECK1: call i32 @__cxa_atexit{{.*}}_ZN5test41AD2Ev // CHECK1: define linkonce_odr void @_ZN5test41AD2Ev({{.*}} comdat align // test that we don't do this optimization at -O0 so that the debugger can // see both destructors. - // NOOPT: define internal void @__cxx_global_var_init.2() + // NOOPT: define internal void @__dtor.2() // NOOPT: call i32 @__cxa_atexit{{.*}}@_ZN5test41BD2Ev // NOOPT: define linkonce_odr void @_ZN5test41BD2Ev({{.*}} comdat align struct A { @@ -94,8 +94,8 @@ namespace test5 { // similar to test4, but with an internal B. - // CHECK2: define internal void @__cxx_global_var_init.3() - // CHECK2: call i32 @__cxa_atexit{{.*}}_ZN5test51AD2Ev + // CHECK2: define internal void @__dtor.4() + // CHECK2: call i32 @__cxa_atexit{{.*}}_ZN5test51XE // CHECK2: define linkonce_odr void @_ZN5test51AD2Ev({{.*}} comdat align struct A { virtual ~A() {} @@ -120,8 +120,8 @@ }; } B X; - // CHECK3: define internal void @__cxx_global_var_init.4() - // CHECK3: call i32 @__cxa_atexit({{.*}}@_ZN5test61AD2Ev + // CHECK3: define internal void @__dtor.6() + // CHECK3: call i32 @__cxa_atexit({{.*}}@_ZN5test61XE } namespace test7 { @@ -142,8 +142,8 @@ namespace test8 { // Test that we replace ~zed with ~bar which is an alias to ~foo. // CHECK4: @_ZN5test83barD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN5test83fooD2Ev - // CHECK4: define internal void @__cxx_global_var_init.5() - // CHECK4: call i32 @__cxa_atexit({{.*}}@_ZN5test83barD2Ev + // CHECK4: define internal void @__dtor.8() + // CHECK4: call i32 @__cxa_atexit({{.*}}@_ZN5test83fooE struct foo { ~foo(); }; Index: clang/test/CodeGenCXX/cxx11-thread-local.cpp =================================================================== --- clang/test/CodeGenCXX/cxx11-thread-local.cpp +++ clang/test/CodeGenCXX/cxx11-thread-local.cpp @@ -199,8 +199,8 @@ // CHECK: store i32 %{{.*}}, i32* [[VFM_ADDR]], align 4 // CHECK: br label -// LINUX_AIX: define internal void @[[XF_M_INIT]]() -// DARWIN: define internal cxx_fast_tlscc void @[[XF_M_INIT]]() +// LINUX_AIX: define internal void @__ctor() +// DARWIN: define internal void @__ctor() // CHECK-NOT: comdat // CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIfE1mE to i8*) // CHECK: %[[XF_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0 Index: clang/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp =================================================================== --- clang/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp +++ clang/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp @@ -28,13 +28,13 @@ // CHECK: @_ZN8Constant2d2E ={{.*}} global { i32, i8, i8 } { i32 1, i8 2, i8 3 }, align 4 // CHECK: @_ZN8Constant2d3E ={{.*}} global { i32, i8, i8 } { i32 1, i8 0, i8 0 }, align 4 - // CHECK-LABEL: define {{.*}}global_var_init + // CHECK-LABEL: define {{.*}}__dtor() // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN8Constant1DD1Ev {{.*}} @_ZN8Constant2d1E - // CHECK-LABEL: define {{.*}}global_var_init + // CHECK-LABEL: define {{.*}}__dtor.2() // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN8Constant1DD1Ev {{.*}} @_ZN8Constant2d2E - // CHECK-LABEL: define {{.*}}global_var_init + // CHECK-LABEL: define {{.*}}__dtor.4() // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN8Constant1DD1Ev {{.*}} @_ZN8Constant2d3E } Index: clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp =================================================================== --- clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp +++ clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp @@ -85,7 +85,7 @@ // CHECK: } int get_e() { return e.n; } -// CHECK: define {{.*}}[[E2_INIT:@__cxx_global_var_init[^(]*]]( +// CHECK: define {{.*}}[[E2_INIT:@__dtor[^(]*]]( // LINUX: call {{.*}} @__cxa_thread_atexit({{.*}} @_ZN10DestructedD1Ev {{.*}} @e2 // DARWIN: call {{.*}} @_tlv_atexit({{.*}} @_ZN10DestructedD1Ev {{.*}} @e2 thread_local constinit Destructed e2; Index: clang/test/CodeGenCXX/dllimport.cpp =================================================================== --- clang/test/CodeGenCXX/dllimport.cpp +++ clang/test/CodeGenCXX/dllimport.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -no-enable-noundef-analysis -triple i686-windows-msvc -fno-rtti -fno-threadsafe-statics -fms-extensions -emit-llvm -std=c++1y -O0 -o - %s -DMSABI -w | FileCheck --check-prefix=MSC --check-prefix=M32 %s -// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-windows-msvc -fno-rtti -fno-threadsafe-statics -fms-extensions -emit-llvm -std=c++1y -O0 -o - %s -DMSABI -w | FileCheck --check-prefix=MSC --check-prefix=M64 %s +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple i686-windows-msvc -fno-rtti -fno-threadsafe-statics -fms-extensions -emit-llvm -std=c++1y -O0 -o - %s -DMSABI -w | FileCheck --check-prefix=MSC --check-prefix=M32 --check-prefix=GL32 %s +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-windows-msvc -fno-rtti -fno-threadsafe-statics -fms-extensions -emit-llvm -std=c++1y -O0 -o - %s -DMSABI -w | FileCheck --check-prefix=MSC --check-prefix=M64 --check-prefix=GL64 %s // RUN: %clang_cc1 -no-enable-noundef-analysis -triple i686-windows-gnu -fno-rtti -fno-threadsafe-statics -fms-extensions -emit-llvm -std=c++1y -O0 -o - %s -w | FileCheck --check-prefix=GNU --check-prefix=G32 %s // RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-windows-gnu -fno-rtti -fno-threadsafe-statics -fms-extensions -emit-llvm -std=c++1y -O0 -o - %s -w | FileCheck --check-prefix=GNU %s // RUN: %clang_cc1 -no-enable-noundef-analysis -triple i686-windows-msvc -fno-rtti -fno-threadsafe-statics -fms-extensions -fms-compatibility-version=18.00 -emit-llvm -std=c++1y -O1 -disable-llvm-passes -o - %s -DMSABI -w | FileCheck --check-prefix=MO1 --check-prefix=M18 %s @@ -737,8 +737,6 @@ namespace PR19933 { // Don't dynamically initialize dllimport vars. -// MSC2-NOT: @llvm.global_ctors -// GNU2-NOT: @llvm.global_ctors struct NonPOD { NonPOD(); }; template struct A { static NonPOD x; }; @@ -856,6 +854,12 @@ USEMEMFUNC(PR23770BaseTemplate, f); // M32-DAG: declare dllimport x86_thiscallcc void @"?f@?$PR23770BaseTemplate@H@@QAEXXZ" +// MSC-DAG: @"?val@@3HA" = external dllimport global i32 +// GL32-DAG: @"?x@@3PAHA" = dso_local global ptr null +// GL64-DAG: @"?x@@3PEAHEA" = dso_local global ptr null +// MSC-DAG: @"?impx@@3HA" = external dllimport global i32 +// MSC-DAG: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 201, ptr @__ctor, ptr null }, { i32, ptr, ptr } { i32 201, ptr @__ctor.1, ptr null }] + namespace PR27810 { template struct basic_ostream { @@ -1026,3 +1030,19 @@ void baz() { U u; u.foo(); } // No diagnostic. } + +void assigndllimporttoconst () { + // MSC-DAG: define dso_local void @"?assigndllimporttoconst@@YAXXZ"() + // MSC-DAG: %[[VAL_REF:.*]] = alloca ptr + // MSC-DAG-NEXT: store ptr @"?val@@3HA", ptr %[[VAL_REF]] + extern int _declspec(dllimport) val; + constexpr int& val_ref = val; +} + +_declspec(dllimport) int impx; +constexpr int *y = &impx; +int *x = &impx; + +__declspec(dllimport) extern int impextx; +inline int *inly = &impextx; +int **z = &inly; Index: clang/test/CodeGenCXX/dso-handle-custom.cpp =================================================================== --- clang/test/CodeGenCXX/dso-handle-custom.cpp +++ clang/test/CodeGenCXX/dso-handle-custom.cpp @@ -8,7 +8,7 @@ // CHECK-DEFAULT: @__dso_handle = global ptr @__dso_handle, align 8 // CHECK-HIDDEN: @__dso_handle = hidden global ptr @__dso_handle, align 8 -// CHECK: define internal void @__cxx_global_var_init() +// CHECK: define internal void @__dtor() // CHECK: call i32 @__cxa_atexit({{.*}}, {{.*}}, ptr @__dso_handle) #ifdef HIDDEN Index: clang/test/CodeGenCXX/funcattrs-global-ctor-dtor.cpp =================================================================== --- clang/test/CodeGenCXX/funcattrs-global-ctor-dtor.cpp +++ clang/test/CodeGenCXX/funcattrs-global-ctor-dtor.cpp @@ -7,6 +7,6 @@ A g; -// CHECK: define internal void @__cxx_global_var_init() [[ATTR0:#[0-9]+]] -// CHECK: define internal void @_GLOBAL__sub_I_funcattrs_global_ctor_dtor.cpp() [[ATTR0]] +// CHECK: define internal void @__ctor() [[ATTR0:#[0-9]+]] +// CHECK: define internal void @__dtor() [[ATTR0]] // CHECK: attributes [[ATTR0]] = {{{.*}} sspstrong {{.*}}} Index: clang/test/CodeGenCXX/no_destroy.cpp =================================================================== --- clang/test/CodeGenCXX/no_destroy.cpp +++ clang/test/CodeGenCXX/no_destroy.cpp @@ -35,10 +35,11 @@ [[clang::no_destroy]] thread_local NonTrivial2 nt22; } -// CHECK-LABEL: define internal void @__cxx_global_var_init +// CHECK-LABEL: define internal void @__ctor.3() +// CHECK-LABEL: define internal void @__dtor.4() // CHECK: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev [[clang::always_destroy]] NonTrivial nt3; -// CHECK-LABEL: define internal void @__cxx_global_var_init +// CHECK-LABEL: define internal void @__dtor.6() // CHECK: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev [[clang::always_destroy]] thread_local NonTrivial nt4; Index: clang/test/CodeGenCXX/non-const-init-cxx2a.cpp =================================================================== --- clang/test/CodeGenCXX/non-const-init-cxx2a.cpp +++ clang/test/CodeGenCXX/non-const-init-cxx2a.cpp @@ -15,5 +15,5 @@ // CHECK: @b ={{.*}} global {{.*}} i32 123 B b = B(); -// CHECK: define {{.*}}cxx_global_var_init +// CHECK: define {{.*}}__ctor() // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN1BD1Ev, {{.*}} @b Index: clang/test/CodeGenCXX/static-destructor.cpp =================================================================== --- clang/test/CodeGenCXX/static-destructor.cpp +++ clang/test/CodeGenCXX/static-destructor.cpp @@ -16,17 +16,17 @@ Foo global; // X86 destructors have void return, and are registered directly with __cxa_atexit. -// X86: define internal void @__cxx_global_var_init() +// X86: define internal void @__dtor() // X86: call i32 @__cxa_atexit(ptr @_ZN3FooD1Ev, ptr @global, ptr @__dso_handle) // ARM destructors return this, but can be registered directly with __cxa_atexit // because the calling conventions tolerate the mismatch. -// ARM: define internal void @__cxx_global_var_init() +// ARM: define internal void @__dtor() // ARM: call i32 @__cxa_atexit(ptr @_ZN3FooD1Ev, ptr @global, ptr @__dso_handle) // Wasm destructors return this, and use a wrapper function, which is registered // with __cxa_atexit. -// WASM: define internal void @__cxx_global_var_init() +// WASM: define internal void @__dtor() // WASM: call i32 @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr null, ptr @__dso_handle) // WASM: define internal void @__cxx_global_array_dtor(ptr noundef %0) Index: clang/test/CodeGenOpenCLCXX/atexit.clcpp =================================================================== --- clang/test/CodeGenOpenCLCXX/atexit.clcpp +++ clang/test/CodeGenOpenCLCXX/atexit.clcpp @@ -5,7 +5,7 @@ }; S s; -//CHECK-LABEL: define internal spir_func void @__cxx_global_var_init() +//CHECK-LABEL: define internal spir_func void @__ctor() //CHECK: call spir_func i32 @__cxa_atexit(ptr @_ZNU3AS41SD1Ev, ptr null, ptr addrspace(1) @__dso_handle) //CHECK: declare spir_func i32 @__cxa_atexit(ptr, ptr, ptr addrspace(1)) Index: clang/test/SemaCXX/PR19955.cpp =================================================================== --- clang/test/SemaCXX/PR19955.cpp +++ clang/test/SemaCXX/PR19955.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple i686-mingw32 -verify -std=c++11 %s extern int __attribute__((dllimport)) var; -constexpr int *varp = &var; // expected-error {{must be initialized by a constant expression}} +constexpr int *varp = &var; extern __attribute__((dllimport)) void fun(); constexpr void (*funp)(void) = &fun; // expected-error {{must be initialized by a constant expression}} Index: clang/test/SemaCXX/constant-expression-cxx11.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx11.cpp +++ clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1596,7 +1596,7 @@ void f(int k) { // expected-note {{here}} int arr[k]; // expected-warning {{C99}} expected-note {{function parameter 'k'}} constexpr int n = 1 + - sizeof(arr) // expected-error {{constant expression}} + sizeof(arr) // expected-error{{constexpr variable 'n' must be initialized by a constant expression}} * 3; } } Index: clang/test/SemaCXX/dllimport-constexpr.cpp =================================================================== --- clang/test/SemaCXX/dllimport-constexpr.cpp +++ clang/test/SemaCXX/dllimport-constexpr.cpp @@ -40,7 +40,6 @@ // constexpr initialization doesn't work for dllimport things. // expected-error@+1{{must be initialized by a constant expression}} constexpr void (*constexpr_import_func)() = &imported_func; -// expected-error@+1{{must be initialized by a constant expression}} constexpr int *constexpr_import_int = &imported_int; // expected-error@+1{{must be initialized by a constant expression}} constexpr void (Foo::*constexpr_memptr)() = &Foo::imported_method; @@ -60,3 +59,11 @@ // expected-note@+1 {{requested here}} StaticConstexpr::g_fp(); } + +extern int __declspec(dllimport) val; +constexpr int& val_ref = val; + +void assigndllimporttoconst () { + extern int _declspec(dllimport) val; + constexpr int& val_ref = val; +}