diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -292,6 +292,9 @@ Windows Support ^^^^^^^^^^^^^^^ +- Fixed an assertion failure that occurred due to a failure to propagate + ``MSInheritanceAttr`` attributes to class template instantiations created + for explicit template instantiation declarations. LoongArch Support ^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -10110,6 +10110,17 @@ ClassTemplate, CanonicalConverted, PrevDecl); SetNestedNameSpecifier(*this, Specialization, SS); + // A MSInheritanceAttr attached to the previous declaration must be + // propagated to the new node prior to instantiation. + if (PrevDecl) { + if (const auto *A = PrevDecl->getAttr()) { + auto *Clone = A->clone(getASTContext()); + Clone->setInherited(true); + Specialization->addAttr(Clone); + Consumer.AssignInheritanceModel(Specialization); + } + } + if (!HasNoEffect && !PrevDecl) { // Insert the new specialization. ClassTemplate->AddSpecialization(Specialization, InsertPos); @@ -10226,11 +10237,6 @@ dllExportImportClassTemplateSpecialization(*this, Def); } - if (Def->hasAttr()) { - Specialization->addAttr(Def->getAttr()); - Consumer.AssignInheritanceModel(Specialization); - } - // Set the template specialization kind. Make sure it is set before // instantiating the members which will trigger ASTConsumer callbacks. Specialization->setTemplateSpecializationKind(TSK); diff --git a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp --- a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck -allow-deprecated-dag-overlap %s // RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X64 +// RUN: %clang_cc1 -std=c++17 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X64 // RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify // RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify @@ -934,3 +935,32 @@ void A::printd() { JSMethod(); } // CHECK-LABEL: @"??$JSMethod@VA@PMFInTemplateArgument@@$1?printd@12@AAEHH@Z@PMFInTemplateArgument@@YAXXZ"( } + +namespace MissingMSInheritanceAttr { +// This is a regression test for an assertion failure that occurred when +// compiling for C++17. The issue concerned a failure to propagate a +// MSInheritanceAttr attribute for the explicit template instantiation +// definition prior to it being required to complete the specialization +// definition in order to determine its alignment so as to resolve a +// lookup for a deallocation function for the virtual destructor. +template +class a; +struct b { + typedef void (a::*f)(); + f d; +}; +template +class a { + virtual ~a(); + b e; +}; +extern template class a; +template class a; +#ifdef _WIN64 +static_assert(sizeof(b::d) == 24, ""); +static_assert(sizeof(void (a::*)()) == 24, ""); +#else +static_assert(sizeof(b::d) == 16, ""); +static_assert(sizeof(void (a::*)()) == 16, ""); +#endif +}