[PATCH] D137107: Allow MS extension: support of constexpr with __declspec(dllimport).

Zahira Ammarguellat via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 31 12:49:39 PDT 2022


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 at 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 at 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 at 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 at +1{{must be initialized by a constant expression}}
 constexpr void (*constexpr_import_func)() = &imported_func;
-// expected-error at +1{{must be initialized by a constant expression}}
 constexpr int *constexpr_import_int = &imported_int;
 // expected-error at +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 at 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 at 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 &&


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D137107.472107.patch
Type: text/x-patch
Size: 4185 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20221031/e169b403/attachment.bin>


More information about the cfe-commits mailing list