From b9d36540a85b859ff1189c6c2c3acbc59033ae49 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 5 Nov 2020 13:44:50 +0100 Subject: [PATCH] [dllexport] Avoid assert for explicitly defaulted methods in explicit instantiation definitions (PR47683) Clang was asserting due to attempting to codegen such methods twice. Differential revision: https://reviews.llvm.org/D90849 --- clang/lib/Sema/SemaDeclCXX.cpp | 19 ++++++++++++++----- clang/test/CodeGenCXX/dllexport.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ebda013..c49e9ca 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5895,13 +5895,22 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { // 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 index 3371db3..f8dc2ab 100644 --- a/clang/test/CodeGenCXX/dllexport.cpp +++ b/clang/test/CodeGenCXX/dllexport.cpp @@ -915,6 +915,36 @@ template<> template<> void ExportedClassTemplate2::baz() {} // 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 //===----------------------------------------------------------------------===// -- 2.7.4