[PATCH] Fix ctor/dtor aliases losing 'dllexport'

Dario Domizioli dario.domizioli at gmail.com
Tue Sep 16 10:42:57 PDT 2014


Hello Clang,

I have noticed that when the compiler emits aliases for simple constructors
and destructors it does not transfer the 'dllexport' storage class
attribute to the alias.
Because in the source code there is only "the constructor" and the user
cannot differentiate between the C1 and C2 portions of it, if one portion
is dllexport'ed then the other must be too. At the moment however C1 is
aliased to C2, and the alias does not have 'dllexport'. This can cause link
errors. The same is true for the destructor (and its D1 and D2 portions).

The attached patch fixed the issue, although I am not 100% sure that my
change is in the right place.
Rafael's refactor in r217847 means that the same code has to exist in two
places: TryEmitDefinitionAsAlias() in CGCXX.cpp and
emitConstructorDestructorAlias() in ItaniumCXXABI.cpp.
Maybe there's a better place where to put the change...

Also, my test assumes that C1 is aliased to C2 (and D1 to D2), and I have
checked it's true with the provided triple which exercises the Itanium ABI
code, but I cannot seem to get the "x86_64-windows-msvc" triple to create
aliases for C1 and D1, so I don't have coverage for the code in
TryEmitDefinitionAsAlias.
Can anybody provide advice on that? Or should I just fix the issue in the
Itanium ABI and worry about the msvc ABI later? It would seem a shame not
to fix both cases...

Cheers,
    Dario Domizioli
    SN Systems - Sony Computer Entertainment Group
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140916/c7e13fd9/attachment.html>
-------------- next part --------------
Index: lib/CodeGen/CGCXX.cpp
===================================================================
--- lib/CodeGen/CGCXX.cpp	(revision 217884)
+++ lib/CodeGen/CGCXX.cpp	(working copy)
@@ -190,6 +190,17 @@
     Alias->setName(MangledName);
   }
 
+  // Process the dllexport attribute based on whether the original definition
+  // (not necessarily the aliasee) was exported.
+  const auto *D = cast<ValueDecl>(AliasDecl.getDecl());
+  if (D->hasAttr<DLLExportAttr>()) {
+    const auto *FD = dyn_cast<FunctionDecl>(D);
+    // The dllexport attribute is always emitted for variables but is
+    // ignored for not defined functions.
+    if (!FD || FD->hasBody())
+      Alias->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+  }
+
   // Finally, set up the alias with its proper name and attributes.
   SetCommonAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
 
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp	(revision 217884)
+++ lib/CodeGen/ItaniumCXXABI.cpp	(working copy)
@@ -3063,6 +3063,17 @@
     Alias->setName(MangledName);
   }
 
+  // Process the dllexport attribute based on whether the original definition
+  // (not necessarily the aliasee) was exported.
+  const auto *D = cast<ValueDecl>(AliasDecl.getDecl());
+  if (D->hasAttr<DLLExportAttr>()) {
+    const auto *FD = dyn_cast<FunctionDecl>(D);
+    // The dllexport attribute is always emitted for variables but is
+    // ignored for not defined functions.
+    if (!FD || FD->hasBody())
+      Alias->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+  }
+
   // Finally, set up the alias with its proper name and attributes.
   CGM.SetCommonAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
 }
Index: test/CodeGenCXX/dllexport-alias.cpp
===================================================================
--- test/CodeGenCXX/dllexport-alias.cpp	(revision 0)
+++ test/CodeGenCXX/dllexport-alias.cpp	(working copy)
@@ -0,0 +1,18 @@
+// RUN: %clang -target x86_64-windows-gnu %s -S -emit-llvm -o - | FileCheck %s
+
+// This test assumes that the C1 constructor will be aliased to the C2
+// constructor, and the D1 destructor to the D2. It then checks that the aliases
+// are dllexport'ed.
+
+class __declspec(dllexport) A {
+public:
+    A();
+    ~A();
+};
+
+A::A() {}
+
+A::~A() {}
+
+// CHECK: @_ZN1AC1Ev = dllexport alias void (%class.A*)* @_ZN1AC2Ev
+// CHECK: @_ZN1AD1Ev = dllexport alias void (%class.A*)* @_ZN1AD2Ev


More information about the cfe-commits mailing list