zahiraam created this revision. zahiraam added reviewers: majnemer, rnk. Herald added a project: All. zahiraam requested review of this revision. Herald added a project: clang.
Microsoft allows the support of ‘constexpr’ with ‘__declspec(dllimport) starting from VS2017 15.u update 4. See Constexpr doesn't support __declspec(dllimport) in VS2017 15.8 - Visual Studio Feedback. Let’s consider this example. lib.cpp: __declspec(dllexport) int val=12; __declspec(dllexport) int next(int n) { return n + 1; } app1.cpp: #include <iostream> extern int __declspec(dllimport) next(int n); int main () { extern int __declspec(dllimport) val; constexpr int& val_ref = val; int i = next(val_ref); std::cout << "i: " << i << std::endl; return i; } Compiling this will give the expected output. $ cl /LD lib.cpp $ cl /EHsc app1.cpp /link lib.lib $ ./app1.exe i: 13 The Intel compiler has the same behavior than MSVC. Clang compiles this test case with this error: error: constexpr variable 'val_ref' must be initialized by a constant expression constexpr int& val_ref = val; ^ ~~~ 1 error generated. I think this should be fixed. This patch is doing that. Now let’s look now at this example (dllimport at TU scope level): app2.cpp: #include <iostream> extern int __declspec(dllimport) next(int n); extern int __declspec(dllimport) val; constexpr int& val_ref = val; int main () { int i = next(val_ref); std::cout << "i: " << i << std::endl; return i; } Compiling this will result into an unresolved symbol: $ cl /EHsc app2.cpp /link lib.lib app2.obj : error LNK2001: unresolved external symbol "int val" (?val@@3HA) app2.exe : fatal error LNK1120: 1 unresolved externals ICL and clang generate the same error. These are the symols generated for all 3 compilers: ICL: 003 00000000 UNDEF notype External | __imp_?next@@YAHH@Z (__declspec(dllimport) int __cdecl next(int)) 004 00000000 UNDEF notype External | __imp_?val@@3HA (__declspec(dllimport) int val) 00C 00000000 SECT4 notype External | ?val_ref@@3AEAHEA (int & val_ref) 00D 00000000 UNDEF notype External | ?val@@3HA (int val) MSVC: 00A 00000000 UNDEF notype External | __imp_?next@@YAHH@Z (__declspec(dllimport) int __cdecl next(int)) 015 00000000 SECT6 notype Static | ?val_ref@@3AEAHEA (int & val_ref) The symbols generated by ICL seem to be what's expected. MSVC should be generating an "__imp_?val" symbol. Clang with the change in this patch is generating the expected symbols: 010 00000000 UNDEF notype External | __imp_?val@@3HA (__declspec(dllimport) int val) 011 00000000 UNDEF notype External | __imp_?next@@YAHH@Z (__declspec(dllimport) int __cdecl next(int)) 012 00000000 SECT5 notype External | ?val_ref@@3AEAHEA (int & val_ref) 013 00000000 UNDEF notype External | ?val@@3HA (int val) Fixes issue https://github.com/llvm/llvm-project/issues/53182 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D137107 Files: clang/lib/AST/ExprConstant.cpp clang/test/CodeGenCXX/PR19955.cpp clang/test/CodeGenCXX/dllimport.cpp clang/test/SemaCXX/PR19955.cpp clang/test/SemaCXX/dllimport-constexpr.cpp 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; 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/CodeGenCXX/dllimport.cpp =================================================================== --- clang/test/CodeGenCXX/dllimport.cpp +++ clang/test/CodeGenCXX/dllimport.cpp @@ -97,9 +97,9 @@ }; USE(inlineStaticLocalsFunc); -// The address of a dllimport global cannot be used in constant initialization. -// M32-DAG: @"?arr@?1??initializationFunc@@YAPAHXZ@4QBQAHB" = internal global [1 x ptr] zeroinitializer -// GNU-DAG: @_ZZ18initializationFuncvE3arr = internal global [1 x ptr] zeroinitializer +// The address of a dllimport global can be used in constant initialization. +// M32-DAG: @"?arr@?1??initializationFunc@@YAPAHXZ@4QBQAHB" = internal constant [1 x ptr] [ptr @"?ExternGlobalDecl@@3HA"] +// GNU-DAG: @_ZZ18initializationFuncvE3arr = internal constant [1 x ptr] [ptr @ExternGlobalDecl] int *initializationFunc() { static int *const arr[] = {&ExternGlobalDecl}; return arr[0]; Index: clang/test/CodeGenCXX/PR19955.cpp =================================================================== --- clang/test/CodeGenCXX/PR19955.cpp +++ clang/test/CodeGenCXX/PR19955.cpp @@ -6,20 +6,15 @@ 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-DAG: @"?var@@3HA" = external dllimport global i32 +// CHECK-DAG: @"?varp@@3PAHA" = dso_local global ptr @"?var@@3HA" + 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" - -// X64-LABEL: @"??__Evarp@@YAXXZ" -// X64-DAG: store ptr @"?var@@3HA", ptr @"?varp@@3PEAHEA" - // CHECK-LABEL: @"??__Efunp@@YAXXZ"() // CHECK-DAG: store ptr @"?fun@@YAXXZ", ptr @"?funp@@3P6AXXZA" Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -2228,12 +2228,16 @@ // 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<DLLImportAttr>()) + if (!isForManglingOnly(Kind) && Var->hasAttr<DLLImportAttr>()) { // FIXME: Diagnostic! - return false; - + if (Info.getLangOpts().C99) + // Address of dllimport variables can't be used for initialization in + // C language modes. + return false; + // A dllimport variable can be a constant address. This is a MS + // extension. + return true; + } // In CUDA/HIP device compilation, only device side variables have // constant addresses. if (Info.getCtx().getLangOpts().CUDA &&
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; 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/CodeGenCXX/dllimport.cpp =================================================================== --- clang/test/CodeGenCXX/dllimport.cpp +++ clang/test/CodeGenCXX/dllimport.cpp @@ -97,9 +97,9 @@ }; USE(inlineStaticLocalsFunc); -// The address of a dllimport global cannot be used in constant initialization. -// M32-DAG: @"?arr@?1??initializationFunc@@YAPAHXZ@4QBQAHB" = internal global [1 x ptr] zeroinitializer -// GNU-DAG: @_ZZ18initializationFuncvE3arr = internal global [1 x ptr] zeroinitializer +// The address of a dllimport global can be used in constant initialization. +// M32-DAG: @"?arr@?1??initializationFunc@@YAPAHXZ@4QBQAHB" = internal constant [1 x ptr] [ptr @"?ExternGlobalDecl@@3HA"] +// GNU-DAG: @_ZZ18initializationFuncvE3arr = internal constant [1 x ptr] [ptr @ExternGlobalDecl] int *initializationFunc() { static int *const arr[] = {&ExternGlobalDecl}; return arr[0]; Index: clang/test/CodeGenCXX/PR19955.cpp =================================================================== --- clang/test/CodeGenCXX/PR19955.cpp +++ clang/test/CodeGenCXX/PR19955.cpp @@ -6,20 +6,15 @@ 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-DAG: @"?var@@3HA" = external dllimport global i32 +// CHECK-DAG: @"?varp@@3PAHA" = dso_local global ptr @"?var@@3HA" + 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" - -// X64-LABEL: @"??__Evarp@@YAXXZ" -// X64-DAG: store ptr @"?var@@3HA", ptr @"?varp@@3PEAHEA" - // CHECK-LABEL: @"??__Efunp@@YAXXZ"() // CHECK-DAG: store ptr @"?fun@@YAXXZ", ptr @"?funp@@3P6AXXZA" Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -2228,12 +2228,16 @@ // 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<DLLImportAttr>()) + if (!isForManglingOnly(Kind) && Var->hasAttr<DLLImportAttr>()) { // FIXME: Diagnostic! - return false; - + if (Info.getLangOpts().C99) + // Address of dllimport variables can't be used for initialization in + // C language modes. + return false; + // A dllimport variable can be a constant address. This is a MS + // extension. + return true; + } // In CUDA/HIP device compilation, only device side variables have // constant addresses. if (Info.getCtx().getLangOpts().CUDA &&
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits