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@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@X@@QAEAAU0@ABU0@@Z"
+
+ constexpr ExplicitInstConstexprMembers() {}
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc
%struct.ExplicitInstConstexprMembers*
@"\01??0?$ExplicitInstConstexprMembers@X@@QAE@XZ"
+
+ ExplicitInstConstexprMembers(const ExplicitInstConstexprMembers&) = default;
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc
%struct.ExplicitInstConstexprMembers*
@"\01??0?$ExplicitInstConstexprMembers@X@@QAE@ABU0@@Z"
+
+ constexpr int f() const { return 42; }
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc i32
@"\01?f@?$ExplicitInstConstexprMembers@X@@QBEHXZ"
+};
+template struct __declspec(dllexport) ExplicitInstConstexprMembers<void>;
//===----------------------------------------------------------------------===//
// Classes with template base classes
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
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@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@X@@QAEAAU0@ABU0@@Z"
+
+ constexpr ExplicitInstConstexprMembers() {}
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstConstexprMembers* @"\01??0?$ExplicitInstConstexprMembers@X@@QAE@XZ"
+
+ ExplicitInstConstexprMembers(const ExplicitInstConstexprMembers&) = default;
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstConstexprMembers* @"\01??0?$ExplicitInstConstexprMembers@X@@QAE@ABU0@@Z"
+
+ constexpr int f() const { return 42; }
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc i32 @"\01?f@?$ExplicitInstConstexprMembers@X@@QBEHXZ"
+};
+template struct __declspec(dllexport) ExplicitInstConstexprMembers<void>;
//===----------------------------------------------------------------------===//
// Classes with template base classes
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits