diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5895,13 +5895,22 @@ // The function will be passed to the consumer when its definition is // encountered. - } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() || + } else if (MD->isExplicitlyDefaulted()) { + // Synthesize and instantiate explicitly defaulted methods. + S.MarkFunctionReferenced(Class->getLocation(), MD); + + if (TSK != TSK_ExplicitInstantiationDefinition) { + // Except for explicit instantiation defs, we will not see the + // definition again later, so pass it to the consumer now. + S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); + } + } else if (!MD->isTrivial() || MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) { - // Synthesize and instantiate non-trivial implicit methods, explicitly - // 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 across libraries. + // Synthesize and instantiate non-trivial implicit 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 across libraries. S.MarkFunctionReferenced(Class->getLocation(), MD); // There is no later point when we will see the definition of this diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp --- a/clang/test/CodeGenCXX/dllexport.cpp +++ b/clang/test/CodeGenCXX/dllexport.cpp @@ -915,6 +915,36 @@ // M32-DAG: define dso_local x86_thiscallcc void @"??$baz@H@?$ExportedClassTemplate2@H@pr34849@@QAEXXZ" } +namespace pr47683 { +struct X { X() {} }; + +template struct S { + S() = default; + X x; +}; +template struct __declspec(dllexport) S; +// M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc %"struct.pr47683::S"* @"??0?$S@H@pr47683@@QAE@XZ" + +template struct T { + T() = default; + X x; +}; +extern template struct T; +template struct __declspec(dllexport) T; +// Don't assert about multiple codegen for explicitly defaulted method in explicit instantiation def. +// M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc %"struct.pr47683::T"* @"??0?$T@H@pr47683@@QAE@XZ" + +template struct U { + U(); + X x; +}; +template U::U() = default; +extern template struct U; +template struct __declspec(dllexport) U; +// Same as T, but with out-of-line ctor. +// M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc %"struct.pr47683::U"* @"??0?$U@H@pr47683@@QAE@XZ" +} + //===----------------------------------------------------------------------===// // Classes with template base classes //===----------------------------------------------------------------------===//