Don't dllexport reference temporaries
authorHans Wennborg <hans@chromium.org>
Fri, 4 Feb 2022 10:11:11 +0000 (11:11 +0100)
committerHans Wennborg <hans@chromium.org>
Fri, 4 Feb 2022 15:31:51 +0000 (16:31 +0100)
Even if the reference itself is dllexport, the temporary should not be.
In fact, we're already giving it internal linkage, so dllexporting it
is not just wasteful, but will fail to link, as in the example below:

  $ cat /tmp/a.cc
  void _DllMainCRTStartup() {}
  const int __declspec(dllexport) &foo = 42;

  $ clang-cl -fuse-ld=lld /tmp/a.cc /Zl /link /dll /out:a.dll
  lld-link: error: <root>: undefined symbol: int const &foo::$RT1

Differential revision: https://reviews.llvm.org/D118980

clang/lib/CodeGen/CodeGenModule.cpp
clang/test/CodeGenCXX/reference-temporary-ms.cpp [new file with mode: 0644]

index 2346176..5ffb954 100644 (file)
@@ -5725,6 +5725,9 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
       /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
   if (emitter) emitter->finalize(GV);
   setGVProperties(GV, VD);
+  if (GV->getDLLStorageClass() == llvm::GlobalVariable::DLLExportStorageClass)
+    // The reference temporary should never be dllexport.
+    GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
   GV->setAlignment(Align.getAsAlign());
   if (supportsCOMDAT() && GV->isWeakForLinker())
     GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
diff --git a/clang/test/CodeGenCXX/reference-temporary-ms.cpp b/clang/test/CodeGenCXX/reference-temporary-ms.cpp
new file mode 100644 (file)
index 0000000..dd12ad8
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s
+
+const int __declspec(dllexport) &Exported = 42;
+
+// The reference temporary shouldn't be dllexport, even if the reference is.
+// CHECK: @"?$RT1@Exported@@3ABHB" = internal constant i32 42
+
+// CHECK: @"?Exported@@3ABHB" = dso_local dllexport constant i32* @"?$RT1@Exported@@3ABHB"