[clang] WIP: [clang] MicrosoftCXXABI: Fix exception copy constructor LUT after loading AST (PR #114075)

Andrey Glebov via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 29 14:42:56 PST 2025


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 <andrey458641387 at 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 <andrey458641387 at 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 <andrey458641387 at 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 <andrey458641387 at 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);
   }
 }
 



More information about the cfe-commits mailing list