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 @@ -2228,11 +2228,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 @@ -504,6 +504,21 @@ PtrArray->setComdat(C); } +void CodeGenModule::EmitCXXCtorInit(const VarDecl *D, llvm::GlobalVariable *Addr, + bool PerformInit, int Priority, + llvm::StringLiteral FuncName) { + 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); + AddGlobalCtor(Fn, Priority); +} + void CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, llvm::GlobalVariable *Addr, Index: clang/lib/CodeGen/CGExprConstant.cpp =================================================================== --- clang/lib/CodeGen/CGExprConstant.cpp +++ clang/lib/CodeGen/CGExprConstant.cpp @@ -1920,8 +1920,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/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -1623,6 +1623,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); 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 @@ -4839,6 +4839,9 @@ // also don't need to register a destructor. if (getLangOpts().CPlusPlus && !NeedsGlobalDtor) DelayedCXXInitPosition.erase(D); + if (getLangOpts().CPlusPlus && D->hasConstantInitialization() && + NeedsGlobalDtor && D->getType()->isRecordType()) + NeedsGlobalCtor = true; #ifndef NDEBUG CharUnits VarSize = getContext().getTypeSizeInChars(ASTTy) + @@ -4992,9 +4995,15 @@ maybeSetTrivialComdat(*D, *GV); // Emit the initializer function if necessary. - if (NeedsGlobalCtor || NeedsGlobalDtor) - EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); + if (D->hasConstantInitialization() && D->getType()->isRecordType()) { + EmitCXXCtorInit(D, GV, true, 201, llvm::StringLiteral("ctor")); + EmitCXXCtorInit(D, GV, false, 65535, llvm::StringLiteral("dtor")); + 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/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 @_GLOBAL__I_000201, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_dllimport.cpp, ptr null }] + namespace PR27810 { template struct basic_ostream { @@ -1026,3 +1030,15 @@ 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; 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 @@ -1595,7 +1595,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; +}