[PATCH] Fix asserts about emitting constexpr methods twice during dllexport explicit instantiation (PR21718)

Hans Wennborg hans at chromium.org
Mon Dec 15 19:09:18 PST 2014


Hi rsmith, majnemer,

During explicit instantiation of dllexport class templates, we would end up trying to emit constexpr methods (at least) twice:

1. MarkFunctionReferenced would cause it to be emitted, and
2. InstantiateClassMembers would then emit it again
(3. if we had gotten this far, we'd then call HandleTopLevelDecl on it, which would be the third emission attempt)

This patch tries to fix the problem. I'm not sure it's the right fix - it really feels like an odd work-around - but it's the best I've come up with so far. Comments most welcome!

http://reviews.llvm.org/D6674

Files:
  lib/Sema/SemaDeclCXX.cpp
  test/CodeGenCXX/dllexport.cpp

Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -4747,6 +4747,15 @@
     }
 
     if (MD && ClassExported) {
+      // Instantiations of constexpr template member functions are eagerly
+      // emitted by MarkFunctionReferenced, and also emitted by
+      // InstantiateClassMembers. To avoid emitting the function twice, pass
+      // OdrUse = false to MarkFunctionReferenced and don't pass them to the
+      // consumer (PR21718).
+      bool OdrUse = !MD->isConstexpr() ||
+                    TSK != TSK_ExplicitInstantiationDefinition ||
+                    !MD->getInstantiatedFromMemberFunction();
+
       if (MD->isUserProvided()) {
         // Instantiate non-default class member functions ...
 
@@ -4756,7 +4765,7 @@
         if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited())
           continue;
 
-        S.MarkFunctionReferenced(Class->getLocation(), MD);
+        S.MarkFunctionReferenced(Class->getLocation(), MD, OdrUse);
 
         // The function will be passed to the consumer when its definition is
         // encountered.
@@ -4767,11 +4776,12 @@
         // defaulted methods, and the copy and move assignment operators. The
         // latter are exported even if they are trivial, because the address of
         // an operator can be taken and should compare equal accross libraries.
-        S.MarkFunctionReferenced(Class->getLocation(), MD);
+        S.MarkFunctionReferenced(Class->getLocation(), MD, OdrUse);
 
         // There is no later point when we will see the definition of this
         // function, so pass it to the consumer now.
-        S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD));
+        if (OdrUse)
+          S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD));
       }
     }
   }
Index: test/CodeGenCXX/dllexport.cpp
===================================================================
--- test/CodeGenCXX/dllexport.cpp
+++ test/CodeGenCXX/dllexport.cpp
@@ -615,6 +615,21 @@
 struct __declspec(dllexport) ExportedDerivedClass : NonExportedBaseClass {};
 // M32-DAG: weak_odr dllexport x86_thiscallcc void @"\01??1ExportedDerivedClass@@UAE at XZ"
 
+// Do not assert about generating code for constexpr functions twice during explicit instantiation (PR21718).
+template <typename T> struct ExplicitInstConstexprMembers {
+  // Copy assignment operator
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable(1) %struct.ExplicitInstConstexprMembers* @"\01??4?$ExplicitInstConstexprMembers at X@@QAEAAU0 at ABU0@@Z"
+
+  constexpr ExplicitInstConstexprMembers() {}
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstConstexprMembers* @"\01??0?$ExplicitInstConstexprMembers at X@@QAE at XZ"
+
+  ExplicitInstConstexprMembers(const ExplicitInstConstexprMembers&) = default;
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstConstexprMembers* @"\01??0?$ExplicitInstConstexprMembers at X@@QAE at ABU0@@Z"
+
+  constexpr int f() const { return 42; }
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc i32 @"\01?f@?$ExplicitInstConstexprMembers at X@@QBEHXZ"
+};
+template struct __declspec(dllexport) ExplicitInstConstexprMembers<void>;
 
 //===----------------------------------------------------------------------===//
 // Classes with template base classes

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D6674.17318.patch
Type: text/x-patch
Size: 3387 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141216/3a2ad356/attachment.bin>


More information about the cfe-commits mailing list