https://github.com/glebov-andrey updated https://github.com/llvm/llvm-project/pull/114075
>From 22f29b48173c3eb4495d498334e56aaf9abb5a34 Mon Sep 17 00:00:00 2001 From: Andrey Glebov <andrey458641...@gmail.com> Date: Mon, 28 Oct 2024 00:02:51 +0300 Subject: [PATCH 1/4] [clang] MicrosoftCXXABI: restore the RecordToCopyCtor table when loading AST (#53486) - Includes a regression test for the issue --- .../clang/AST/CXXRecordDeclDefinitionBits.def | 5 +++++ clang/include/clang/AST/DeclCXX.h | 8 ++++++++ clang/lib/AST/DeclCXX.cpp | 7 ++++--- clang/lib/Sema/SemaExprCXX.cpp | 4 ++++ clang/lib/Serialization/ASTReaderDecl.cpp | 14 ++++++++++++++ .../PCH/cxx-exception-copy-ctor-crash.cpp | 19 +++++++++++++++++++ .../test/PCH/cxx-exception-copy-ctor-crash.h | 14 ++++++++++++++ 7 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 clang/test/PCH/cxx-exception-copy-ctor-crash.cpp create mode 100644 clang/test/PCH/cxx-exception-copy-ctor-crash.h diff --git a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def index 6620840df0ced2..7560691a0e4172 100644 --- a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def +++ b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def @@ -249,6 +249,11 @@ FIELD(HasDeclaredCopyAssignmentWithConstParam, 1, MERGE_OR) /// base classes or fields have a no-return destructor FIELD(IsAnyDestructorNoReturn, 1, NO_MERGE) +/// Microsoft CXX ABI specific: +/// Whether the copy constructor is used by a `throw` expression. +/// Used by ASTReader to restore the sidecar RecordToCopyCtor LUT. +FIELD(HasCopyConstructorForExceptionObject, 1, MERGE_OR) + /// Whether the record type is intangible (if any base classes or fields have /// type that is intangible). HLSL only. FIELD(IsHLSLIntangible, 1, NO_MERGE) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 79fd403c2718c8..b6e541272dcfda 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1558,6 +1558,14 @@ class CXXRecordDecl : public RecordDecl { /// a field or in base class. bool isHLSLIntangible() const { return data().IsHLSLIntangible; } + bool hasCopyConstructorForExceptionObject() const { + return data().HasCopyConstructorForExceptionObject; + } + + void setHasCopyConstructorForExceptionObject() { + data().HasCopyConstructorForExceptionObject = true; + } + /// If the class is a local class [class.local], returns /// the enclosing function declaration. const FunctionDecl *isLocalClass() const { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index a023a9f456a0e4..e868ae0d950b88 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -109,9 +109,10 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), HasDeclaredCopyAssignmentWithConstParam(false), - IsAnyDestructorNoReturn(false), IsHLSLIntangible(false), IsLambda(false), - IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false), - HasODRHash(false), Definition(D) {} + IsAnyDestructorNoReturn(false), + HasCopyConstructorForExceptionObject(false), IsHLSLIntangible(false), + IsLambda(false), IsParsingBaseSpecifiers(false), + ComputedVisibleConversions(false), HasODRHash(false), Definition(D) {} CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { return Bases.get(Definition->getASTContext().getExternalSource()); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 1e39d69e8b230f..8f6b760ad2842c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1082,6 +1082,10 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, // friendship or any other means). Context.addCopyConstructorForExceptionObject(Subobject, CD); + // Store the bit in CXXRecordDecl so that ASTReader can restore this + // mapping later. + Subobject->setHasCopyConstructorForExceptionObject(); + // We don't keep the instantiated default argument expressions around so // we must rebuild them here. for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 8210eb2143acf5..263da41b2b2d56 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2331,6 +2331,20 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { } VisitCXXMethodDecl(D); + + // Microsoft CXX ABI specific: + // Restore the RecordToCopyCtor sidecar LUT entry so that `throw` expressions + // find the correct copy constructor for exceptions during codegen. + // There is no need to check the target info because the + // HasCopyConstructorForExceptionObject bit only gets set for the MS ABI. + if (D->isCopyConstructor()) { + // TODO What if this is not the same copy constructor which was chosen by + // LookupCopyingConstructor() in SemaExprCXX? Is there a better way? + auto *R = cast<CXXRecordDecl>(D->getDeclContext()); + if (R->hasCopyConstructorForExceptionObject()) { + Reader.getContext().addCopyConstructorForExceptionObject(R, D); + } + } } void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { diff --git a/clang/test/PCH/cxx-exception-copy-ctor-crash.cpp b/clang/test/PCH/cxx-exception-copy-ctor-crash.cpp new file mode 100644 index 00000000000000..29bcb114f20f0a --- /dev/null +++ b/clang/test/PCH/cxx-exception-copy-ctor-crash.cpp @@ -0,0 +1,19 @@ +// REQUIRES: system-windows, target={{.*-windows-msvc}} +// RUN: %clang_cc1 -x c++ -std=c++17 -fcxx-exceptions -fexceptions -triple=%ms_abi_triple -emit-pch -building-pch-with-obj -fmodules-codegen -o %t.pch %S/cxx-exception-copy-ctor-crash.h +// RUN: %clang_cc1 -x c++ -std=c++17 -fcxx-exceptions -fexceptions -triple=%ms_abi_triple -include-pch %t.pch -emit-obj -building-pch-with-obj -fmodules-codegen -o %t.pch.obj +// RUN: %clang_cc1 -x c++ -std=c++17 -fcxx-exceptions -fexceptions -triple=%ms_abi_triple -include-pch %t.pch -emit-obj -o %t.obj %s +// RUN: lld-link -subsystem:console -out:%t.exe %t.pch.obj %t.obj libucrt.lib libvcruntime.lib libcmt.lib +// RUN: %t.exe + +// Regression test for https://github.com/llvm/llvm-project/issues/53486 + +int main() { + try { + throw Exception(); + } catch (const Exception ex) { // catch by value to trigger copy constructor + } + if (ctor_count != dtor_count) { + return 1; + } + return 0; +} diff --git a/clang/test/PCH/cxx-exception-copy-ctor-crash.h b/clang/test/PCH/cxx-exception-copy-ctor-crash.h new file mode 100644 index 00000000000000..9645df56c786e3 --- /dev/null +++ b/clang/test/PCH/cxx-exception-copy-ctor-crash.h @@ -0,0 +1,14 @@ +// Header for PCH test cxx-exception-copy-ctor-crash.cpp + +inline int ctor_count = 0; +inline int dtor_count = 0; + +struct Exception { + Exception() { ++ctor_count; } + ~Exception() { ++dtor_count; } + Exception(const Exception &) noexcept { ++ctor_count; } +}; + +inline void throw_exception() { + throw Exception(); +} >From aa7190c8d7cbbd10122d5f4184b08d97be209526 Mon Sep 17 00:00:00 2001 From: Andrey Glebov <andrey458641...@gmail.com> Date: Tue, 28 Jan 2025 01:34:15 +0300 Subject: [PATCH 2/4] [clang] [WIP] MicrosoftCXXABI: save and load the RecordToCopyCtor table (#53486) - Replaces the previous attempt at restoring the table - The implementation is currently broken --- clang/include/clang/AST/ASTContext.h | 3 +++ .../clang/AST/CXXRecordDeclDefinitionBits.def | 5 ---- clang/include/clang/AST/DeclCXX.h | 8 ------- clang/include/clang/Sema/ExternalSemaSource.h | 3 +++ .../clang/Sema/MultiplexExternalSemaSource.h | 4 ++++ clang/include/clang/Sema/Sema.h | 2 ++ .../include/clang/Serialization/ASTBitCodes.h | 2 ++ clang/include/clang/Serialization/ASTReader.h | 10 ++++++++ clang/lib/AST/ASTContext.cpp | 5 ++++ clang/lib/AST/CXXABI.h | 3 +++ clang/lib/AST/DeclCXX.cpp | 7 +++--- clang/lib/AST/ItaniumCXXABI.cpp | 5 ++++ clang/lib/AST/MicrosoftCXXABI.cpp | 5 ++++ .../lib/Sema/MultiplexExternalSemaSource.cpp | 6 +++++ clang/lib/Sema/Sema.cpp | 2 ++ clang/lib/Sema/SemaDeclCXX.cpp | 13 +++++++++++ clang/lib/Sema/SemaExprCXX.cpp | 4 ---- clang/lib/Serialization/ASTReader.cpp | 23 +++++++++++++++++++ clang/lib/Serialization/ASTReaderDecl.cpp | 14 ----------- clang/lib/Serialization/ASTWriter.cpp | 13 +++++++++++ 20 files changed, 102 insertions(+), 35 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 65be782c1ba43e..6c244dbb1d7f4a 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -3289,6 +3289,9 @@ class ASTContext : public RefCountedBase<ASTContext> { const FunctionDecl *FD, llvm::function_ref<void(FunctionDecl *)> Pred) const; + const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * + getRecordToCopyCtor() const; + const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD); diff --git a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def index 7560691a0e4172..6620840df0ced2 100644 --- a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def +++ b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def @@ -249,11 +249,6 @@ FIELD(HasDeclaredCopyAssignmentWithConstParam, 1, MERGE_OR) /// base classes or fields have a no-return destructor FIELD(IsAnyDestructorNoReturn, 1, NO_MERGE) -/// Microsoft CXX ABI specific: -/// Whether the copy constructor is used by a `throw` expression. -/// Used by ASTReader to restore the sidecar RecordToCopyCtor LUT. -FIELD(HasCopyConstructorForExceptionObject, 1, MERGE_OR) - /// Whether the record type is intangible (if any base classes or fields have /// type that is intangible). HLSL only. FIELD(IsHLSLIntangible, 1, NO_MERGE) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index b6e541272dcfda..79fd403c2718c8 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1558,14 +1558,6 @@ class CXXRecordDecl : public RecordDecl { /// a field or in base class. bool isHLSLIntangible() const { return data().IsHLSLIntangible; } - bool hasCopyConstructorForExceptionObject() const { - return data().HasCopyConstructorForExceptionObject; - } - - void setHasCopyConstructorForExceptionObject() { - data().HasCopyConstructorForExceptionObject = true; - } - /// If the class is a local class [class.local], returns /// the enclosing function declaration. const FunctionDecl *isLocalClass() const { diff --git a/clang/include/clang/Sema/ExternalSemaSource.h b/clang/include/clang/Sema/ExternalSemaSource.h index 11cd69df88d1c1..f44c361862e97b 100644 --- a/clang/include/clang/Sema/ExternalSemaSource.h +++ b/clang/include/clang/Sema/ExternalSemaSource.h @@ -200,6 +200,9 @@ class ExternalSemaSource : public ExternalASTSource { virtual void ReadDeclsToCheckForDeferredDiags(llvm::SmallSetVector<Decl *, 4> &Decls) {} + virtual void ReadRecordExceptionCopyingConstructors( + llvm::MapVector<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) {} + /// \copydoc Sema::CorrectTypo /// \note LookupKind must correspond to a valid Sema::LookupNameKind /// diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 921bebe3a44af5..60d56682881286 100644 --- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -345,6 +345,10 @@ class MultiplexExternalSemaSource : public ExternalSemaSource { void ReadDeclsToCheckForDeferredDiags( llvm::SmallSetVector<Decl *, 4> &Decls) override; + void ReadRecordExceptionCopyingConstructors( + llvm::MapVector<CXXRecordDecl *, + CXXConstructorDecl *> &RecordToCtor) override; + /// \copydoc ExternalSemaSource::CorrectTypo /// \note Returns the first nonempty correction. TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d0fc735be5f763..ca1ad76cf0fb09 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5428,6 +5428,8 @@ class Sema final : public SemaBase { /// \returns true if any work was done, false otherwise. bool DefineUsedVTables(); + void LoadExternalRecordToExceptionCopyingCtor(); + /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared /// special functions, such as the default constructor, copy /// constructor, or destructor, to the given C++ class (C++ diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 1b56ed2c9776b5..5951bbad9ec291 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -742,6 +742,8 @@ enum ASTRecordTypes { UPDATE_MODULE_LOCAL_VISIBLE = 76, UPDATE_TU_LOCAL_VISIBLE = 77, + + MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS = 78, }; /// Record types used within a source manager block. diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 47301419c76c68..719156c48bb6b9 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -1044,6 +1044,12 @@ class ASTReader /// The IDs of all decls with function effects to be checked. SmallVector<GlobalDeclID> DeclsWithEffectsToVerify; + struct RecordAndCopyingCtor { + GlobalDeclID RecordID; + GlobalDeclID CtorID; + }; + SmallVector<RecordAndCopyingCtor> RecordToCopyingCtor; + private: struct ImportedSubmodule { serialization::SubmoduleID ID; @@ -2289,6 +2295,10 @@ class ASTReader llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>> &LPTMap) override; + void ReadRecordExceptionCopyingConstructors( + llvm::MapVector<CXXRecordDecl *, + CXXConstructorDecl *> &RecordToCtor) override; + void AssignedLambdaNumbering(CXXRecordDecl *Lambda) override; /// Load a selector from disk, registering its ID if it exists. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cd1bcb3b9a063d..805cb40a3447ce 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -13103,6 +13103,11 @@ ASTContext::createMangleNumberingContext() const { return ABI->createMangleNumberingContext(); } +const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * +ASTContext::getRecordToCopyCtor() const { + return ABI->getRecordToCopyCtor(); +} + const CXXConstructorDecl * ASTContext::getCopyConstructorForExceptionObject(CXXRecordDecl *RD) { return ABI->getCopyConstructorForExceptionObject( diff --git a/clang/lib/AST/CXXABI.h b/clang/lib/AST/CXXABI.h index 9258a53fefebcb..e411714b619aa7 100644 --- a/clang/lib/AST/CXXABI.h +++ b/clang/lib/AST/CXXABI.h @@ -56,6 +56,9 @@ class CXXABI { virtual void addCopyConstructorForExceptionObject(CXXRecordDecl *, CXXConstructorDecl *) = 0; + virtual const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * + getRecordToCopyCtor() const = 0; + /// Retrieves the mapping from class to copy constructor for this C++ ABI. virtual const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index e868ae0d950b88..a023a9f456a0e4 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -109,10 +109,9 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), HasDeclaredCopyAssignmentWithConstParam(false), - IsAnyDestructorNoReturn(false), - HasCopyConstructorForExceptionObject(false), IsHLSLIntangible(false), - IsLambda(false), IsParsingBaseSpecifiers(false), - ComputedVisibleConversions(false), HasODRHash(false), Definition(D) {} + IsAnyDestructorNoReturn(false), IsHLSLIntangible(false), IsLambda(false), + IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false), + HasODRHash(false), Definition(D) {} CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { return Bases.get(Definition->getASTContext().getExternalSource()); diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index a1b2551419f5e6..290fa1e6047ad6 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -256,6 +256,11 @@ class ItaniumCXXABI : public CXXABI { return Layout.getNonVirtualSize() == PointerSize; } + const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * + getRecordToCopyCtor() const override { + return nullptr; + } + const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override { return nullptr; diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index 1c020c3ad4ad55..247a6e5ad9b1eb 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -146,6 +146,11 @@ class MicrosoftCXXABI : public CXXABI { llvm_unreachable("unapplicable to the MS ABI"); } + const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * + getRecordToCopyCtor() const override { + return &RecordToCopyCtor; + } + const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override { return RecordToCopyCtor[RD]; diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 6d945300c386c0..966b9d09f47cb7 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -336,6 +336,12 @@ void MultiplexExternalSemaSource::ReadLateParsedTemplates( Sources[i]->ReadLateParsedTemplates(LPTMap); } +void MultiplexExternalSemaSource::ReadRecordExceptionCopyingConstructors( + llvm::MapVector<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadRecordExceptionCopyingConstructors(RecordToCtor); +} + TypoCorrection MultiplexExternalSemaSource::CorrectTypo( const DeclarationNameInfo &Typo, int LookupKind, Scope *S, CXXScopeSpec *SS, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 9507d7602aa401..f8b1e4a4d385de 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1101,6 +1101,8 @@ void Sema::ActOnStartOfTranslationUnit() { if (getLangOpts().CPlusPlusModules && getLangOpts().getCompilingModule() == LangOptions::CMK_HeaderUnit) HandleStartOfHeaderUnit(); + + LoadExternalRecordToExceptionCopyingCtor(); } void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e4e3bbad1f5205..5e8218bfc75209 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18669,6 +18669,19 @@ bool Sema::DefineUsedVTables() { return DefinedAnything; } +void Sema::LoadExternalRecordToExceptionCopyingCtor() { + if (!ExternalSource) + return; + + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + llvm::MapVector<CXXRecordDecl *, CXXConstructorDecl *> RecordToCtorMap; + ExternalSource->ReadRecordExceptionCopyingConstructors(RecordToCtorMap); + for (const auto &[RD, CD] : RecordToCtorMap) { + Context.addCopyConstructorForExceptionObject(RD, CD); + } + } +} + void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, const CXXRecordDecl *RD) { for (const auto *I : RD->methods()) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 8f6b760ad2842c..1e39d69e8b230f 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1082,10 +1082,6 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, // friendship or any other means). Context.addCopyConstructorForExceptionObject(Subobject, CD); - // Store the bit in CXXRecordDecl so that ASTReader can restore this - // mapping later. - Subobject->setHasCopyConstructorForExceptionObject(); - // We don't keep the instantiated default argument expressions around so // we must rebuild them here. for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f524251c48ddd7..3ca789879bf9b2 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4313,6 +4313,19 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) DeclsToCheckForDeferredDiags.insert(ReadDeclID(F, Record, I)); break; + + case MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS: { + if (Record.size() % 2 != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "Invalid MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS record"); + for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { + RecordToCopyingCtor.push_back( + {ReadDeclID(F, Record, I), + ReadDeclID(F, Record, I)}); + } + break; + } } } } @@ -9372,6 +9385,16 @@ void ASTReader::ReadLateParsedTemplates( LateParsedTemplates.clear(); } +void ASTReader::ReadRecordExceptionCopyingConstructors( + llvm::MapVector<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) { + for (const auto &[RecordID, CtorID] : RecordToCopyingCtor) { + auto *RD = cast<CXXRecordDecl>(GetDecl(RecordID)); + auto *CD = cast<CXXConstructorDecl>(GetDecl(CtorID)); + RecordToCtor.insert({RD, CD}); + } + RecordToCopyingCtor.clear(); +} + void ASTReader::AssignedLambdaNumbering(CXXRecordDecl *Lambda) { if (!Lambda->getLambdaContextDecl()) return; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 263da41b2b2d56..8210eb2143acf5 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2331,20 +2331,6 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { } VisitCXXMethodDecl(D); - - // Microsoft CXX ABI specific: - // Restore the RecordToCopyCtor sidecar LUT entry so that `throw` expressions - // find the correct copy constructor for exceptions during codegen. - // There is no need to check the target info because the - // HasCopyConstructorForExceptionObject bit only gets set for the MS ABI. - if (D->isCopyConstructor()) { - // TODO What if this is not the same copy constructor which was chosen by - // LookupCopyingConstructor() in SemaExprCXX? Is there a better way? - auto *R = cast<CXXRecordDecl>(D->getDeclContext()); - if (R->hasCopyConstructorForExceptionObject()) { - Reader.getContext().addCopyConstructorForExceptionObject(R, D); - } - } } void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 2d0fae8b64d074..0d78d3f7e312bb 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5847,6 +5847,19 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) { if (!VTablesToEmit.empty()) Stream.EmitRecord(VTABLES_TO_EMIT, VTablesToEmit); + + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + RecordData ExceptionCopyingConstructors; + const auto *RecordToCopyCtor = Context.getRecordToCopyCtor(); + assert(RecordToCopyCtor); + for (const auto [RD, CD] : *RecordToCopyCtor) { + AddDeclRef(RD, ExceptionCopyingConstructors); + AddDeclRef(CD, ExceptionCopyingConstructors); + } + if (!ExceptionCopyingConstructors.empty()) + Stream.EmitRecord(MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS, + ExceptionCopyingConstructors); + } } ASTFileSignature ASTWriter::WriteASTCore(Sema *SemaPtr, StringRef isysroot, >From 8355d2e001e428042cb9368832c0317b483c04fb Mon Sep 17 00:00:00 2001 From: Andrey Glebov <andrey458641...@gmail.com> Date: Thu, 30 Jan 2025 00:15:08 +0300 Subject: [PATCH 3/4] [clang] [WIP] MicrosoftCXXABI: move loading RecordToCopyCtor table from Sema to AST (#53486) --- clang/include/clang/AST/ASTContext.h | 6 ++-- clang/include/clang/AST/ExternalASTSource.h | 3 ++ clang/include/clang/Sema/ExternalSemaSource.h | 3 -- .../clang/Sema/MultiplexExternalSemaSource.h | 8 ++--- clang/include/clang/Sema/Sema.h | 2 -- clang/include/clang/Serialization/ASTReader.h | 8 ++--- clang/lib/AST/ASTContext.cpp | 13 +++++++-- clang/lib/AST/CXXABI.h | 4 +-- clang/lib/AST/ExternalASTSource.cpp | 3 ++ clang/lib/AST/ItaniumCXXABI.cpp | 4 +-- clang/lib/AST/MicrosoftCXXABI.cpp | 4 +-- .../lib/Sema/MultiplexExternalSemaSource.cpp | 12 ++++---- clang/lib/Sema/Sema.cpp | 2 -- clang/lib/Sema/SemaDeclCXX.cpp | 13 --------- clang/lib/Serialization/ASTReader.cpp | 29 +++++++++---------- 15 files changed, 54 insertions(+), 60 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 6c244dbb1d7f4a..fd16cd83c956c2 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -667,6 +667,8 @@ class ASTContext : public RefCountedBase<ASTContext> { /// For performance, track whether any function effects are in use. mutable bool AnyFunctionEffects = false; + bool ExternalCopyConstructorsForExceptionObjectsLoaded = false; + const TargetInfo *Target = nullptr; const TargetInfo *AuxTarget = nullptr; clang::PrintingPolicy PrintingPolicy; @@ -3289,8 +3291,8 @@ class ASTContext : public RefCountedBase<ASTContext> { const FunctionDecl *FD, llvm::function_ref<void(FunctionDecl *)> Pred) const; - const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * - getRecordToCopyCtor() const; + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * + getRecordToCopyCtor(); const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD); diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 42aed56d42e076..ba83e5d2cffc16 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -175,6 +175,9 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> { LoadExternalSpecializations(const Decl *D, ArrayRef<TemplateArgument> TemplateArgs); + virtual void LoadExternalExceptionCopyingConstructors( + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor); + /// Ensures that the table of all visible declarations inside this /// context is up to date. /// diff --git a/clang/include/clang/Sema/ExternalSemaSource.h b/clang/include/clang/Sema/ExternalSemaSource.h index f44c361862e97b..11cd69df88d1c1 100644 --- a/clang/include/clang/Sema/ExternalSemaSource.h +++ b/clang/include/clang/Sema/ExternalSemaSource.h @@ -200,9 +200,6 @@ class ExternalSemaSource : public ExternalASTSource { virtual void ReadDeclsToCheckForDeferredDiags(llvm::SmallSetVector<Decl *, 4> &Decls) {} - virtual void ReadRecordExceptionCopyingConstructors( - llvm::MapVector<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) {} - /// \copydoc Sema::CorrectTypo /// \note LookupKind must correspond to a valid Sema::LookupNameKind /// diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 60d56682881286..d1341c523bdc4e 100644 --- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -104,6 +104,10 @@ class MultiplexExternalSemaSource : public ExternalSemaSource { LoadExternalSpecializations(const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) override; + void LoadExternalExceptionCopyingConstructors( + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) + override; + /// Ensures that the table of all visible declarations inside this /// context is up to date. void completeVisibleDeclsMap(const DeclContext *DC) override; @@ -345,10 +349,6 @@ class MultiplexExternalSemaSource : public ExternalSemaSource { void ReadDeclsToCheckForDeferredDiags( llvm::SmallSetVector<Decl *, 4> &Decls) override; - void ReadRecordExceptionCopyingConstructors( - llvm::MapVector<CXXRecordDecl *, - CXXConstructorDecl *> &RecordToCtor) override; - /// \copydoc ExternalSemaSource::CorrectTypo /// \note Returns the first nonempty correction. TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ca1ad76cf0fb09..d0fc735be5f763 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5428,8 +5428,6 @@ class Sema final : public SemaBase { /// \returns true if any work was done, false otherwise. bool DefineUsedVTables(); - void LoadExternalRecordToExceptionCopyingCtor(); - /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared /// special functions, such as the default constructor, copy /// constructor, or destructor, to the given C++ class (C++ diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 719156c48bb6b9..c10a3a54c3d07c 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -2165,6 +2165,10 @@ class ASTReader LoadExternalSpecializations(const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) override; + void LoadExternalExceptionCopyingConstructors( + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) + override; + /// Finds all the visible declarations with a given name. /// The current implementation of this method just loads the entire /// lookup table as unmaterialized references. @@ -2295,10 +2299,6 @@ class ASTReader llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>> &LPTMap) override; - void ReadRecordExceptionCopyingConstructors( - llvm::MapVector<CXXRecordDecl *, - CXXConstructorDecl *> &RecordToCtor) override; - void AssignedLambdaNumbering(CXXRecordDecl *Lambda) override; /// Load a selector from disk, registering its ID if it exists. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 805cb40a3447ce..bc8cdfa2b95817 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -13103,13 +13103,22 @@ ASTContext::createMangleNumberingContext() const { return ABI->createMangleNumberingContext(); } -const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * -ASTContext::getRecordToCopyCtor() const { +llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * +ASTContext::getRecordToCopyCtor() { return ABI->getRecordToCopyCtor(); } const CXXConstructorDecl * ASTContext::getCopyConstructorForExceptionObject(CXXRecordDecl *RD) { + if (!getTargetInfo().getCXXABI().isMicrosoft()) { + return nullptr; + } + if (ExternalSource && !ExternalCopyConstructorsForExceptionObjectsLoaded) { + auto *Map = ABI->getRecordToCopyCtor(); + assert(Map); + ExternalSource->LoadExternalExceptionCopyingConstructors(*Map); + ExternalCopyConstructorsForExceptionObjectsLoaded = true; + } return ABI->getCopyConstructorForExceptionObject( cast<CXXRecordDecl>(RD->getFirstDecl())); } diff --git a/clang/lib/AST/CXXABI.h b/clang/lib/AST/CXXABI.h index e411714b619aa7..612c9779346bdb 100644 --- a/clang/lib/AST/CXXABI.h +++ b/clang/lib/AST/CXXABI.h @@ -56,8 +56,8 @@ class CXXABI { virtual void addCopyConstructorForExceptionObject(CXXRecordDecl *, CXXConstructorDecl *) = 0; - virtual const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * - getRecordToCopyCtor() const = 0; + virtual llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * + getRecordToCopyCtor() = 0; /// Retrieves the mapping from class to copy constructor for this C++ ABI. virtual const CXXConstructorDecl * diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index e2451f294741d3..f262529c990a15 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -105,6 +105,9 @@ bool ExternalASTSource::LoadExternalSpecializations( return false; } +void ExternalASTSource::LoadExternalExceptionCopyingConstructors( + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> &) {} + void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {} void ExternalASTSource::FindExternalLexicalDecls( diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index 290fa1e6047ad6..f0e1e9317d8382 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -256,8 +256,8 @@ class ItaniumCXXABI : public CXXABI { return Layout.getNonVirtualSize() == PointerSize; } - const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * - getRecordToCopyCtor() const override { + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * + getRecordToCopyCtor() override { return nullptr; } diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index 247a6e5ad9b1eb..472ca10054b4cf 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -146,8 +146,8 @@ class MicrosoftCXXABI : public CXXABI { llvm_unreachable("unapplicable to the MS ABI"); } - const llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * - getRecordToCopyCtor() const override { + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * + getRecordToCopyCtor() override { return &RecordToCopyCtor; } diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 966b9d09f47cb7..3ec2226d2977e1 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -134,6 +134,12 @@ bool MultiplexExternalSemaSource::LoadExternalSpecializations( return AnyNewSpecsLoaded; } +void MultiplexExternalSemaSource::LoadExternalExceptionCopyingConstructors( + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->LoadExternalExceptionCopyingConstructors(RecordToCtor); +} + void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){ for(size_t i = 0; i < Sources.size(); ++i) Sources[i]->completeVisibleDeclsMap(DC); @@ -336,12 +342,6 @@ void MultiplexExternalSemaSource::ReadLateParsedTemplates( Sources[i]->ReadLateParsedTemplates(LPTMap); } -void MultiplexExternalSemaSource::ReadRecordExceptionCopyingConstructors( - llvm::MapVector<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) { - for (size_t i = 0; i < Sources.size(); ++i) - Sources[i]->ReadRecordExceptionCopyingConstructors(RecordToCtor); -} - TypoCorrection MultiplexExternalSemaSource::CorrectTypo( const DeclarationNameInfo &Typo, int LookupKind, Scope *S, CXXScopeSpec *SS, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index f8b1e4a4d385de..9507d7602aa401 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1101,8 +1101,6 @@ void Sema::ActOnStartOfTranslationUnit() { if (getLangOpts().CPlusPlusModules && getLangOpts().getCompilingModule() == LangOptions::CMK_HeaderUnit) HandleStartOfHeaderUnit(); - - LoadExternalRecordToExceptionCopyingCtor(); } void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5e8218bfc75209..e4e3bbad1f5205 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18669,19 +18669,6 @@ bool Sema::DefineUsedVTables() { return DefinedAnything; } -void Sema::LoadExternalRecordToExceptionCopyingCtor() { - if (!ExternalSource) - return; - - if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { - llvm::MapVector<CXXRecordDecl *, CXXConstructorDecl *> RecordToCtorMap; - ExternalSource->ReadRecordExceptionCopyingConstructors(RecordToCtorMap); - for (const auto &[RD, CD] : RecordToCtorMap) { - Context.addCopyConstructorForExceptionObject(RD, CD); - } - } -} - void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, const CXXRecordDecl *RD) { for (const auto *I : RD->methods()) diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 3ca789879bf9b2..b05251a22023dd 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4314,19 +4314,16 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, DeclsToCheckForDeferredDiags.insert(ReadDeclID(F, Record, I)); break; - case MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS: { + case MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS: if (Record.size() % 2 != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "Invalid MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS record"); - for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { + for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) RecordToCopyingCtor.push_back( - {ReadDeclID(F, Record, I), - ReadDeclID(F, Record, I)}); - } + {ReadDeclID(F, Record, I), ReadDeclID(F, Record, I)}); break; } - } } } @@ -8365,6 +8362,16 @@ bool ASTReader::LoadExternalSpecializations( return NewDeclsFound; } +void ASTReader::LoadExternalExceptionCopyingConstructors( + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) { + for (const auto &[RecordID, CtorID] : RecordToCopyingCtor) { + auto *RD = cast<CXXRecordDecl>(GetDecl(RecordID)); + auto *CD = cast<CXXConstructorDecl>(GetDecl(CtorID)); + RecordToCtor.insert({RD, CD}); + } + RecordToCopyingCtor.clear(); +} + void ASTReader::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, SmallVectorImpl<Decl *> &Decls) { @@ -9385,16 +9392,6 @@ void ASTReader::ReadLateParsedTemplates( LateParsedTemplates.clear(); } -void ASTReader::ReadRecordExceptionCopyingConstructors( - llvm::MapVector<CXXRecordDecl *, CXXConstructorDecl *> &RecordToCtor) { - for (const auto &[RecordID, CtorID] : RecordToCopyingCtor) { - auto *RD = cast<CXXRecordDecl>(GetDecl(RecordID)); - auto *CD = cast<CXXConstructorDecl>(GetDecl(CtorID)); - RecordToCtor.insert({RD, CD}); - } - RecordToCopyingCtor.clear(); -} - void ASTReader::AssignedLambdaNumbering(CXXRecordDecl *Lambda) { if (!Lambda->getLambdaContextDecl()) return; >From e90bab70c86706454925da13cff0cc746afe7367 Mon Sep 17 00:00:00 2001 From: Andrey Glebov <andrey458641...@gmail.com> Date: Thu, 30 Jan 2025 01:41:28 +0300 Subject: [PATCH 4/4] [clang] [WIP] MicrosoftCXXABI: Fix crashes when CXXABI is nullptr (#53486) --- clang/lib/AST/ASTContext.cpp | 5 ++++- clang/lib/Serialization/ASTWriter.cpp | 17 +++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index bc8cdfa2b95817..16c0220c78bc82 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -13105,7 +13105,10 @@ ASTContext::createMangleNumberingContext() const { llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> * ASTContext::getRecordToCopyCtor() { - return ABI->getRecordToCopyCtor(); + if (ABI) { // TODO Why can this be null? + return ABI->getRecordToCopyCtor(); + } + return nullptr; } const CXXConstructorDecl * diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 0d78d3f7e312bb..c5c82dc665301e 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5849,16 +5849,17 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) { Stream.EmitRecord(VTABLES_TO_EMIT, VTablesToEmit); if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { - RecordData ExceptionCopyingConstructors; const auto *RecordToCopyCtor = Context.getRecordToCopyCtor(); - assert(RecordToCopyCtor); - for (const auto [RD, CD] : *RecordToCopyCtor) { - AddDeclRef(RD, ExceptionCopyingConstructors); - AddDeclRef(CD, ExceptionCopyingConstructors); + if (RecordToCopyCtor) { + RecordData ExceptionCopyingConstructors; + for (const auto [RD, CD] : *RecordToCopyCtor) { + AddDeclRef(RD, ExceptionCopyingConstructors); + AddDeclRef(CD, ExceptionCopyingConstructors); + } + if (!ExceptionCopyingConstructors.empty()) + Stream.EmitRecord(MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS, + ExceptionCopyingConstructors); } - if (!ExceptionCopyingConstructors.empty()) - Stream.EmitRecord(MSCXXABI_EXCEPTION_COPYING_CONSTRUCTORS, - ExceptionCopyingConstructors); } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits