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

Dario Domizioli dario.domizioli at gmail.com
Fri Sep 19 09:35:14 PDT 2014


Thanks for the review!

Here's another patch with the comments addressed. It has become tiny! :-)

Having changed TryEmitBaseDestructorAsAlias back to the original
implementation, should I file some bug to keep track of the situation for
the future?

Cheers,
    Dario Domizioli
    SN Systems - Sony Computer Entertainment Group






On 19 September 2014 15:52, Rafael EspĂ­ndola <rafael.espindola at gmail.com>
wrote:

> On 17 September 2014 10:07, Dario Domizioli <dario.domizioli at gmail.com>
> wrote:
> > Hi!
> > Thanks for the quick reply. I'm attaching a new patch which addresses the
> > comments.
> >
> > I have created a new function CodeGenModule::setAliasAttributes() which
> can
> > be invoked by the alias creation functions instead of
> SetCommonAttributes.
> > The new function includes a call to SetCommonAttributes just like its
> > already existing sister setNonAliasAttributes() does.
> >
> > With this patch, the test does cover all the code for the dllexport
> > transferral, and the only thing it does not cover is whether
> > TryEmitDefinitionAsAlias calls the new setAliasAttributes(). The MSVC ABI
> > seems to be generating only one constructor though (at least in the
> simple
> > test), so the problem with aliasing is hidden and I can't really cover
> that
> > line of code.
> >
>
> +  const auto *VD = cast<ValueDecl>(D);
>
> If an unconditional cast is to be made, it is probably better to have
> CodeGenModule::setAliasAttributes take a ValueDecl. By why you need
> the cast? You can call hasAttr on D directly.
>
> +    // The dllexport attribute is always emitted for variables but is
> +    // ignored for not defined functions.
>
> What does it mean to dll export a variable declaration? In any case,
> this function is only called on definitions. It should probably do
> something like
>
>   /// NOTE: This should only be called for definitions.
>   void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV);
>
> and avoid the test.
>
> Another interesting case is
>
> struct A {
>   ~A();
> };
> A::~A() {}
> struct B : public A {
>   ~B();
> };
> B::~B() {}
>
> Compile with "-O1 -disable-llvm-optzns" and you get
>
> @_ZN1BD2Ev = alias bitcast (void (%struct.A*)* @_ZN1AD2Ev to void
> (%struct.B*)*)
>
> but add a  __declspec(dllexport) and we emit a function. It looks like
> the logic for doing so is working around this very bug in a specific
> case! Simply deleting it on top of your patch makes clang produce
>
> @_ZN1BD2Ev = dllexport alias bitcast (void (%struct.A*)* @_ZN1AD2Ev to
> void (%struct.B*)*
>
> Which looks correct.
>
> This last part (alias to a base class destructor) can probably be a
> subsequent patch, but in that case please leave the dead call to
> setAliasAttributes out of the first patch (the one in
> TryEmitBaseDestructorAsAlias).
>
> Thanks,
> Rafael
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140919/26e2d787/attachment.html>
-------------- next part --------------
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp	(revision 218126)
+++ lib/CodeGen/CodeGenModule.cpp	(working copy)
@@ -786,6 +786,17 @@
     addUsedGlobal(GV);
 }
 
+void CodeGenModule::setAliasAttributes(const Decl *D,
+                                       llvm::GlobalValue *GV) {
+  SetCommonAttributes(D, GV);
+
+  // Process the dllexport attribute based on whether the original definition
+  // (not necessarily the aliasee) was exported.
+  if (D->hasAttr<DLLExportAttr>()) {
+    GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+  }
+}
+
 void CodeGenModule::setNonAliasAttributes(const Decl *D,
                                           llvm::GlobalObject *GO) {
   SetCommonAttributes(D, GO);
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h	(revision 218126)
+++ lib/CodeGen/CodeGenModule.h	(working copy)
@@ -1069,6 +1069,12 @@
   /// NOTE: This should only be called for definitions.
   void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV);
 
+  /// Set attributes which must be preserved by an alias. This includes common
+  /// attributes (i.e. it includes a call to SetCommonAttributes).
+  ///
+  /// NOTE: This should only be called for definitions.
+  void setAliasAttributes(const Decl *D, llvm::GlobalValue *GV);
+
   void addReplacement(StringRef Name, llvm::Constant *C);
 private:
 
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp	(revision 218126)
+++ lib/CodeGen/ItaniumCXXABI.cpp	(working copy)
@@ -3068,7 +3068,7 @@
   }
 
   // Finally, set up the alias with its proper name and attributes.
-  CGM.SetCommonAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
+  CGM.setAliasAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
 }
 
 void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
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_cc1 -triple x86_64-windows-gnu -mconstructor-aliases %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