[Lldb-commits] [lldb] [WIP][lldb] Use forward decls with redeclared definitions instead of minimal import for records (PR #95100)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Mon Jun 24 11:33:00 PDT 2024


https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/95100

>From ebaadaf065580eed357c9618e4d740d60ee444cb Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 13 Feb 2024 14:26:11 +0000
Subject: [PATCH 01/14] [lldb][NFC] Add an ImporterBackedASTSource that serves
 as base class for LLDB ExternalASTSources that use the ASTImporter

This gives all ExternalASTSource classes a common base class that allows
other classes (in LLDB's case ClangASTImporter) to invalidate the redeclaration chains
in an ASTContext. The implementation just calls the (private) function to bump the
generation counter which is how we track whether a redeclaration chain is out of date.

This is used in D101950 to let the ClangASTImporter mark redeclaration chains as
out-of-date so that they update themselves via the ExternalASTSource.

Patch itself is NFC as it just changes the inheritance of a bunch of classes and changes
the LLVM RTTI to make sure we can reliably cast to it. Will be merged with its
dependent patch that lets the ClangASTImporter handle redeclaration chains.
---
 .../Plugins/ExpressionParser/Clang/ASTUtils.h |  6 ++-
 .../ExpressionParser/Clang/ClangASTSource.h   |  3 +-
 .../Clang/ClangExternalASTSourceCallbacks.h   |  7 ++-
 .../AppleObjCRuntime/AppleObjCDeclVendor.cpp  |  3 +-
 .../Plugins/TypeSystem/Clang/CMakeLists.txt   |  1 +
 .../Clang/ImporterBackedASTSource.cpp         | 13 ++++++
 .../Clang/ImporterBackedASTSource.h           | 46 +++++++++++++++++++
 7 files changed, 73 insertions(+), 6 deletions(-)
 create mode 100644 lldb/source/Plugins/TypeSystem/Clang/ImporterBackedASTSource.cpp
 create mode 100644 lldb/source/Plugins/TypeSystem/Clang/ImporterBackedASTSource.h

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
index da2b1a15f7461..604821137c447 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
@@ -10,6 +10,8 @@
 #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H
 
 #include "clang/Basic/ASTSourceDescriptor.h"
+#include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
+#include "clang/Basic/Module.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/MultiplexExternalSemaSource.h"
 #include "clang/Sema/Sema.h"
@@ -26,7 +28,7 @@ namespace lldb_private {
 
 /// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take
 /// ownership of the provided source.
-class ExternalASTSourceWrapper : public clang::ExternalSemaSource {
+class ExternalASTSourceWrapper : public ImporterBackedASTSource {
   ExternalASTSource *m_Source;
 
 public:
@@ -246,7 +248,7 @@ class ASTConsumerForwarder : public clang::SemaConsumer {
 /// provide more accurate replies to the requests, but might not be able to
 /// answer all requests. The debug information will be used as a fallback then
 /// to provide information that is not in the C++ module.
-class SemaSourceWithPriorities : public clang::ExternalSemaSource {
+class SemaSourceWithPriorities : public ImporterBackedASTSource {
 
 private:
   /// The sources ordered in decreasing priority.
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
index 83c910477acc8..bca420efebdab 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
@@ -13,6 +13,7 @@
 
 #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
 #include "Plugins/ExpressionParser/Clang/NameSearchContext.h"
+#include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
 #include "lldb/Symbol/CompilerType.h"
 #include "lldb/Target/Target.h"
 #include "clang/AST/ExternalASTSource.h"
@@ -30,7 +31,7 @@ namespace lldb_private {
 /// knows the name it is looking for, but nothing else. The ExternalSemaSource
 /// class provides Decls (VarDecl, FunDecl, TypeDecl) to Clang for these
 /// names, consulting the ClangExpressionDeclMap to do the actual lookups.
-class ClangASTSource : public clang::ExternalASTSource,
+class ClangASTSource : public ImporterBackedASTSource,
                        public ClangASTImporter::MapCompleter {
 public:
   /// Constructor
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
index 6bd18186a567d..7cd54c7c31c8f 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H
 #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H
 
+#include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "clang/Basic/ASTSourceDescriptor.h"
 #include <optional>
@@ -21,13 +22,15 @@ class Module;
 
 namespace lldb_private {
 
-class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource {
+class ClangExternalASTSourceCallbacks : public ImporterBackedASTSource {
   /// LLVM RTTI support.
   static char ID;
 
 public:
   /// LLVM RTTI support.
-  bool isA(const void *ClassID) const override { return ClassID == &ID; }
+  bool isA(const void *ClassID) const override {
+    return ClassID == &ID || ImporterBackedASTSource::isA(ClassID);
+  }
   static bool classof(const clang::ExternalASTSource *s) { return s->isA(&ID); }
 
   ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {}
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
index 6894cdccaf95a..985953d7c7e67 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
@@ -11,6 +11,7 @@
 #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
 #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
@@ -24,7 +25,7 @@
 using namespace lldb_private;
 
 class lldb_private::AppleObjCExternalASTSource
-    : public clang::ExternalASTSource {
+    : public ImporterBackedASTSource {
 public:
   AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor)
       : m_decl_vendor(decl_vendor) {}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt b/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt
index 37a3142da7274..4b33789479478 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt
+++ b/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_lldb_library(lldbPluginTypeSystemClang PLUGIN
+  ImporterBackedASTSource.cpp
   TypeSystemClang.cpp
 
   LINK_LIBS
diff --git a/lldb/source/Plugins/TypeSystem/Clang/ImporterBackedASTSource.cpp b/lldb/source/Plugins/TypeSystem/Clang/ImporterBackedASTSource.cpp
new file mode 100644
index 0000000000000..f9445b4548cc7
--- /dev/null
+++ b/lldb/source/Plugins/TypeSystem/Clang/ImporterBackedASTSource.cpp
@@ -0,0 +1,13 @@
+//===-- ImporterBackedASTSource.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
+
+using namespace lldb_private;
+
+char ImporterBackedASTSource::ID;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/ImporterBackedASTSource.h b/lldb/source/Plugins/TypeSystem/Clang/ImporterBackedASTSource.h
new file mode 100644
index 0000000000000..00d1a578a0596
--- /dev/null
+++ b/lldb/source/Plugins/TypeSystem/Clang/ImporterBackedASTSource.h
@@ -0,0 +1,46 @@
+//===-- ImporterBackedASTSource.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_IMPORTERBACKEDASTSOURCE
+#define LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_IMPORTERBACKEDASTSOURCE
+
+#include "clang/AST/ASTContext.h"
+#include "clang/Sema/ExternalSemaSource.h"
+
+namespace lldb_private {
+
+/// The base class of all ExternalASTSources in LLDB that use the
+/// ClangASTImporter to move declarations from other ASTs to the ASTContext they
+/// are attached to.
+class ImporterBackedASTSource : public clang::ExternalSemaSource {
+  /// LLVM RTTI support.
+  static char ID;
+
+public:
+  /// LLVM RTTI support.
+  bool isA(const void *ClassID) const override {
+    return ClassID == &ID || ExternalSemaSource::isA(ClassID);
+  }
+  static bool classof(const clang::ExternalASTSource *s) { return s->isA(&ID); }
+
+  /// This marks all redeclaration chains in the ASTContext as out-of-date and
+  /// that this ExternalASTSource should be consulted to get the complete
+  /// redeclaration chain.
+  ///
+  /// \see ExternalASTSource::CompleteRedeclChain
+  void MarkRedeclChainsAsOutOfDate(clang::ASTContext &c) {
+    // This invalidates redeclaration chains but also other things such as
+    // identifiers. There isn't a more precise way at the moment that only
+    // affects redecl chains.
+    incrementGeneration(c);
+  }
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_IMPORTERBACKEDASTSOURCE

>From a5d7658f1d56273442d7bd1aeca1394745e3dc75 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 14 Feb 2024 18:47:28 +0000
Subject: [PATCH 02/14] [lldb][ClangASTImporter][NFCI] Implement
 CompleteTagDeclWithOrigin in terms of CompleteTagDecl

---
 .../ExpressionParser/Clang/ClangASTImporter.cpp | 17 ++---------------
 1 file changed, 2 insertions(+), 15 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 44071d1ea71c7..6e7d3906f4867 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -815,21 +815,8 @@ bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
 
 bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl,
                                                  clang::TagDecl *origin_decl) {
-  clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext();
-
-  if (!TypeSystemClang::GetCompleteDecl(origin_ast_ctx, origin_decl))
-    return false;
-
-  ImporterDelegateSP delegate_sp(
-      GetDelegate(&decl->getASTContext(), origin_ast_ctx));
-
-  if (delegate_sp)
-    delegate_sp->ImportDefinitionTo(decl, origin_decl);
-
-  ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
-
-  context_md->setOrigin(decl, DeclOrigin(origin_ast_ctx, origin_decl));
-  return true;
+  SetDeclOrigin(decl, origin_decl);
+  return CompleteTagDecl(decl);
 }
 
 bool ClangASTImporter::CompleteObjCInterfaceDecl(

>From 28ca94b1d0d37522699f2111756ecd195f210d15 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 14 Feb 2024 16:37:55 +0000
Subject: [PATCH 03/14] [lldb][ClangASTImporter][NFC] Factor completion logic
 out of ~CompleteTagDeclsScope

---
 .../Clang/ClangASTImporter.cpp                | 54 ++++++++++---------
 1 file changed, 30 insertions(+), 24 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 6e7d3906f4867..839e264442c62 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -230,6 +230,35 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
   clang::ASTContext *m_src_ctx;
   ClangASTImporter &importer;
 
+  void CompleteDecl(
+      Decl *decl,
+      lldb_private::ClangASTImporter::ASTContextMetadata const &to_context_md) {
+    // The decl that should be completed has to be imported into the target
+    // context from some other context.
+    assert(to_context_md.hasOrigin(decl));
+    // We should only complete decls coming from the source context.
+    assert(to_context_md.getOrigin(decl).ctx == m_src_ctx);
+
+    Decl *original_decl = to_context_md.getOrigin(decl).decl;
+
+    // Complete the decl now.
+    TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
+    if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
+      if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
+        if (original_tag_decl->isCompleteDefinition()) {
+          m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
+          tag_decl->setCompleteDefinition(true);
+        }
+      }
+
+      tag_decl->setHasExternalLexicalStorage(false);
+      tag_decl->setHasExternalVisibleStorage(false);
+    } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
+      container_decl->setHasExternalLexicalStorage(false);
+      container_decl->setHasExternalVisibleStorage(false);
+    }
+  }
+
 public:
   /// Constructs a CompleteTagDeclsScope.
   /// \param importer The ClangASTImporter that we should observe.
@@ -252,30 +281,7 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
       NamedDecl *decl = m_decls_to_complete.pop_back_val();
       m_decls_already_completed.insert(decl);
 
-      // The decl that should be completed has to be imported into the target
-      // context from some other context.
-      assert(to_context_md->hasOrigin(decl));
-      // We should only complete decls coming from the source context.
-      assert(to_context_md->getOrigin(decl).ctx == m_src_ctx);
-
-      Decl *original_decl = to_context_md->getOrigin(decl).decl;
-
-      // Complete the decl now.
-      TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
-      if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
-        if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
-          if (original_tag_decl->isCompleteDefinition()) {
-            m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
-            tag_decl->setCompleteDefinition(true);
-          }
-        }
-
-        tag_decl->setHasExternalLexicalStorage(false);
-        tag_decl->setHasExternalVisibleStorage(false);
-      } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
-        container_decl->setHasExternalLexicalStorage(false);
-        container_decl->setHasExternalVisibleStorage(false);
-      }
+      CompleteDecl(decl, *to_context_md);
 
       to_context_md->removeOrigin(decl);
     }

>From 1c8e6942274aec757dc03a18ce4b412de68537ad Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 14 Feb 2024 17:03:42 +0000
Subject: [PATCH 04/14] [lldb][ClangASTImporter][NFCI] Factor setting external
 storage out of ASTImporterDelegate::Imported

---
 .../ExpressionParser/Clang/ClangASTImporter.cpp | 17 ++++++++++++-----
 .../ExpressionParser/Clang/ClangASTImporter.h   |  2 ++
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 839e264442c62..461eb64819e4c 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -1355,6 +1355,18 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
              from, m_source_ctx, &to->getASTContext());
   }
 
+  if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) {
+    m_main.BuildNamespaceMap(to_namespace_decl);
+    to_namespace_decl->setHasExternalVisibleStorage();
+  }
+
+  MarkDeclImported(from, to);
+}
+
+void ClangASTImporter::ASTImporterDelegate::MarkDeclImported(Decl *from,
+                                                             Decl *to) {
+  Log *log = GetLog(LLDBLog::Expressions);
+
   if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) {
     to_tag_decl->setHasExternalLexicalStorage();
     to_tag_decl->getPrimaryContext()->setMustBuildLookupTable();
@@ -1369,11 +1381,6 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
         (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
   }
 
-  if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) {
-    m_main.BuildNamespaceMap(to_namespace_decl);
-    to_namespace_decl->setHasExternalVisibleStorage();
-  }
-
   if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) {
     to_container_decl->setHasExternalLexicalStorage();
     to_container_decl->setHasExternalVisibleStorage();
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
index bc962e544d2f1..d71615e7d3c31 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
@@ -346,6 +346,8 @@ class ClangASTImporter {
     llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override;
 
   private:
+    void MarkDeclImported(clang::Decl *from, clang::Decl *to);
+
     /// Decls we should ignore when mapping decls back to their original
     /// ASTContext. Used by the CxxModuleHandler to mark declarations that
     /// were created from the 'std' C++ module to prevent that the Importer

>From 3c2ec79b2f589819d98a8a49604d1e0161a81723 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 19 Feb 2024 12:21:04 +0000
Subject: [PATCH 05/14] [lldb][ClangASTImporter][NFC] Move ASTImproterDelegate
 constructor definition into source file

---
 .../Clang/ClangASTImporter.cpp                | 19 +++++++++++++++++++
 .../ExpressionParser/Clang/ClangASTImporter.h | 17 +----------------
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 461eb64819e4c..6b8dc762d448d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -1413,3 +1413,22 @@ clang::Decl *
 ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) {
   return m_main.GetDeclOrigin(To).decl;
 }
+
+ClangASTImporter::ASTImporterDelegate::ASTImporterDelegate(
+    ClangASTImporter &main, clang::ASTContext *target_ctx,
+    clang::ASTContext *source_ctx)
+    : clang::ASTImporter(*target_ctx, main.m_file_manager, *source_ctx,
+                         main.m_file_manager, true /*minimal*/),
+      m_main(main), m_source_ctx(source_ctx) {
+  // Target and source ASTContext shouldn't be identical. Importing AST
+  // nodes within the same AST doesn't make any sense as the whole idea
+  // is to import them to a different AST.
+  lldbassert(target_ctx != source_ctx && "Can't import into itself");
+  // This is always doing a minimal import of any declarations. This means
+  // that there has to be an ExternalASTSource in the target ASTContext
+  // (that should implement the callbacks that complete any declarations
+  // on demand). Without an ExternalASTSource, this ASTImporter will just
+  // do a minimal import and the imported declarations won't be completed.
+  assert(target_ctx->getExternalSource() && "Missing ExternalSource");
+  setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal);
+}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
index d71615e7d3c31..233c0a7d1796a 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
@@ -282,22 +282,7 @@ class ClangASTImporter {
   /// their counterpart from a C++ module.
   struct ASTImporterDelegate : public clang::ASTImporter {
     ASTImporterDelegate(ClangASTImporter &main, clang::ASTContext *target_ctx,
-                        clang::ASTContext *source_ctx)
-        : clang::ASTImporter(*target_ctx, main.m_file_manager, *source_ctx,
-                             main.m_file_manager, true /*minimal*/),
-          m_main(main), m_source_ctx(source_ctx) {
-      // Target and source ASTContext shouldn't be identical. Importing AST
-      // nodes within the same AST doesn't make any sense as the whole idea
-      // is to import them to a different AST.
-      lldbassert(target_ctx != source_ctx && "Can't import into itself");
-      // This is always doing a minimal import of any declarations. This means
-      // that there has to be an ExternalASTSource in the target ASTContext
-      // (that should implement the callbacks that complete any declarations
-      // on demand). Without an ExternalASTSource, this ASTImporter will just
-      // do a minimal import and the imported declarations won't be completed.
-      assert(target_ctx->getExternalSource() && "Missing ExternalSource");
-      setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal);
-    }
+                        clang::ASTContext *source_ctx);
 
     /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate
     /// and deattaches it at the end of the scope. Supports being used multiple

>From 205c0739fb6f0634393c5c60a14c6145b019ee46 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Fri, 16 Feb 2024 12:20:23 +0000
Subject: [PATCH 06/14] [lldb][ClangASTImporter][NFC] Factor out CanImport
 logic

---
 .../Clang/ClangASTImporter.cpp                | 37 ++++++++-----------
 .../ExpressionParser/Clang/ClangASTImporter.h |  2 +
 2 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 6b8dc762d448d..1099b841ec094 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -365,6 +365,16 @@ clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx,
   return result;
 }
 
+bool ClangASTImporter::CanImport(const Decl *d) {
+  if (!d)
+    return false;
+  if (isa<TagDecl>(d))
+    return GetDeclOrigin(d).Valid();
+  if (isa<ObjCInterfaceDecl>(d))
+    return GetDeclOrigin(d).Valid();
+  return false;
+}
+
 bool ClangASTImporter::CanImport(const CompilerType &type) {
   if (!ClangUtil::IsClangType(type))
     return false;
@@ -374,24 +384,10 @@ bool ClangASTImporter::CanImport(const CompilerType &type) {
 
   const clang::Type::TypeClass type_class = qual_type->getTypeClass();
   switch (type_class) {
-  case clang::Type::Record: {
-    const clang::CXXRecordDecl *cxx_record_decl =
-        qual_type->getAsCXXRecordDecl();
-    if (cxx_record_decl) {
-      if (GetDeclOrigin(cxx_record_decl).Valid())
-        return true;
-    }
-  } break;
-
-  case clang::Type::Enum: {
-    clang::EnumDecl *enum_decl =
-        llvm::cast<clang::EnumType>(qual_type)->getDecl();
-    if (enum_decl) {
-      if (GetDeclOrigin(enum_decl).Valid())
-        return true;
-    }
-  } break;
-
+  case clang::Type::Record:
+    return CanImport(qual_type->getAsRecordDecl());
+  case clang::Type::Enum:
+    return CanImport(llvm::cast<clang::EnumType>(qual_type)->getDecl());
   case clang::Type::ObjCObject:
   case clang::Type::ObjCInterface: {
     const clang::ObjCObjectType *objc_class_type =
@@ -401,10 +397,7 @@ bool ClangASTImporter::CanImport(const CompilerType &type) {
           objc_class_type->getInterface();
       // We currently can't complete objective C types through the newly added
       // ASTContext because it only supports TagDecl objects right now...
-      if (class_interface_decl) {
-        if (GetDeclOrigin(class_interface_decl).Valid())
-          return true;
-      }
+      return CanImport(class_interface_decl);
     }
   } break;
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
index 233c0a7d1796a..867d60fcae085 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
@@ -157,6 +157,8 @@ class ClangASTImporter {
   /// \see ClangASTImporter::Import
   bool CanImport(const CompilerType &type);
 
+  bool CanImport(const clang::Decl *d);
+
   /// If the given type was copied from another TypeSystemClang then copy over
   /// all missing information (e.g., the definition of a 'class' type).
   ///

>From cc34b9a371c282a9a9a8b4362138a7550c0c3ded Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 14 Feb 2024 16:01:57 +0000
Subject: [PATCH 07/14] [lldb][ClangASTImporter] Assert that we never overwrite
 a record layout

---
 .../ExpressionParser/Clang/ClangASTImporter.cpp        |  7 ++++++-
 .../Plugins/ExpressionParser/Clang/ClangASTImporter.h  |  2 ++
 .../Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp   | 10 ++++------
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 1099b841ec094..69af8dcef538d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -767,7 +767,6 @@ bool ClangASTImporter::LayoutRecordType(
     field_offsets.swap(pos->second.field_offsets);
     base_offsets.swap(pos->second.base_offsets);
     vbase_offsets.swap(pos->second.vbase_offsets);
-    m_record_decl_to_layout_map.erase(pos);
     return true;
   }
 
@@ -789,9 +788,15 @@ bool ClangASTImporter::LayoutRecordType(
 
 void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl,
                                         const LayoutInfo &layout) {
+  assert(!HasRecordLayout(decl) && "Trying to overwrite layout?");
   m_record_decl_to_layout_map.insert(std::make_pair(decl, layout));
 }
 
+bool ClangASTImporter::HasRecordLayout(const RecordDecl *decl) const {
+  decl = llvm::cast<RecordDecl>(decl->getFirstDecl());
+  return m_record_decl_to_layout_map.count(decl) > 0;
+}
+
 bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
   DeclOrigin decl_origin = GetDeclOrigin(decl);
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
index 867d60fcae085..3b01b4cf813cc 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
@@ -119,6 +119,8 @@ class ClangASTImporter {
   /// \param layout The layout for the record.
   void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout);
 
+  bool HasRecordLayout(const clang::RecordDecl *decl) const;
+
   bool LayoutRecordType(
       const clang::RecordDecl *record_decl, uint64_t &bit_size,
       uint64_t &alignment,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 52f4d765cbbd4..1f9c298dc3243 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2246,8 +2246,9 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
   TypeSystemClang::BuildIndirectFields(clang_type);
   TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
 
-  if (!layout_info.field_offsets.empty() || !layout_info.base_offsets.empty() ||
-      !layout_info.vbase_offsets.empty()) {
+  clang::CXXRecordDecl *record_decl =
+      m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
+  if (record_decl && !GetClangASTImporter().HasRecordLayout(record_decl)) {
     if (type)
       layout_info.bit_size = type->GetByteSize(nullptr).value_or(0) * 8;
     if (layout_info.bit_size == 0)
@@ -2257,10 +2258,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
       layout_info.alignment =
           die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_alignment, 0) * 8;
 
-    clang::CXXRecordDecl *record_decl =
-        m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
-    if (record_decl)
-      GetClangASTImporter().SetRecordLayout(record_decl, layout_info);
+    GetClangASTImporter().SetRecordLayout(record_decl, layout_info);
   }
   // Now parse all contained types inside of the class. We make forward
   // declarations to all classes, but we need the CXXRecordDecl to have decls

>From caa7000ee05e86d061f901135ede41522ce31709 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 13 Feb 2024 14:43:44 +0000
Subject: [PATCH 08/14] [lldb][TypeSystemClang][NFC] Make
 TemplateParamterInfos::pack_name a std::optional

---
 lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index d67b7a4c9fe72..da15fccc62999 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -353,7 +353,7 @@ class TypeSystemClang : public TypeSystem {
     bool IsValid() const {
       // Having a pack name but no packed args doesn't make sense, so mark
       // these template parameters as invalid.
-      if (pack_name && !packed_args)
+      if (HasPackName() && !packed_args)
         return false;
       return args.size() == names.size() &&
              (!packed_args || !packed_args->packed_args);
@@ -394,14 +394,14 @@ class TypeSystemClang : public TypeSystem {
       return packed_args->GetArgs();
     }
 
-    bool HasPackName() const { return pack_name && pack_name[0]; }
+    bool HasPackName() const { return pack_name.has_value(); }
 
     llvm::StringRef GetPackName() const {
       assert(HasPackName());
-      return pack_name;
+      return pack_name.value();
     }
 
-    void SetPackName(char const *name) { pack_name = name; }
+    void SetPackName(char const *name) { pack_name.emplace(name); }
 
     void SetParameterPack(std::unique_ptr<TemplateParameterInfos> args) {
       packed_args = std::move(args);
@@ -413,7 +413,7 @@ class TypeSystemClang : public TypeSystem {
     llvm::SmallVector<const char *, 2> names;
     llvm::SmallVector<clang::TemplateArgument, 2> args;
 
-    const char * pack_name = nullptr;
+    std::optional<std::string> pack_name;
     std::unique_ptr<TemplateParameterInfos> packed_args;
   };
 

>From e7341b6c8e756e9b2b7102aaaa443f069850a189 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 13 Feb 2024 16:18:32 +0000
Subject: [PATCH 09/14] [lldb][TypeSystemClang][NFC] Make
 TemplateParameterInfos copyable

---
 .../TypeSystem/Clang/TypeSystemClang.h        | 21 +++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index da15fccc62999..75c8cceec3aab 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -342,10 +342,27 @@ class TypeSystemClang : public TypeSystem {
       assert(names.size() == args_in.size());
     }
 
-    TemplateParameterInfos(TemplateParameterInfos const &) = delete;
     TemplateParameterInfos(TemplateParameterInfos &&) = delete;
 
-    TemplateParameterInfos &operator=(TemplateParameterInfos const &) = delete;
+    TemplateParameterInfos(const TemplateParameterInfos &o)
+        : names(o.names), args(o.args), pack_name(o.pack_name) {
+      if (o.packed_args)
+        packed_args = std::make_unique<TemplateParameterInfos>(*o.packed_args);
+    }
+
+    TemplateParameterInfos &operator=(const TemplateParameterInfos &o) {
+      auto tmp = TemplateParameterInfos(o);
+      swap(tmp);
+      return *this;
+    }
+
+    void swap(TemplateParameterInfos &other) noexcept {
+      std::swap(names, other.names);
+      std::swap(args, other.args);
+      std::swap(pack_name, other.pack_name);
+      std::swap(packed_args, other.packed_args);
+    }
+
     TemplateParameterInfos &operator=(TemplateParameterInfos &&) = delete;
 
     ~TemplateParameterInfos() = default;

>From 43aabf001c0f760daa46716b93bc60f63b25de78 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 13 Feb 2024 16:38:38 +0000
Subject: [PATCH 10/14] [lldb] Make TypeSystemClang work with redeclarations

This patch is a part of D101950 which makes LLDB use redeclarations in its internal clang ASTs.

This patch does the following:

Add an API that allows redeclaring a declaration inside a TypeSystemClang.
Make the TypeSystemClang APIs work with redeclarations. Mainly making sure we look at redeclarations of DeclContext (see the added calls to getPrimaryContext which for example finds the definition of a class. See also the test for nested types)
Removes code that assumes a 1-1 mapping between Type and Decl (which is no longer true for redeclarations). The biggest offender here are the APIs for creating classes/templates/etc. as they return all CompilerType (which doesn't identify a unique Decl, but only a redeclaration chain).
Removed code that tries to eagerly create types for declarations. Types should be created via GetTypeForDecl so that existing types from forward declarations are reused. Otherwise we end up with
The patch also makes that we store the TemplateParameterInfos for template specializations
in the TypeSystemClang. The only reason for this is that Clang is using a different data
structure for storing this info internally so we can't just reuse the information from the
forward declaration when creating the redeclaration (see CreateRedeclaration). This
can be removed once we updated the DWARF parser and the TypeSystemClang APIs
to accept the information as we can find it in the Clang AST.

This shouldn't affect LLDB's functionality on its own as the DWARF parser currently doesn't
create redeclarations. That's why all the tests are unit tests.

The added logic for looking for the right redeclaration should work as before in ASTs that only
have single-decl redeclaration chains (which is what we currently do).
---
 .../Clang/ClangASTImporter.cpp                |  10 +-
 .../ExpressionParser/Clang/ClangASTImporter.h |   2 +
 .../ExpressionParser/Clang/ClangASTSource.cpp |   5 +-
 .../ExpressionParser/Clang/ClangUtil.cpp      |  11 +
 .../ExpressionParser/Clang/ClangUtil.h        |   9 +
 .../TypeSystem/Clang/TypeSystemClang.cpp      | 183 ++++++++--
 .../TypeSystem/Clang/TypeSystemClang.h        |  55 ++-
 lldb/unittests/CMakeLists.txt                 |   1 +
 lldb/unittests/TypeSystem/CMakeLists.txt      |   1 +
 .../unittests/TypeSystem/Clang/CMakeLists.txt |  14 +
 .../Clang/TestClangRedeclarations.cpp         | 332 ++++++++++++++++++
 11 files changed, 597 insertions(+), 26 deletions(-)
 create mode 100644 lldb/unittests/TypeSystem/CMakeLists.txt
 create mode 100644 lldb/unittests/TypeSystem/Clang/CMakeLists.txt
 create mode 100644 lldb/unittests/TypeSystem/Clang/TestClangRedeclarations.cpp

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 69af8dcef538d..3d3a782d544cc 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -295,6 +295,7 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
     // Filter out decls that we can't complete later.
     if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to))
       return;
+
     RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from);
     // We don't need to complete injected class name decls.
     if (from_record_decl && from_record_decl->isInjectedClassName())
@@ -757,6 +758,9 @@ bool ClangASTImporter::LayoutRecordType(
         &base_offsets,
     llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
         &vbase_offsets) {
+
+  record_decl = llvm::cast<RecordDecl>(record_decl->getFirstDecl());
+
   RecordDeclToLayoutMap::iterator pos =
       m_record_decl_to_layout_map.find(record_decl);
   base_offsets.clear();
@@ -788,6 +792,7 @@ bool ClangASTImporter::LayoutRecordType(
 
 void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl,
                                         const LayoutInfo &layout) {
+  decl = llvm::cast<RecordDecl>(decl->getFirstDecl());
   assert(!HasRecordLayout(decl) && "Trying to overwrite layout?");
   m_record_decl_to_layout_map.insert(std::make_pair(decl, layout));
 }
@@ -819,7 +824,10 @@ bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
 
 bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl,
                                                  clang::TagDecl *origin_decl) {
-  SetDeclOrigin(decl, origin_decl);
+  if (!origin_decl->getDefinition())
+    return false;
+
+  SetDeclOrigin(decl, origin_decl->getFirstDecl());
   return CompleteTagDecl(decl);
 }
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
index 3b01b4cf813cc..7da82d804cd7e 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
@@ -175,6 +175,8 @@ class ClangASTImporter {
 
   bool CompleteTagDecl(clang::TagDecl *decl);
 
+  /// This function assumes origin has been completed (i.e., has a valid
+  /// definition).
   bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin);
 
   bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 1fdd272dcbece..3fb70e7d5c803 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -281,8 +281,11 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) {
   if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) {
     // We couldn't complete the type.  Maybe there's a definition somewhere
     // else that can be completed.
-    if (TagDecl *alternate = FindCompleteType(tag_decl))
+    if (TagDecl *alternate = FindCompleteType(tag_decl)) {
+      assert(alternate->getDefinition() != nullptr &&
+             "Trying to complete a TagDecl from an incomplete origin");
       m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, alternate);
+    }
   }
 
   LLDB_LOG(log, "      [CTD] After:\n{0}", ClangUtil::DumpDecl(tag_decl));
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
index 2e0bb318cb507..025b19be1eaf0 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
@@ -10,6 +10,7 @@
 
 #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "clang/AST/DeclObjC.h"
 
 using namespace clang;
 using namespace lldb_private;
@@ -65,6 +66,16 @@ clang::TagDecl *ClangUtil::GetAsTagDecl(const CompilerType &type) {
   return qual_type->getAsTagDecl();
 }
 
+clang::Decl *ClangUtil::GetFirstDecl(clang::Decl *d) {
+  if (!d)
+    return nullptr;
+  if (auto *td = llvm::dyn_cast<clang::TagDecl>(d))
+    return td->getFirstDecl();
+  if (auto *od = llvm::dyn_cast<clang::ObjCInterfaceDecl>(d))
+    return od->getFirstDecl();
+  return d;
+}
+
 std::string ClangUtil::DumpDecl(const clang::Decl *d) {
   if (!d)
     return "nullptr";
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
index 50cae42bc7c21..a8db09277e434 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
@@ -36,6 +36,15 @@ struct ClangUtil {
 
   static clang::TagDecl *GetAsTagDecl(const CompilerType &type);
 
+  /// If the given Decl is redeclarable, return the first declaration in its
+  /// redeclaration chain. Otherwise return d itself.
+  static clang::Decl *GetFirstDecl(clang::Decl *d);
+
+  /// \see ClangUtil::GetFirstDecl
+  static const clang::Decl *GetFirstDecl(const clang::Decl *d) {
+    return GetFirstDecl(const_cast<clang::Decl *>(d));
+  }
+
   /// Returns a textual representation of the given Decl's AST. Does not
   /// deserialize any child nodes.
   static std::string DumpDecl(const clang::Decl *d);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index cd1c500d9aa29..30fd2b0c23271 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -10,6 +10,7 @@
 
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/FormatAdapters.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -1159,11 +1160,18 @@ CompilerType TypeSystemClang::GetTypeForDecl(clang::NamedDecl *decl) {
 }
 
 CompilerType TypeSystemClang::GetTypeForDecl(TagDecl *decl) {
-  return GetType(getASTContext().getTagDeclType(decl));
+  // Create the type for the TagDecl. Pass the previous decl to make sure that
+  // all redeclarations share the same type.
+  return GetType(
+      getASTContext().getTypeDeclType(decl, decl->getPreviousDecl()));
 }
 
-CompilerType TypeSystemClang::GetTypeForDecl(ObjCInterfaceDecl *decl) {
-  return GetType(getASTContext().getObjCInterfaceType(decl));
+CompilerType TypeSystemClang::GetTypeForDecl(const ObjCInterfaceDecl *decl) {
+  // FIXME: getObjCInterfaceType second parameter could be const.
+  // Create the type for the ObjCInterfaceDecl. Pass the previous decl to make
+  // sure that all redeclarations share the same type.
+  return GetType(getASTContext().getObjCInterfaceType(
+      decl, const_cast<ObjCInterfaceDecl *>(decl->getPreviousDecl())));
 }
 
 CompilerType TypeSystemClang::GetTypeForDecl(clang::ValueDecl *value_decl) {
@@ -1218,6 +1226,17 @@ TypeSystemClang::GetOrCreateClangModule(llvm::StringRef name,
 }
 
 CompilerType TypeSystemClang::CreateRecordType(
+    clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
+    lldb::AccessType access_type, llvm::StringRef name, int kind,
+    lldb::LanguageType language, ClangASTMetadata *metadata,
+    bool exports_symbols) {
+  clang::NamedDecl *d =
+      CreateRecordDecl(decl_ctx, owning_module, access_type, name, kind,
+                       language, metadata, exports_symbols);
+  return GetTypeForDecl(d);
+}
+
+clang::NamedDecl *TypeSystemClang::CreateRecordDecl(
     clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
     AccessType access_type, llvm::StringRef name, int kind,
     LanguageType language, ClangASTMetadata *metadata, bool exports_symbols) {
@@ -1225,13 +1244,14 @@ CompilerType TypeSystemClang::CreateRecordType(
 
   if (decl_ctx == nullptr)
     decl_ctx = ast.getTranslationUnitDecl();
+  decl_ctx = decl_ctx->getPrimaryContext();
 
   if (language == eLanguageTypeObjC ||
       language == eLanguageTypeObjC_plus_plus) {
     bool isForwardDecl = true;
     bool isInternal = false;
-    return CreateObjCClass(name, decl_ctx, owning_module, isForwardDecl,
-                           isInternal, metadata);
+    return CreateObjCDecl(name, decl_ctx, owning_module, isForwardDecl,
+                          isInternal, metadata);
   }
 
   // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and
@@ -1286,7 +1306,7 @@ CompilerType TypeSystemClang::CreateRecordType(
   if (decl_ctx)
     decl_ctx->addDecl(decl);
 
-  return GetType(ast.getTagDeclType(decl));
+  return decl;
 }
 
 namespace {
@@ -1548,6 +1568,7 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl(
   ClassTemplateDecl *class_template_decl = nullptr;
   if (decl_ctx == nullptr)
     decl_ctx = ast.getTranslationUnitDecl();
+  decl_ctx = decl_ctx->getPrimaryContext();
 
   IdentifierInfo &identifier_info = ast.Idents.get(class_name);
   DeclarationName decl_name(&identifier_info);
@@ -1643,6 +1664,8 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
     DeclContext *decl_ctx, OptionalClangModuleID owning_module,
     ClassTemplateDecl *class_template_decl, int kind,
     const TemplateParameterInfos &template_param_infos) {
+  decl_ctx = decl_ctx->getPrimaryContext();
+
   ASTContext &ast = getASTContext();
   llvm::SmallVector<clang::TemplateArgument, 2> args(
       template_param_infos.Size() +
@@ -1662,7 +1685,6 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
   class_template_specialization_decl->setInstantiationOf(class_template_decl);
   class_template_specialization_decl->setTemplateArgs(
       TemplateArgumentList::CreateCopy(ast, args));
-  ast.getTypeDeclType(class_template_specialization_decl, nullptr);
   class_template_specialization_decl->setDeclName(
       class_template_decl->getDeclName());
   SetOwningModule(class_template_specialization_decl, owning_module);
@@ -1671,6 +1693,13 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
   class_template_specialization_decl->setSpecializationKind(
       TSK_ExplicitSpecialization);
 
+  // Store the information that is needed to later redeclare this exact
+  // template specialization.
+  ClassTemplateRedeclInfo redecl_info;
+  redecl_info.m_template_args = template_param_infos;
+  m_class_template_redecl_infos[class_template_specialization_decl] =
+      redecl_info;
+
   return class_template_specialization_decl;
 }
 
@@ -1796,7 +1825,7 @@ bool TypeSystemClang::RecordHasFields(const RecordDecl *record_decl) {
 
 #pragma mark Objective-C Classes
 
-CompilerType TypeSystemClang::CreateObjCClass(
+clang::ObjCInterfaceDecl *TypeSystemClang::CreateObjCDecl(
     llvm::StringRef name, clang::DeclContext *decl_ctx,
     OptionalClangModuleID owning_module, bool isForwardDecl, bool isInternal,
     ClangASTMetadata *metadata) {
@@ -1816,7 +1845,7 @@ CompilerType TypeSystemClang::CreateObjCClass(
   if (metadata)
     SetMetadata(decl, *metadata);
 
-  return GetType(ast.getObjCInterfaceType(decl));
+  return decl;
 }
 
 bool TypeSystemClang::BaseSpecifierIsEmpty(const CXXBaseSpecifier *b) {
@@ -2299,7 +2328,7 @@ CompilerType TypeSystemClang::GetOrCreateStructForIdentifier(
 
 #pragma mark Enumeration Types
 
-CompilerType TypeSystemClang::CreateEnumerationType(
+clang::EnumDecl *TypeSystemClang::CreateEnumerationDecl(
     llvm::StringRef name, clang::DeclContext *decl_ctx,
     OptionalClangModuleID owning_module, const Declaration &decl,
     const CompilerType &integer_clang_type, bool is_scoped) {
@@ -2325,7 +2354,7 @@ CompilerType TypeSystemClang::CreateEnumerationType(
 
   enum_decl->setAccess(AS_public); // TODO respect what's in the debug info
 
-  return GetType(ast.getTagDeclType(enum_decl));
+  return enum_decl;
 }
 
 CompilerType TypeSystemClang::GetIntTypeFromBitSize(size_t bit_size,
@@ -2432,7 +2461,9 @@ bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast,
 
     ast_source->CompleteType(tag_decl);
 
-    return !tag_decl->getTypeForDecl()->isIncompleteType();
+    tag_decl = tag_decl->getDefinition();
+
+    return tag_decl && !tag_decl->getTypeForDecl()->isIncompleteType();
   } else if (clang::ObjCInterfaceDecl *objc_interface_decl =
                  llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl)) {
     if (objc_interface_decl->getDefinition())
@@ -2443,7 +2474,10 @@ bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast,
 
     ast_source->CompleteType(objc_interface_decl);
 
-    return !objc_interface_decl->getTypeForDecl()->isIncompleteType();
+    objc_interface_decl = objc_interface_decl->getDefinition();
+
+    return objc_interface_decl &&
+           !objc_interface_decl->getTypeForDecl()->isIncompleteType();
   } else {
     return false;
   }
@@ -2463,9 +2497,17 @@ void TypeSystemClang::SetMetadataAsUserID(const clang::Type *type,
   SetMetadata(type, meta_data);
 }
 
+/// Returns the Decl in a redeclaration chain that is used to store the
+/// the ClangASTMetadata in the metadata map.
+static const clang::Decl *GetDeclForMetadataStorage(const clang::Decl *d) {
+  // Only the first Decl never changes and never requires any loading from
+  // the ExternalASTSource, so it can be a stable key for the map.
+  return ClangUtil::GetFirstDecl(d);
+}
+
 void TypeSystemClang::SetMetadata(const clang::Decl *object,
                                   ClangASTMetadata &metadata) {
-  m_decl_metadata[object] = metadata;
+  m_decl_metadata[GetDeclForMetadataStorage(object)] = metadata;
 }
 
 void TypeSystemClang::SetMetadata(const clang::Type *object,
@@ -2474,7 +2516,7 @@ void TypeSystemClang::SetMetadata(const clang::Type *object,
 }
 
 ClangASTMetadata *TypeSystemClang::GetMetadata(const clang::Decl *object) {
-  auto It = m_decl_metadata.find(object);
+  auto It = m_decl_metadata.find(GetDeclForMetadataStorage(object));
   if (It != m_decl_metadata.end())
     return &It->second;
   return nullptr;
@@ -4644,6 +4686,7 @@ CompilerType TypeSystemClang::CreateTypedef(
         TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx);
     if (!decl_ctx)
       decl_ctx = getASTContext().getTranslationUnitDecl();
+    decl_ctx = decl_ctx->getPrimaryContext();
 
     clang::TypedefDecl *decl =
         clang::TypedefDecl::CreateDeserialized(clang_ast, GlobalDeclID());
@@ -5578,6 +5621,9 @@ void TypeSystemClang::ForEachEnumerator(
   if (enum_type) {
     const clang::EnumDecl *enum_decl = enum_type->getDecl();
     if (enum_decl) {
+      enum_decl = enum_decl->getDefinition();
+      if (!enum_decl)
+        return;
       CompilerType integer_type = GetType(enum_decl->getIntegerType());
 
       clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
@@ -7721,6 +7767,8 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
 
   clang::CXXRecordDecl *cxx_record_decl =
       record_qual_type->getAsCXXRecordDecl();
+  if (cxx_record_decl)
+    cxx_record_decl = cxx_record_decl->getDefinition();
 
   if (cxx_record_decl == nullptr)
     return nullptr;
@@ -8199,9 +8247,13 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType(
     return nullptr;
 
   clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type);
+  if (class_interface_decl)
+    if (auto * def = class_interface_decl->getDefinition())
+      class_interface_decl = def;
 
   if (class_interface_decl == nullptr)
     return nullptr;
+
   auto ts = type.GetTypeSystem();
   auto lldb_ast = ts.dyn_cast_or_null<TypeSystemClang>();
   if (lldb_ast == nullptr)
@@ -8272,8 +8324,7 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType(
       clang::ObjCMethodDecl::CreateDeserialized(ast, GlobalDeclID());
   objc_method_decl->setDeclName(method_selector);
   objc_method_decl->setReturnType(method_function_prototype->getReturnType());
-  objc_method_decl->setDeclContext(
-      lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type)));
+  objc_method_decl->setDeclContext(class_interface_decl);
   objc_method_decl->setInstanceMethod(isInstance);
   objc_method_decl->setVariadic(isVariadic);
   objc_method_decl->setPropertyAccessor(isPropertyAccessor);
@@ -8383,7 +8434,11 @@ bool TypeSystemClang::StartTagDeclarationDefinition(const CompilerType &type) {
     if (tag_type) {
       clang::TagDecl *tag_decl = tag_type->getDecl();
       if (tag_decl) {
-        tag_decl->startDefinition();
+        // There are several declarations in the redeclaration chain that could
+        // define this type. The most logical declaration that we could turn
+        // into a definition is the most recent one.
+        clang::TagDecl *def = tag_decl->getMostRecentDecl();
+        def->startDefinition();
         return true;
       }
     }
@@ -8393,7 +8448,11 @@ bool TypeSystemClang::StartTagDeclarationDefinition(const CompilerType &type) {
     if (object_type) {
       clang::ObjCInterfaceDecl *interface_decl = object_type->getInterface();
       if (interface_decl) {
-        interface_decl->startDefinition();
+        // There are several declarations in the redeclaration chain that could
+        // define this type. The most logical declaration that we could turn
+        // into a definition is the most recent one.
+        clang::ObjCInterfaceDecl *def = interface_decl->getMostRecentDecl();
+        def->startDefinition();
         return true;
       }
     }
@@ -8636,7 +8695,7 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
                           uint32_t bitfield_bit_size) {
   const clang::EnumType *enutype =
       llvm::cast<clang::EnumType>(qual_type.getTypePtr());
-  const clang::EnumDecl *enum_decl = enutype->getDecl();
+  const clang::EnumDecl *enum_decl = enutype->getDecl()->getDefinition();
   assert(enum_decl);
   lldb::offset_t offset = byte_offset;
   const uint64_t enum_svalue = data.GetMaxS64Bitfield(
@@ -8870,7 +8929,7 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
       if (!objc_class_type)
         break;
       clang::ObjCInterfaceDecl *class_interface_decl =
-            objc_class_type->getInterface();
+          objc_class_type->getInterface()->getDefinition();
       if (!class_interface_decl)
         break;
       if (level == eDescriptionLevelVerbose)
@@ -9045,6 +9104,88 @@ void TypeSystemClang::CompleteObjCInterfaceDecl(
   }
 }
 
+/// Appends an existing declaration to the redeclaration chain.
+/// \param ts The TypeSystemClang that contains the two declarations.
+/// \param prev The most recent existing declaration.
+/// \param redecl The new declaration which should be appended to the end of
+/// redeclaration chain.
+template <typename T>
+static void ConnectRedeclToPrev(TypeSystemClang &ts, T *prev, T *redecl) {
+  assert(&ts.getASTContext() == &prev->getASTContext() && "Not ");
+  redecl->setPreviousDecl(prev);
+  // Now that the redecl chain is done, create the type explicitly via
+  // the TypeSystemClang interface that will reuse the type of the previous
+  // decl.
+  ts.GetTypeForDecl(redecl);
+  // The previous decl and the redeclaration both declare the same type.
+  assert(prev->getTypeForDecl() == redecl->getTypeForDecl());
+}
+
+/// Returns the ClangModuleID for the given declaration.
+static OptionalClangModuleID GetModuleForDecl(clang::Decl *d) {
+  if (!d->isFromASTFile() || !d->getOwningModuleID())
+    return OptionalClangModuleID();
+  return OptionalClangModuleID(d->getOwningModuleID());
+}
+
+void TypeSystemClang::CreateRedeclaration(CompilerType ct) {
+  // All the cases below just check for a specific declaration kind, create
+  // a new declaration with matching data. We don't care about metadata which
+  // should only be tracked in the first redeclaration and should be identical
+  // for all redeclarations.
+
+  if (clang::ObjCInterfaceDecl *interface = GetAsObjCInterfaceDecl(ct)) {
+    clang::NamedDecl *res = CreateObjCDecl(
+        interface->getName(), interface->getDeclContext()->getRedeclContext(),
+        GetModuleForDecl(interface), /*isForwardDecl=*/false,
+        interface->isImplicit());
+    clang::ObjCInterfaceDecl *redecl = llvm::cast<ObjCInterfaceDecl>(res);
+    ConnectRedeclToPrev(*this, interface, redecl);
+    return;
+  }
+
+  clang::TagDecl *tag_decl = ClangUtil::GetAsTagDecl(ct);
+  if (!tag_decl)
+    return;
+
+  if (clang::EnumDecl *enum_decl = dyn_cast<EnumDecl>(tag_decl)) {
+    Declaration decl;
+    clang::EnumDecl *redecl = CreateEnumerationDecl(
+        enum_decl->getNameAsString().c_str(),
+        tag_decl->getDeclContext()->getRedeclContext(),
+        GetModuleForDecl(enum_decl), decl, GetType(enum_decl->getIntegerType()),
+        enum_decl->isScoped());
+    ConnectRedeclToPrev(*this, enum_decl, redecl);
+    return;
+  }
+
+  if (auto *template_decl =
+          dyn_cast<ClassTemplateSpecializationDecl>(tag_decl)) {
+    auto redecl_info = m_class_template_redecl_infos.find(template_decl);
+    // If we are asked to redeclare a template that we haven't declared, then
+    // there is nothing we can do.
+    assert(redecl_info != m_class_template_redecl_infos.end());
+    TemplateParameterInfos template_infos = redecl_info->second.m_template_args;
+    auto *redecl = CreateClassTemplateSpecializationDecl(
+        tag_decl->getDeclContext()->getRedeclContext(),
+        GetModuleForDecl(template_decl),
+        template_decl->getSpecializedTemplate(),
+        llvm::to_underlying(tag_decl->getTagKind()), template_infos);
+    ConnectRedeclToPrev(*this, template_decl, redecl);
+    return;
+  }
+
+  assert(llvm::isa<RecordDecl>(tag_decl));
+  clang::NamedDecl *redecl_record = CreateRecordDecl(
+      tag_decl->getDeclContext()->getRedeclContext(),
+      GetModuleForDecl(tag_decl), lldb::eAccessPublic, tag_decl->getName(),
+      llvm::to_underlying(tag_decl->getTagKind()), eLanguageTypeC_plus_plus,
+      nullptr);
+  clang::TagDecl *redecl = llvm::cast<TagDecl>(redecl_record);
+  ConnectRedeclToPrev(*this, tag_decl, redecl);
+  return;
+}
+
 DWARFASTParser *TypeSystemClang::GetDWARFParser() {
   if (!m_dwarf_ast_parser_up)
     m_dwarf_ast_parser_up = std::make_unique<DWARFASTParserClang>(*this);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 75c8cceec3aab..09752124b7453 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -252,7 +252,7 @@ class TypeSystemClang : public TypeSystem {
 
   CompilerType GetTypeForDecl(clang::TagDecl *decl);
 
-  CompilerType GetTypeForDecl(clang::ObjCInterfaceDecl *objc_decl);
+  CompilerType GetTypeForDecl(const clang::ObjCInterfaceDecl *objc_decl);
 
   CompilerType GetTypeForDecl(clang::ValueDecl *value_decl);
 
@@ -333,6 +333,14 @@ class TypeSystemClang : public TypeSystem {
                                 ClangASTMetadata *metadata = nullptr,
                                 bool exports_symbols = false);
 
+  clang::NamedDecl *CreateRecordDecl(clang::DeclContext *decl_ctx,
+                                     OptionalClangModuleID owning_module,
+                                     lldb::AccessType access_type,
+                                     llvm::StringRef name, int kind,
+                                     lldb::LanguageType language,
+                                     ClangASTMetadata *metadata = nullptr,
+                                     bool exports_symbols = false);
+
   class TemplateParameterInfos {
   public:
     TemplateParameterInfos() = default;
@@ -476,7 +484,16 @@ class TypeSystemClang : public TypeSystem {
                                clang::DeclContext *decl_ctx,
                                OptionalClangModuleID owning_module,
                                bool isForwardDecl, bool isInternal,
-                               ClangASTMetadata *metadata = nullptr);
+                               ClangASTMetadata *metadata = nullptr) {
+    clang::ObjCInterfaceDecl *d = CreateObjCDecl(
+        name, decl_ctx, owning_module, isForwardDecl, isInternal, metadata);
+    return GetTypeForDecl(d);
+  }
+
+  clang::ObjCInterfaceDecl *
+  CreateObjCDecl(llvm::StringRef name, clang::DeclContext *decl_ctx,
+                 OptionalClangModuleID owning_module, bool isForwardDecl,
+                 bool isInternal, ClangASTMetadata *metadata = nullptr);
 
   // Returns a mask containing bits from the TypeSystemClang::eTypeXXX
   // enumerations
@@ -518,12 +535,23 @@ class TypeSystemClang : public TypeSystem {
                                size_t element_count, bool is_vector);
 
   // Enumeration Types
+  clang::EnumDecl *CreateEnumerationDecl(llvm::StringRef name,
+                                         clang::DeclContext *decl_ctx,
+                                         OptionalClangModuleID owning_module,
+                                         const Declaration &decl,
+                                         const CompilerType &integer_qual_type,
+                                         bool is_scoped);
+
   CompilerType CreateEnumerationType(llvm::StringRef name,
                                      clang::DeclContext *decl_ctx,
                                      OptionalClangModuleID owning_module,
                                      const Declaration &decl,
                                      const CompilerType &integer_qual_type,
-                                     bool is_scoped);
+                                     bool is_scoped) {
+    clang::EnumDecl *enum_decl = CreateEnumerationDecl(
+        name, decl_ctx, owning_module, decl, integer_qual_type, is_scoped);
+    return GetType(getASTContext().getTagDeclType(enum_decl));
+  }
 
   // Integer type functions
 
@@ -546,6 +574,15 @@ class TypeSystemClang : public TypeSystem {
 
   void CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *);
 
+  /// Creates a redeclaration for the declaration specified by the given type.
+  /// The redeclaration will be at the end of the redeclaration chain. The
+  /// passed declaration has to be created via a TypeSystemClang interface.
+  ///
+  /// \param type The type which declaration should be redeclared. Has to be
+  /// an Objective-C interface type (or Objective-C type), RecordType or
+  /// EnumType.
+  void CreateRedeclaration(CompilerType ct);
+
   bool LayoutRecordType(
       const clang::RecordDecl *record_decl, uint64_t &size, uint64_t &alignment,
       llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
@@ -1229,6 +1266,18 @@ class TypeSystemClang : public TypeSystem {
   /// AccessSpecifier.
   CXXRecordDeclAccessMap m_cxx_record_decl_access;
 
+  /// The information we need to redeclare a class template but that we can't
+  /// gather from the forward declaration.
+  struct ClassTemplateRedeclInfo {
+    TemplateParameterInfos m_template_args;
+  };
+  typedef llvm::DenseMap<const clang::Decl *, ClassTemplateRedeclInfo>
+      ClassTemplateRedeclInfoMap;
+  // FIXME: This is in theory redundant. Instead we should change the way we
+  // create ClassTemplateSpecializationDecls in TypeSystemClang so that we can
+  // just pass the data from the forward declaration.
+  ClassTemplateRedeclInfoMap m_class_template_redecl_infos;
+
   /// The sema associated that is currently used to build this ASTContext.
   /// May be null if we are already done parsing this ASTContext or the
   /// ASTContext wasn't created by parsing source code.
diff --git a/lldb/unittests/CMakeLists.txt b/lldb/unittests/CMakeLists.txt
index a2585a94b6155..4d65ef563bc96 100644
--- a/lldb/unittests/CMakeLists.txt
+++ b/lldb/unittests/CMakeLists.txt
@@ -68,6 +68,7 @@ add_subdirectory(ScriptInterpreter)
 add_subdirectory(Signals)
 add_subdirectory(Symbol)
 add_subdirectory(SymbolFile)
+add_subdirectory(TypeSystem)
 add_subdirectory(Target)
 add_subdirectory(tools)
 add_subdirectory(UnwindAssembly)
diff --git a/lldb/unittests/TypeSystem/CMakeLists.txt b/lldb/unittests/TypeSystem/CMakeLists.txt
new file mode 100644
index 0000000000000..17c40aee44cc2
--- /dev/null
+++ b/lldb/unittests/TypeSystem/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(Clang)
diff --git a/lldb/unittests/TypeSystem/Clang/CMakeLists.txt b/lldb/unittests/TypeSystem/Clang/CMakeLists.txt
new file mode 100644
index 0000000000000..15e226c172d17
--- /dev/null
+++ b/lldb/unittests/TypeSystem/Clang/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_lldb_unittest(TypeSystemClangTests
+  TestClangRedeclarations.cpp
+
+  LINK_LIBS
+    lldbHost
+    lldbSymbol
+    lldbUtilityHelpers
+    lldbPluginObjectFileELF
+    lldbPluginObjectFileMachO
+    lldbPluginSymbolFileDWARF
+    lldbPluginSymbolFileSymtab
+    lldbPluginTypeSystemClang
+    LLVMTestingSupport
+  )
diff --git a/lldb/unittests/TypeSystem/Clang/TestClangRedeclarations.cpp b/lldb/unittests/TypeSystem/Clang/TestClangRedeclarations.cpp
new file mode 100644
index 0000000000000..c669a22dc9f56
--- /dev/null
+++ b/lldb/unittests/TypeSystem/Clang/TestClangRedeclarations.cpp
@@ -0,0 +1,332 @@
+//===-- TestClangRedeclarations.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/Symbol/ClangTestUtils.h"
+#include "lldb/Core/Declaration.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Type.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace lldb;
+using namespace lldb_private;
+
+struct TestClangRedeclarations : public testing::Test {
+  SubsystemRAII<FileSystem, HostInfo> subsystems;
+
+  void SetUp() override {
+    m_holder =
+        std::make_unique<clang_utils::TypeSystemClangHolder>("test ASTContext");
+    m_ast = m_holder->GetAST();
+  }
+
+  void TearDown() override {
+    m_ast = nullptr;
+    m_holder.reset();
+  }
+
+  TypeSystemClang *m_ast = nullptr;
+  std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
+};
+
+TEST_F(TestClangRedeclarations, RedeclareCppClass) {
+  // Test redeclaring C++ classes.
+
+  OptionalClangModuleID module_id(1);
+  CompilerType class_type = m_ast->CreateRecordType(
+      m_ast->GetTranslationUnitDecl(), module_id, lldb::eAccessNone, "A",
+      llvm::to_underlying(TagTypeKind::Class), lldb::eLanguageTypeC_plus_plus);
+  auto *record = llvm::cast<CXXRecordDecl>(ClangUtil::GetAsTagDecl(class_type));
+
+  m_ast->CreateRedeclaration(class_type);
+  m_ast->StartTagDeclarationDefinition(class_type);
+  // For C++ classes, the definition is already available (but it is currently
+  // being defined). Make sure the definition is last in the redecl chain.
+  CXXRecordDecl *def = record->getDefinition();
+  ASSERT_TRUE(def);
+  ASSERT_TRUE(def->isBeingDefined());
+  ASSERT_NE(def, record);
+  EXPECT_EQ(def->getPreviousDecl(), record);
+
+  // Add a method.
+  std::vector<CompilerType> args;
+  CompilerType func_type =
+      m_ast->CreateFunctionType(m_ast->GetBasicType(lldb::eBasicTypeInt),
+                                args.data(), args.size(), /*is_variadic=*/false,
+                                /*type_quals=*/0, clang::CallingConv::CC_C);
+  const bool is_virtual = false;
+  const bool is_static = false;
+  const bool is_inline = false;
+  const bool is_explicit = false;
+  const bool is_attr_used = false;
+  const bool is_artificial = false;
+  clang::CXXMethodDecl *method = m_ast->AddMethodToCXXRecordType(
+      class_type.GetOpaqueQualType(), "A", nullptr, func_type,
+      lldb::eAccessPublic, is_virtual, is_static, is_inline, is_explicit,
+      is_attr_used, is_artificial);
+  // Check that the method was created and is in the definition.
+  ASSERT_NE(method, nullptr);
+  EXPECT_EQ(method->getParent(), def);
+
+  // Add an ivar and check that it was added to the definition.
+  FieldDecl *member_var = m_ast->AddFieldToRecordType(
+      class_type, "f", m_ast->GetBasicType(lldb::eBasicTypeInt),
+      lldb::eAccessPublic,
+      /*bitfield_bit_size=*/0);
+  ASSERT_TRUE(member_var);
+  EXPECT_EQ(member_var->getParent(), def);
+
+  // Complete the class and check that the last decl is the definition.
+  m_ast->CompleteTagDeclarationDefinition(class_type);
+  EXPECT_FALSE(record->isThisDeclarationADefinition());
+  EXPECT_TRUE(def->isThisDeclarationADefinition());
+  // Check that the module is identical.
+  EXPECT_EQ(def->getOwningModuleID(), module_id.GetValue());
+
+  // Make sure forward decl and definition have the same type.
+  EXPECT_EQ(def->getTypeForDecl(), record->getTypeForDecl());
+}
+
+TEST_F(TestClangRedeclarations, RedeclareCppTemplateClass) {
+  // Test redeclaring C++ template classes.
+
+  OptionalClangModuleID module_id(1);
+  auto args = std::make_unique<TypeSystemClang::TemplateParameterInfos>();
+  args->InsertArg("T", TemplateArgument(m_ast->getASTContext().IntTy));
+
+  ClassTemplateDecl *template_decl = m_ast->CreateClassTemplateDecl(
+      m_ast->GetTranslationUnitDecl(), module_id, lldb::eAccessNone, "A",
+      llvm::to_underlying(TagTypeKind::Struct), *args);
+  ClassTemplateSpecializationDecl *fwd_decl =
+      m_ast->CreateClassTemplateSpecializationDecl(
+          m_ast->GetTranslationUnitDecl(), module_id, template_decl,
+          llvm::to_underlying(TagTypeKind::Struct), *args);
+  CompilerType spec_type =
+      m_ast->CreateClassTemplateSpecializationType(fwd_decl);
+
+  // Delete the TemplateParameterInfos to make sure TypeSystemClang doesn't
+  // rely on the caller to keep them around.
+  args.reset();
+
+  m_ast->CreateRedeclaration(spec_type);
+  m_ast->StartTagDeclarationDefinition(spec_type);
+  // For C++ classes, the definition is already available (but it is currently
+  // being defined). Make sure the definition is last in the redecl chain.
+  CXXRecordDecl *def = fwd_decl->getDefinition();
+  ASSERT_TRUE(def);
+  ASSERT_TRUE(def->isBeingDefined());
+  ASSERT_NE(def, fwd_decl);
+  EXPECT_EQ(def->getPreviousDecl(), fwd_decl);
+
+  // Add an ivar and check that it was added to the definition.
+  FieldDecl *member_var = m_ast->AddFieldToRecordType(
+      spec_type, "f", m_ast->GetBasicType(lldb::eBasicTypeInt),
+      lldb::eAccessPublic,
+      /*bitfield_bit_size=*/0);
+  ASSERT_TRUE(member_var);
+  EXPECT_EQ(member_var->getParent(), def);
+
+  // Complete the class and check that the last decl is the definition.
+  m_ast->CompleteTagDeclarationDefinition(spec_type);
+  EXPECT_FALSE(fwd_decl->isThisDeclarationADefinition());
+  EXPECT_TRUE(def->isThisDeclarationADefinition());
+
+  // Check that the module is identical.
+  EXPECT_EQ(def->getOwningModuleID(), module_id.GetValue());
+
+  // Make sure forward decl and definition have the same type.
+  EXPECT_EQ(def->getTypeForDecl(), fwd_decl->getTypeForDecl());
+}
+
+TEST_F(TestClangRedeclarations, RedeclareObjCClass) {
+  // Test redeclaring Objective-C interfaces.
+
+  OptionalClangModuleID module_id(1);
+  CompilerType objc_class =
+      m_ast->CreateObjCClass("A", m_ast->GetTranslationUnitDecl(), module_id,
+                             /*isForwardDecl=*/false,
+                             /*isInternal=*/false);
+  ObjCInterfaceDecl *interface = m_ast->GetAsObjCInterfaceDecl(objc_class);
+  m_ast->CreateRedeclaration(objc_class);
+  m_ast->StartTagDeclarationDefinition(objc_class);
+  ObjCInterfaceDecl *def = interface->getDefinition();
+  ASSERT_TRUE(def);
+  ASSERT_NE(def, interface);
+  EXPECT_EQ(def->getPreviousDecl(), interface);
+
+  // Add a method.
+  std::vector<CompilerType> args;
+  CompilerType func_type =
+      m_ast->CreateFunctionType(m_ast->GetBasicType(lldb::eBasicTypeInt),
+                                args.data(), args.size(), /*is_variadic=*/false,
+                                /*type_quals=*/0, clang::CallingConv::CC_C);
+  const bool variadic = false;
+  const bool artificial = false;
+  const bool objc_direct = false;
+  clang::ObjCMethodDecl *method = TypeSystemClang::AddMethodToObjCObjectType(
+      objc_class, "-[A foo]", func_type, artificial, variadic, objc_direct);
+  // Check that the method was created and is in the definition.
+  ASSERT_NE(method, nullptr);
+  EXPECT_EQ(*def->meth_begin(), method);
+
+  // Add an ivar and check that it was added to the definition.
+  FieldDecl *ivar = m_ast->AddFieldToRecordType(
+      objc_class, "f", m_ast->GetBasicType(lldb::eBasicTypeInt),
+      lldb::eAccessPublic,
+      /*bitfield_bit_size=*/0);
+  ASSERT_TRUE(ivar);
+  EXPECT_EQ(*def->ivar_begin(), ivar);
+
+  m_ast->CompleteTagDeclarationDefinition(objc_class);
+  // The forward declaration should be unchanged.
+  EXPECT_FALSE(interface->isThisDeclarationADefinition());
+  EXPECT_TRUE(def->isThisDeclarationADefinition());
+  // Check that the module is identical.
+  EXPECT_EQ(def->getOwningModuleID(), module_id.GetValue());
+
+  // Make sure forward decl and definition have the same type.
+  EXPECT_EQ(def->getTypeForDecl(), interface->getTypeForDecl());
+}
+
+TEST_F(TestClangRedeclarations, RedeclareEnum) {
+  // Test redeclaring enums.
+
+  OptionalClangModuleID module_id(1);
+  Declaration decl;
+  CompilerType enum_type = m_ast->CreateEnumerationType(
+      "A", m_ast->GetTranslationUnitDecl(), module_id, decl,
+      m_ast->GetBasicType(lldb::eBasicTypeInt), /*is_scoped=*/true);
+
+  EnumDecl *fwd_decl = m_ast->GetAsEnumDecl(enum_type);
+  m_ast->CreateRedeclaration(enum_type);
+  m_ast->StartTagDeclarationDefinition(enum_type);
+  m_ast->AddEnumerationValueToEnumerationType(
+      enum_type, decl, "case1", /*enum_value=*/1, /*enum_value_bit_size=*/32);
+  m_ast->CompleteTagDeclarationDefinition(enum_type);
+
+  // There should now be a definition at the end of the redeclaration chain.
+  EnumDecl *def = fwd_decl->getDefinition();
+  ASSERT_TRUE(def);
+  ASSERT_NE(def, fwd_decl);
+  EXPECT_EQ(def->getPreviousDecl(), fwd_decl);
+  // The forward declaration should be unchanged.
+  EXPECT_FALSE(fwd_decl->isThisDeclarationADefinition());
+  EXPECT_TRUE(def->isThisDeclarationADefinition());
+  // Check that the module is identical.
+  EXPECT_EQ(def->getOwningModuleID(), module_id.GetValue());
+
+  // Make sure forward decl and definition have the same type.
+  EXPECT_EQ(def->getTypeForDecl(), fwd_decl->getTypeForDecl());
+
+  // Check that ForEachEnumerator uses the definition.
+  bool seen_value = false;
+  m_ast->ForEachEnumerator(enum_type.GetOpaqueQualType(),
+                           [&seen_value](const CompilerType &, ConstString name,
+                                         const llvm::APSInt &) {
+                             EXPECT_EQ(name, "case1");
+                             seen_value = true;
+                             return true;
+                           });
+  EXPECT_TRUE(seen_value);
+}
+
+TEST_F(TestClangRedeclarations, NestedDecls) {
+  // Tests that nested declarations pick the right redeclaration as their
+  // DeclContext.
+
+  // Create a class.
+  CompilerType context_class = m_ast->CreateRecordType(
+      m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(),
+      lldb::eAccessNone, "A", llvm::to_underlying(TagTypeKind::Class),
+      lldb::eLanguageTypeC_plus_plus);
+  auto *fwd_decl =
+      llvm::cast<CXXRecordDecl>(ClangUtil::GetAsTagDecl(context_class));
+
+  // Give it a redeclaration that defines it.
+  m_ast->CreateRedeclaration(context_class);
+  m_ast->StartTagDeclarationDefinition(context_class);
+  m_ast->CompleteTagDeclarationDefinition(context_class);
+
+  // Check that there is one forward declaration and a definition now.
+  CXXRecordDecl *def = fwd_decl->getDefinition();
+  ASSERT_TRUE(def);
+  EXPECT_FALSE(fwd_decl->isThisDeclarationADefinition());
+  EXPECT_TRUE(def->isThisDeclarationADefinition());
+
+  // Create a nested class and make sure it picks the definition as its
+  // DeclContext.
+  CompilerType nested_class = m_ast->CreateRecordType(
+      fwd_decl, OptionalClangModuleID(), lldb::eAccessPublic, "A",
+      llvm::to_underlying(TagTypeKind::Class), lldb::eLanguageTypeC_plus_plus);
+  EXPECT_EQ(ClangUtil::GetAsTagDecl(nested_class)->getDeclContext(), def);
+
+  CompilerType int_type = m_ast->GetBasicType(lldb::eBasicTypeInt);
+
+  // Create a typedef and make sure it picks the definition as its DeclContext.
+  CompilerType nested_typedef = int_type.CreateTypedef(
+      "t", CompilerDeclContext(m_ast, static_cast<DeclContext *>(fwd_decl)),
+      /*payload=*/0);
+  const TypedefType *typedef_type =
+      ClangUtil::GetQualType(nested_typedef)->getAs<TypedefType>();
+  ASSERT_TRUE(typedef_type);
+  TypedefNameDecl *nested_typedef_decl = typedef_type->getDecl();
+  ASSERT_TRUE(nested_typedef_decl);
+  EXPECT_EQ(nested_typedef_decl->getDeclContext(), def);
+
+  TypeSystemClang::TemplateParameterInfos args;
+  args.InsertArg("T", TemplateArgument(m_ast->getASTContext().IntTy));
+
+  // Create a class template and specialization and check that their DeclContext
+  // is the definition.
+  ClassTemplateDecl *template_decl = m_ast->CreateClassTemplateDecl(
+      fwd_decl, OptionalClangModuleID(), lldb::eAccessPublic, "A",
+      llvm::to_underlying(TagTypeKind::Struct), args);
+  EXPECT_EQ(template_decl->getDeclContext(), def);
+  ClassTemplateSpecializationDecl *template_spec_decl =
+      m_ast->CreateClassTemplateSpecializationDecl(
+          fwd_decl, OptionalClangModuleID(), template_decl,
+          llvm::to_underlying(TagTypeKind::Struct), args);
+  EXPECT_EQ(template_spec_decl->getDeclContext(), def);
+}
+
+TEST_F(TestClangRedeclarations, MetadataRedeclaration) {
+  // Tests that metadata is shared between redeclarations.
+
+  // Create a class with the test metadata.
+  CompilerType class_with_metadata = m_ast->CreateRecordType(
+      m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(),
+      lldb::eAccessPublic, "A", llvm::to_underlying(TagTypeKind::Class),
+      lldb::eLanguageTypeC_plus_plus);
+  auto *record =
+      llvm::cast<CXXRecordDecl>(ClangUtil::GetAsTagDecl(class_with_metadata));
+  ClangASTMetadata metadata;
+  metadata.SetUserID(1234);
+  m_ast->SetMetadata(record, metadata);
+  ASSERT_EQ(m_ast->GetMetadata(record)->GetUserID(), 1234U);
+
+  // Redeclare and define the redeclaration.
+  m_ast->CreateRedeclaration(class_with_metadata);
+  m_ast->StartTagDeclarationDefinition(class_with_metadata);
+  m_ast->CompleteTagDeclarationDefinition(class_with_metadata);
+  CXXRecordDecl *def = record->getDefinition();
+  ASSERT_TRUE(def);
+  ASSERT_NE(def, record);
+  EXPECT_EQ(def->getPreviousDecl(), record);
+
+  // Check that the redeclaration has the right metadata;
+  ASSERT_TRUE(m_ast->GetMetadata(def));
+  EXPECT_EQ(m_ast->GetMetadata(def)->GetUserID(), 1234U);
+}

>From 2fc0555ff664cb916b50a3ba52d8191ed82696b3 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 15 Feb 2024 14:51:27 +0000
Subject: [PATCH 11/14] [lldb][ExpressionParser][NFC] Implement
 CompleteRedeclChain APIs

---
 .../ExpressionParser/Clang/ClangASTSource.cpp | 39 +++++++++++++++++++
 .../ExpressionParser/Clang/ClangASTSource.h   | 17 ++++++++
 .../Clang/ClangExternalASTSourceCallbacks.cpp | 19 +++++++++
 .../Clang/ClangExternalASTSourceCallbacks.h   |  2 +
 .../AppleObjCRuntime/AppleObjCDeclVendor.cpp  |  9 +++++
 5 files changed, 86 insertions(+)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 3fb70e7d5c803..0c7cdac778101 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -326,6 +326,45 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) {
   LLDB_LOG(log, "      [COID] {0}", ClangUtil::DumpDecl(interface_decl));
 }
 
+void ClangASTSource::CompleteRedeclChain(const Decl *d) {
+  if (!TypeSystemClang::UseRedeclCompletion())
+    return;
+
+  if (const clang::TagDecl *td = llvm::dyn_cast<TagDecl>(d)) {
+    if (td->isBeingDefined())
+      return;
+
+    if (td->getDefinition())
+      return;
+
+    m_ast_importer_sp->CompleteTagDecl(const_cast<clang::TagDecl *>(td));
+    if (!td->getDefinition() && m_ast_importer_sp->GetDeclOrigin(td).Valid()) {
+      if (TagDecl *alternate = FindCompleteType(td))
+        m_ast_importer_sp->CompleteTagDeclWithOrigin(
+            const_cast<clang::TagDecl *>(td), alternate);
+    }
+  }
+  if (const auto *od = llvm::dyn_cast<ObjCInterfaceDecl>(d)) {
+    ClangASTImporter::DeclOrigin original =
+        m_ast_importer_sp->GetDeclOrigin(od);
+    if (ObjCInterfaceDecl *orig =
+            dyn_cast_or_null<ObjCInterfaceDecl>(original.decl)) {
+      if (ObjCInterfaceDecl *i = GetCompleteObjCInterface(orig)) {
+        if (i != orig) {
+          m_ast_importer_sp->SetDeclOrigin(d, i);
+          m_ast_importer_sp->CompleteObjCInterfaceDecl(
+              const_cast<clang::ObjCInterfaceDecl *>(od));
+          return;
+        }
+      }
+    }
+    if (od->getDefinition())
+      return;
+    m_ast_importer_sp->CompleteObjCInterfaceDecl(
+        const_cast<clang::ObjCInterfaceDecl *>(od));
+  }
+}
+
 clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface(
     const clang::ObjCInterfaceDecl *interface_decl) {
   lldb::ProcessSP process(m_target->GetProcessSP());
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
index bca420efebdab..08103ff11228a 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
@@ -154,6 +154,19 @@ class ClangASTSource : public ImporterBackedASTSource,
   ///     The Decl to be completed in place.
   void CompleteType(clang::ObjCInterfaceDecl *Class) override;
 
+  /// Implements ExternalASTSource::CompleteRedeclChain.
+  ///
+  /// This function will simply complete \ref D, using
+  /// its origin to copy the definition if necessary.
+  /// If the definition for \ref D is on a different
+  /// Decl, this function will link the two into a
+  /// declaration chain (this can happen if we found
+  /// the definition on the origin).
+  ///
+  /// \param[in] D
+  ///     The Decl to complete.
+  void CompleteRedeclChain(clang::Decl const *D) override;
+
   /// Called on entering a translation unit.  Tells Clang by calling
   /// setHasExternalVisibleStorage() and setHasExternalLexicalStorage() that
   /// this object has something to say about undefined names.
@@ -232,6 +245,10 @@ class ClangASTSource : public ImporterBackedASTSource,
       return m_original.CompleteType(Class);
     }
 
+    void CompleteRedeclChain(clang::Decl const *D) override {
+      return m_original.CompleteRedeclChain(D);
+    }
+
     bool layoutRecordType(
         const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
         llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
index e746e6afe39be..587654452b139 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
@@ -27,6 +27,25 @@ void ClangExternalASTSourceCallbacks::CompleteType(
   m_ast.CompleteObjCInterfaceDecl(objc_decl);
 }
 
+void ClangExternalASTSourceCallbacks::CompleteRedeclChain(
+    const clang::Decl *d) {
+  if (!TypeSystemClang::UseRedeclCompletion())
+    return;
+
+  if (const clang::TagDecl *td = llvm::dyn_cast<clang::TagDecl>(d)) {
+    if (td->isBeingDefined())
+      return;
+    if (td->getDefinition())
+      return;
+    m_ast.CompleteTagDecl(const_cast<clang::TagDecl *>(td));
+  }
+  if (const auto *od = llvm::dyn_cast<clang::ObjCInterfaceDecl>(d)) {
+    if (od->getDefinition())
+      return;
+    m_ast.CompleteObjCInterfaceDecl(const_cast<clang::ObjCInterfaceDecl *>(od));
+  }
+}
+
 bool ClangExternalASTSourceCallbacks::layoutRecordType(
     const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
     llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
index 7cd54c7c31c8f..f73904d998e48 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
@@ -47,6 +47,8 @@ class ClangExternalASTSourceCallbacks : public ImporterBackedASTSource {
 
   void CompleteType(clang::ObjCInterfaceDecl *objc_decl) override;
 
+  void CompleteRedeclChain(clang::Decl const *D) override;
+
   bool layoutRecordType(
       const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
       llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
index 985953d7c7e67..1117d2f8d1ae8 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
@@ -109,6 +109,15 @@ class lldb_private::AppleObjCExternalASTSource
     }
   }
 
+  void CompleteRedeclChain(const clang::Decl *d) override {
+    using namespace clang;
+    auto *const_interface = llvm::dyn_cast<ObjCInterfaceDecl>(d);
+    if (!const_interface)
+      return;
+    auto *interface = const_cast<ObjCInterfaceDecl *>(const_interface);
+    m_decl_vendor.FinishDecl(interface);
+  }
+
   bool layoutRecordType(
       const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
       llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,

>From 09c5d49b798a9e611058487e345048c51eae0a0e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 14 Feb 2024 16:26:34 +0000
Subject: [PATCH 12/14] [lldb][ASTUtils] Short-circuit multiplexed
 CompleteRedeclChain when we find definition

---
 lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
index 604821137c447..bc950cc7a05b9 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
@@ -281,9 +281,16 @@ class SemaSourceWithPriorities : public ImporterBackedASTSource {
     return nullptr;
   }
 
+  /// Call ExternalASTSource::CompleteRedeclChain(D)
+  /// on each AST source. Returns as soon as we got
+  /// a definition for D.
   void CompleteRedeclChain(const clang::Decl *D) override {
-    for (size_t i = 0; i < Sources.size(); ++i)
+    for (size_t i = 0; i < Sources.size(); ++i) {
       Sources[i]->CompleteRedeclChain(D);
+      if (auto *td = llvm::dyn_cast<clang::TagDecl>(D))
+        if (td->getDefinition())
+          return;
+    }
   }
 
   clang::Selector GetExternalSelector(uint32_t ID) override {

>From 6ce188c9f6a0a0647c135643a55b3ec73602f800 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 15 Feb 2024 17:20:36 +0000
Subject: [PATCH 13/14] [lldb][WIP] Use forward decls with redeclared
 definitions instead of minimal import for records

This patch is rewriting the way we move Clang types between different ASTS in Clang.

The motivation is that the current approach for 'completing types' in LLDB just doesn't work. We have all kinds of situations where we either have Clang crash due to for example having a Record without DefinitionData but with FieldDecls in it.

The reason for that is that at the moment we create record types ([CXX]RecordDecls and ObjCInterfaceDecls) and we always pretend that a type potentially has a definition that somehow could be lazily pulled in. However, Clang doesn't have any interface (at least none that is consistently called) that turns a RecordDecl without DefinitionData into a RecordDecl with DefinitionData. The only relevant API in the ExternalASTSource is CompleteType is suffering from the fact that it's essentially not used by generic Clang code.

The part of the ExternalASTSource API that is consistently called to pull in a potential definition is CompleteRedeclChain (which is for example automatically called when calling getDefinition on a RecordDecl). The problem with CompleteRedeclChain however is that it's not supposed to add definition data to the Decl its called on, but instead it should provide a redeclaration that is defining the record. That's a very different system than what we currently have and we can't just swap it out under the hood.

To make it short: We probably need to rewrite that part of LLDB.

So the solution here is essentially rewriting all our completion code to do this:

* Instead of creating these weirdly defined records that have fields but maybe not definition and so on, we only create forward decls at the start.
* We then bump the GenerationCounter of the ExternalASTSource of the current AST to force rebuilding of the redeclaration chain.
* When Clang asks for the definition of the record, it will ask the ExternalASTSource to complete the redeclaration chain. At this point we build the definition and add it as a second decl.

The ASTImporter can now also stop using the minimal mode for records as there is no reason anymore. It just imports first the forward declaration and then the definition when needed.
---
 .../Clang/ClangASTImporter.cpp                | 253 ++++--------
 .../ExpressionParser/Clang/ClangASTSource.cpp |   6 +-
 .../Clang/ClangExternalASTSourceCallbacks.cpp |   3 -
 .../ExpressionParser/Clang/ClangUtil.cpp      |  12 +
 .../ExpressionParser/Clang/ClangUtil.h        |   2 +
 .../AppleObjCRuntime/AppleObjCDeclVendor.cpp  |  62 +--
 .../AppleObjCRuntime/AppleObjCDeclVendor.h    |   4 +
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 379 +++++++++---------
 .../SymbolFile/DWARF/DWARFASTParserClang.h    |  21 +
 .../TypeSystem/Clang/TypeSystemClang.cpp      | 105 ++---
 .../TypeSystem/Clang/TypeSystemClang.h        |   2 +-
 .../TestCppReferenceToOuterClass.py           |   2 +-
 12 files changed, 353 insertions(+), 498 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 3d3a782d544cc..913fd50d4c9af 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/LLDBLog.h"
@@ -17,6 +18,8 @@
 #include "clang/AST/RecordLayout.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Sema.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 
 #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
@@ -230,35 +233,6 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
   clang::ASTContext *m_src_ctx;
   ClangASTImporter &importer;
 
-  void CompleteDecl(
-      Decl *decl,
-      lldb_private::ClangASTImporter::ASTContextMetadata const &to_context_md) {
-    // The decl that should be completed has to be imported into the target
-    // context from some other context.
-    assert(to_context_md.hasOrigin(decl));
-    // We should only complete decls coming from the source context.
-    assert(to_context_md.getOrigin(decl).ctx == m_src_ctx);
-
-    Decl *original_decl = to_context_md.getOrigin(decl).decl;
-
-    // Complete the decl now.
-    TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
-    if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
-      if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
-        if (original_tag_decl->isCompleteDefinition()) {
-          m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
-          tag_decl->setCompleteDefinition(true);
-        }
-      }
-
-      tag_decl->setHasExternalLexicalStorage(false);
-      tag_decl->setHasExternalVisibleStorage(false);
-    } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
-      container_decl->setHasExternalLexicalStorage(false);
-      container_decl->setHasExternalVisibleStorage(false);
-    }
-  }
-
 public:
   /// Constructs a CompleteTagDeclsScope.
   /// \param importer The ClangASTImporter that we should observe.
@@ -280,9 +254,6 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
     while (!m_decls_to_complete.empty()) {
       NamedDecl *decl = m_decls_to_complete.pop_back_val();
       m_decls_already_completed.insert(decl);
-
-      CompleteDecl(decl, *to_context_md);
-
       to_context_md->removeOrigin(decl);
     }
 
@@ -296,6 +267,8 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
     if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to))
       return;
 
+    to = ClangUtil::GetFirstDecl(to);
+
     RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from);
     // We don't need to complete injected class name decls.
     if (from_record_decl && from_record_decl->isInjectedClassName())
@@ -510,14 +483,7 @@ bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) {
   if (!CanImport(compiler_type))
     return false;
 
-  if (Import(compiler_type)) {
-    TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
-    return true;
-  }
-
-  TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
-                                         false);
-  return false;
+  return Import(compiler_type);
 }
 
 /// Copy layout information from \ref source_map to the \ref destination_map.
@@ -666,8 +632,8 @@ bool ClangASTImporter::importRecordLayoutFromOrigin(
 
   int field_idx = 0, field_count = record_layout.getFieldCount();
 
-  for (RecordDecl::field_iterator fi = origin_record->field_begin(),
-                                  fe = origin_record->field_end();
+  for (RecordDecl::field_iterator fi = definition->field_begin(),
+                                  fe = definition->field_end();
        fi != fe; ++fi) {
     if (field_idx >= field_count)
       return false; // Layout didn't go well.  Bail out.
@@ -808,7 +774,8 @@ bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
   if (!decl_origin.Valid())
     return false;
 
-  if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+  auto *origin_def = llvm::cast<TagDecl>(decl_origin.decl)->getDefinition();
+  if (!origin_def)
     return false;
 
   ImporterDelegateSP delegate_sp(
@@ -816,8 +783,25 @@ bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
 
   ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
                                                 &decl->getASTContext());
-  if (delegate_sp)
-    delegate_sp->ImportDefinitionTo(decl, decl_origin.decl);
+
+  // This is expected to pull in a definition for result_decl (if in redecl
+  // completion mode)
+  llvm::Expected<Decl *> result = delegate_sp->Import(origin_def);
+  if (!result) {
+    llvm::handleAllErrors(result.takeError(),
+                          [](const clang::ASTImportError &e) {
+                            llvm::errs() << "ERR: " << e.toString() << "\n";
+                          });
+    return false;
+  }
+
+  // Create redeclaration chain with the 'to' decls.
+  // Only need to do this if the 'result_decl' is a definition outside
+  // of any redeclaration chain and the input 'decl' was a forward declaration
+  TagDecl *result_decl = llvm::cast<TagDecl>(*result);
+  if (!decl->isThisDeclarationADefinition() && result_decl != decl)
+    if (result_decl->getPreviousDecl() == nullptr)
+      result_decl->setPreviousDecl(decl);
 
   return true;
 }
@@ -838,89 +822,30 @@ bool ClangASTImporter::CompleteObjCInterfaceDecl(
   if (!decl_origin.Valid())
     return false;
 
-  if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+  ObjCInterfaceDecl *origin_decl =
+      llvm::cast<ObjCInterfaceDecl>(decl_origin.decl);
+
+  origin_decl = origin_decl->getDefinition();
+  if (!origin_decl)
     return false;
 
   ImporterDelegateSP delegate_sp(
       GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx));
 
-  if (delegate_sp)
-    delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);
+  llvm::Expected<Decl *> result = delegate_sp->Import(origin_decl);
+  if (result)
+    return true;
 
-  if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass())
-    RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0));
+  llvm::handleAllErrors(result.takeError(),
+                        [](const clang::ASTImportError &e) {
+                          llvm::errs() << "ERR: " << e.toString() << "\n";
+                        });
 
-  return true;
+  return false;
 }
 
 bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) {
-  if (!RequireCompleteType(type))
-    return false;
-
-  Log *log = GetLog(LLDBLog::Expressions);
-
-  if (const TagType *tag_type = type->getAs<TagType>()) {
-    TagDecl *tag_decl = tag_type->getDecl();
-
-    DeclOrigin decl_origin = GetDeclOrigin(tag_decl);
-
-    if (!decl_origin.Valid())
-      return false;
-
-    ImporterDelegateSP delegate_sp(
-        GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx));
-
-    ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
-                                                  &tag_decl->getASTContext());
-
-    TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl);
-
-    for (Decl *origin_child_decl : origin_tag_decl->decls()) {
-      llvm::Expected<Decl *> imported_or_err =
-          delegate_sp->Import(origin_child_decl);
-      if (!imported_or_err) {
-        LLDB_LOG_ERROR(log, imported_or_err.takeError(),
-                       "Couldn't import decl: {0}");
-        return false;
-      }
-    }
-
-    if (RecordDecl *record_decl = dyn_cast<RecordDecl>(origin_tag_decl))
-      record_decl->setHasLoadedFieldsFromExternalStorage(true);
-
-    return true;
-  }
-
-  if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
-    if (ObjCInterfaceDecl *objc_interface_decl =
-            objc_object_type->getInterface()) {
-      DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl);
-
-      if (!decl_origin.Valid())
-        return false;
-
-      ImporterDelegateSP delegate_sp(
-          GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx));
-
-      ObjCInterfaceDecl *origin_interface_decl =
-          llvm::dyn_cast<ObjCInterfaceDecl>(decl_origin.decl);
-
-      for (Decl *origin_child_decl : origin_interface_decl->decls()) {
-        llvm::Expected<Decl *> imported_or_err =
-            delegate_sp->Import(origin_child_decl);
-        if (!imported_or_err) {
-          LLDB_LOG_ERROR(log, imported_or_err.takeError(),
-                         "Couldn't import decl: {0}");
-          return false;
-        }
-      }
-
-      return true;
-    }
-    return false;
-  }
-
-  return true;
+  return RequireCompleteType(type);
 }
 
 bool ClangASTImporter::RequireCompleteType(clang::QualType type) {
@@ -1102,6 +1027,20 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
     }
   }
 
+  if (auto *source = llvm::dyn_cast<ImporterBackedASTSource>(
+          getToContext().getExternalSource())) {
+    // We added a new declaration (which is not a definition) into the
+    // destination AST context, so bump the declaration chain generation
+    // counter.
+    if (clang::TagDecl *td = dyn_cast<TagDecl>(From))
+      if (!td->isThisDeclarationADefinition())
+        source->MarkRedeclChainsAsOutOfDate(getToContext());
+
+    if (clang::ObjCInterfaceDecl *td = dyn_cast<ObjCInterfaceDecl>(From))
+      if (!td->isThisDeclarationADefinition())
+        source->MarkRedeclChainsAsOutOfDate(getToContext());
+  }
+
   // If we have a forcefully completed type, try to find an actual definition
   // for it in other modules.
   const ClangASTMetadata *md = m_main.GetDeclMetadata(From);
@@ -1122,6 +1061,12 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
     DeclContext::lookup_result lr = dc->lookup(*dn_or_err);
     for (clang::Decl *candidate : lr) {
       if (candidate->getKind() == From->getKind()) {
+        // If we're dealing with redecl chains, we want to find the definition,
+        // so skip if the decl is actually just a forwad decl.
+        if (auto *tag_decl = llvm::dyn_cast<TagDecl>(candidate);
+            !tag_decl || !tag_decl->getDefinition())
+          continue;
+
         RegisterImportedDecl(From, candidate);
         m_decls_to_ignore.insert(candidate);
         return candidate;
@@ -1223,27 +1168,6 @@ void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(
   }
 }
 
-/// Takes a CXXMethodDecl and completes the return type if necessary. This
-/// is currently only necessary for virtual functions with covariant return
-/// types where Clang's CodeGen expects that the underlying records are already
-/// completed.
-static void MaybeCompleteReturnType(ClangASTImporter &importer,
-                                        CXXMethodDecl *to_method) {
-  if (!to_method->isVirtual())
-    return;
-  QualType return_type = to_method->getReturnType();
-  if (!return_type->isPointerType() && !return_type->isReferenceType())
-    return;
-
-  clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl();
-  if (!rd)
-    return;
-  if (rd->getDefinition())
-    return;
-
-  importer.CompleteTagDecl(rd);
-}
-
 /// Recreate a module with its parents in \p to_source and return its id.
 static OptionalClangModuleID
 RemapModule(OptionalClangModuleID from_id,
@@ -1366,53 +1290,12 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
     to_namespace_decl->setHasExternalVisibleStorage();
   }
 
-  MarkDeclImported(from, to);
-}
-
-void ClangASTImporter::ASTImporterDelegate::MarkDeclImported(Decl *from,
-                                                             Decl *to) {
-  Log *log = GetLog(LLDBLog::Expressions);
-
-  if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) {
-    to_tag_decl->setHasExternalLexicalStorage();
-    to_tag_decl->getPrimaryContext()->setMustBuildLookupTable();
-    auto from_tag_decl = cast<TagDecl>(from);
-
-    LLDB_LOG(
-        log,
-        "    [ClangASTImporter] To is a TagDecl - attributes {0}{1} [{2}->{3}]",
-        (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
-        (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""),
-        (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
-        (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
+  if (clang::ObjCInterfaceDecl *td = dyn_cast<ObjCInterfaceDecl>(to)) {
+    if (clang::ExternalASTSource *s = getToContext().getExternalSource())
+      if (td->isThisDeclarationADefinition())
+        s->CompleteRedeclChain(td);
+    td->setHasExternalVisibleStorage();
   }
-
-  if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) {
-    to_container_decl->setHasExternalLexicalStorage();
-    to_container_decl->setHasExternalVisibleStorage();
-
-    if (log) {
-      if (ObjCInterfaceDecl *to_interface_decl =
-              llvm::dyn_cast<ObjCInterfaceDecl>(to_container_decl)) {
-        LLDB_LOG(
-            log,
-            "    [ClangASTImporter] To is an ObjCInterfaceDecl - attributes "
-            "{0}{1}{2}",
-            (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
-            (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""),
-            (to_interface_decl->hasDefinition() ? " HasDefinition" : ""));
-      } else {
-        LLDB_LOG(
-            log, "    [ClangASTImporter] To is an {0}Decl - attributes {1}{2}",
-            ((Decl *)to_container_decl)->getDeclKindName(),
-            (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
-            (to_container_decl->hasExternalVisibleStorage() ? " Visible" : ""));
-      }
-    }
-  }
-
-  if (clang::CXXMethodDecl *to_method = dyn_cast<CXXMethodDecl>(to))
-    MaybeCompleteReturnType(m_main, to_method);
 }
 
 clang::Decl *
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 0c7cdac778101..b88c2f0385713 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -327,9 +327,6 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) {
 }
 
 void ClangASTSource::CompleteRedeclChain(const Decl *d) {
-  if (!TypeSystemClang::UseRedeclCompletion())
-    return;
-
   if (const clang::TagDecl *td = llvm::dyn_cast<TagDecl>(d)) {
     if (td->isBeingDefined())
       return;
@@ -402,8 +399,7 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface(
     return nullptr;
 
   ObjCInterfaceDecl *complete_iface_decl(complete_interface_type->getDecl());
-
-  return complete_iface_decl;
+  return complete_iface_decl->getDefinition();
 }
 
 void ClangASTSource::FindExternalLexicalDecls(
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
index 587654452b139..515559006f36e 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
@@ -29,9 +29,6 @@ void ClangExternalASTSourceCallbacks::CompleteType(
 
 void ClangExternalASTSourceCallbacks::CompleteRedeclChain(
     const clang::Decl *d) {
-  if (!TypeSystemClang::UseRedeclCompletion())
-    return;
-
   if (const clang::TagDecl *td = llvm::dyn_cast<clang::TagDecl>(d)) {
     if (td->isBeingDefined())
       return;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
index 025b19be1eaf0..a604779fa8e17 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
@@ -76,6 +76,18 @@ clang::Decl *ClangUtil::GetFirstDecl(clang::Decl *d) {
   return d;
 }
 
+clang::ObjCInterfaceDecl *ClangUtil::GetAsObjCDecl(const CompilerType &type) {
+  clang::QualType qual_type = ClangUtil::GetCanonicalQualType(type);
+  if (qual_type.isNull())
+    return nullptr;
+
+  if (const auto *ot = qual_type->getAsObjCInterfaceType())
+    return ot->getInterface();
+  if (const auto *ot = qual_type->getAsObjCInterfacePointerType())
+    return ot->getInterfaceDecl();
+  return nullptr;
+}
+
 std::string ClangUtil::DumpDecl(const clang::Decl *d) {
   if (!d)
     return "nullptr";
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
index a8db09277e434..199c6639b68fb 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
@@ -45,6 +45,8 @@ struct ClangUtil {
     return GetFirstDecl(const_cast<clang::Decl *>(d));
   }
 
+  static clang::ObjCInterfaceDecl *GetAsObjCDecl(const CompilerType &type);
+
   /// Returns a textual representation of the given Decl's AST. Does not
   /// deserialize any child nodes.
   static std::string DumpDecl(const clang::Decl *d);
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
index 1117d2f8d1ae8..5665252fb6c03 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
@@ -12,6 +12,7 @@
 #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
 #include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
@@ -30,44 +31,6 @@ class lldb_private::AppleObjCExternalASTSource
   AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor)
       : m_decl_vendor(decl_vendor) {}
 
-  bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx,
-                                      clang::DeclarationName name) override {
-
-    Log *log(GetLog(
-        LLDBLog::Expressions)); // FIXME - a more appropriate log channel?
-
-    if (log) {
-      LLDB_LOGF(log,
-                "AppleObjCExternalASTSource::FindExternalVisibleDeclsByName"
-                " on (ASTContext*)%p Looking for %s in (%sDecl*)%p",
-                static_cast<void *>(&decl_ctx->getParentASTContext()),
-                name.getAsString().c_str(), decl_ctx->getDeclKindName(),
-                static_cast<const void *>(decl_ctx));
-    }
-
-    do {
-      const clang::ObjCInterfaceDecl *interface_decl =
-          llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
-
-      if (!interface_decl)
-        break;
-
-      clang::ObjCInterfaceDecl *non_const_interface_decl =
-          const_cast<clang::ObjCInterfaceDecl *>(interface_decl);
-
-      if (!m_decl_vendor.FinishDecl(non_const_interface_decl))
-        break;
-
-      clang::DeclContext::lookup_result result =
-          non_const_interface_decl->lookup(name);
-
-      return (!result.empty());
-    } while (false);
-
-    SetNoExternalVisibleDeclsForName(decl_ctx, name);
-    return false;
-  }
-
   void CompleteType(clang::TagDecl *tag_decl) override {
 
     Log *log(GetLog(
@@ -179,8 +142,8 @@ AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) {
   meta_data.SetISAPtr(isa);
   m_ast_ctx->SetMetadata(new_iface_decl, meta_data);
 
-  new_iface_decl->setHasExternalVisibleStorage();
-  new_iface_decl->setHasExternalLexicalStorage();
+  m_interface_to_isa[new_iface_decl] = isa;
+  m_external_source->MarkRedeclChainsAsOutOfDate(m_ast_ctx->getASTContext());
 
   ast_ctx.getTranslationUnitDecl()->addDecl(new_iface_decl);
 
@@ -408,6 +371,19 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) {
   Log *log(
       GetLog(LLDBLog::Expressions)); // FIXME - a more appropriate log channel?
 
+  clang::ObjCInterfaceDecl *iface_def = nullptr;
+  // Already completed.
+  if (interface_decl->hasDefinition())
+    return true;
+
+  clang::QualType qt(interface_decl->getTypeForDecl(), 0U);
+  CompilerType type(m_ast_ctx, qt.getAsOpaquePtr());
+  CompilerType def_type = m_ast_ctx->CreateRedeclaration(type);
+  iface_def = ClangUtil::GetAsObjCDecl(def_type);
+
+  auto isa = m_interface_to_isa[interface_decl];
+  m_isa_to_interface[isa] = iface_def;
+
   ClangASTMetadata *metadata = m_ast_ctx->GetMetadata(interface_decl);
   ObjCLanguageRuntime::ObjCISA objc_isa = 0;
   if (metadata)
@@ -416,14 +392,12 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) {
   if (!objc_isa)
     return false;
 
-  if (!interface_decl->hasExternalVisibleStorage())
+  // Could've completed during CreateRedeclaration above
+  if (interface_decl->hasDefinition())
     return true;
 
   interface_decl->startDefinition();
 
-  interface_decl->setHasExternalVisibleStorage(false);
-  interface_decl->setHasExternalLexicalStorage(false);
-
   ObjCLanguageRuntime::ClassDescriptorSP descriptor =
       m_runtime.GetClassDescriptorFromISA(objc_isa);
 
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h
index 3bb0f77f6bde4..586b3095af244 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h
@@ -46,6 +46,10 @@ class AppleObjCDeclVendor : public ClangDeclVendor {
       ISAToInterfaceMap;
 
   ISAToInterfaceMap m_isa_to_interface;
+
+  using InterfaceToISAMap =
+      llvm::DenseMap<clang::ObjCInterfaceDecl *, ObjCLanguageRuntime::ObjCISA>;
+  InterfaceToISAMap m_interface_to_isa;
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 1f9c298dc3243..2153c1d300cf8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -13,6 +13,8 @@
 #include "DWARFDebugInfo.h"
 #include "DWARFDeclContext.h"
 #include "DWARFDefines.h"
+#include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "SymbolFileDWARF.h"
 #include "SymbolFileDWARFDebugMap.h"
 #include "SymbolFileDWARFDwo.h"
@@ -27,11 +29,13 @@
 #include "lldb/Core/Value.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/CompilerType.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/SymbolFile.h"
 #include "lldb/Symbol/TypeList.h"
 #include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/TypeSystem.h"
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/Language.h"
 #include "lldb/Utility/LLDBAssert.h"
@@ -44,6 +48,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Type.h"
 #include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/Casting.h"
 
 #include <map>
 #include <memory>
@@ -64,6 +69,18 @@ using namespace lldb_private;
 using namespace lldb_private::dwarf;
 using namespace lldb_private::plugin::dwarf;
 
+/// Types that we want to complete directly (instead of
+/// relying on CompleteRedeclChain):
+/// - Anonymous structures
+/// - Function-local classes
+static bool DirectlyCompleteType(clang::DeclContext *decl_ctx,
+                                 const ParsedDWARFTypeAttributes &attrs) {
+  assert(decl_ctx);
+  if (decl_ctx->isFunctionOrMethod())
+    return true;
+  return attrs.name.IsEmpty() && !attrs.is_forward_declaration;
+}
+
 DWARFASTParserClang::DWARFASTParserClang(TypeSystemClang &ast)
     : DWARFASTParser(Kind::DWARFASTParserClang), m_ast(ast),
       m_die_to_decl_ctx(), m_decl_ctx_to_die() {}
@@ -260,7 +277,7 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast,
 
   // We have already completed the type, or we have found its definition and are
   // ready to complete it later (cf. ParseStructureLikeDIE).
-  if (tag_decl_ctx->isCompleteDefinition() || tag_decl_ctx->isBeingDefined())
+  if (tag_decl_ctx->getDefinition() != nullptr || tag_decl_ctx->isBeingDefined())
     return;
 
   // We reach this point of the tag was present in the debug info as a
@@ -268,8 +285,8 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast,
   // gmodules case), we can complete the type by doing a full import.
 
   // If this type was not imported from an external AST, there's nothing to do.
-  CompilerType type = ast.GetTypeForDecl(tag_decl_ctx);
-  if (type && ast_importer.CanImport(type)) {
+  if (ast_importer.CanImport(tag_decl_ctx)) {
+    CompilerType type = ast.GetTypeForDecl(tag_decl_ctx);
     auto qual_type = ClangUtil::GetQualType(type);
     if (ast_importer.RequireCompleteType(qual_type))
       return;
@@ -281,7 +298,18 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast,
 
   // We don't have a type definition and/or the import failed. We must
   // forcefully complete the type to avoid crashes.
-  ForcefullyCompleteType(type);
+  ForcefullyCompleteType(ast.GetTypeForDecl(tag_decl_ctx));
+}
+
+void DWARFASTParserClang::RegisterDIE(DWARFDebugInfoEntry *die,
+                                      CompilerType type) {
+  if (clang::TagDecl *td = ClangUtil::GetAsTagDecl(type)) {
+    m_die_to_record_map[die] = td;
+  } else if (auto *od = ClangUtil::GetAsObjCDecl(type))
+    m_die_to_objc_interface_map[die] = od;
+  else {
+    assert(false && "Unknown Decl kind?");
+  }
 }
 
 ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
@@ -458,13 +486,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
   }
 
   // Set a bit that lets us know that we are currently parsing this
-  if (auto [it, inserted] =
-          dwarf->GetDIEToType().try_emplace(die.GetDIE(), DIE_IS_BEING_PARSED);
-      !inserted) {
-    if (it->getSecond() == nullptr || it->getSecond() == DIE_IS_BEING_PARSED)
-      return nullptr;
-    return it->getSecond()->shared_from_this();
-  }
+  if (auto *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()))
+    return type_ptr->shared_from_this();
 
   ParsedDWARFTypeAttributes attrs(die);
 
@@ -524,6 +547,13 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
       break;
     }
     UpdateSymbolContextScopeForType(sc, die, type_sp);
+
+    while (!m_to_complete.empty()) {
+      TypeToComplete to_complete = m_to_complete.back();
+      m_to_complete.pop_back();
+      CompleteRecordType(to_complete.die, to_complete.type.get(),
+                         to_complete.clang_type);
+    }
   }
   if (type_sp) {
     dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
@@ -1086,85 +1116,52 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
   if (!TypeSystemClang::IsCXXClassType(class_opaque_type))
     return {};
 
-  if (class_opaque_type.IsBeingDefined()) {
-    // We have a C++ member function with no children (this
-    // pointer!) and clang will get mad if we try and make
-    // a function that isn't well formed in the DWARF, so
-    // we will just skip it...
-    if (!is_static && !die.HasChildren())
-      return {true, nullptr};
-
-    const bool is_attr_used = false;
-    // Neither GCC 4.2 nor clang++ currently set a valid
-    // accessibility in the DWARF for C++ methods...
-    // Default to public for now...
-    const auto accessibility = attrs.accessibility == eAccessNone
-                                   ? eAccessPublic
-                                   : attrs.accessibility;
-
-    clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
-        class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
-        attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
-        is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
-        attrs.is_artificial);
-
-    if (cxx_method_decl) {
-      LinkDeclContextToDIE(cxx_method_decl, die);
-
-      ClangASTMetadata metadata;
-      metadata.SetUserID(die.GetID());
-
-      char const *object_pointer_name =
-          attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr;
-      if (object_pointer_name) {
-        metadata.SetObjectPtrName(object_pointer_name);
-        LLDB_LOGF(log,
-                  "Setting object pointer name: %s on method "
-                  "object %p.\n",
-                  object_pointer_name, static_cast<void *>(cxx_method_decl));
-      }
-      m_ast.SetMetadata(cxx_method_decl, metadata);
-    } else {
-      ignore_containing_context = true;
-    }
+  // We have a C++ member function with no children (this
+  // pointer!) and clang will get mad if we try and make
+  // a function that isn't well formed in the DWARF, so
+  // we will just skip it...
+  if (!is_static && !die.HasChildren())
+    return {true, nullptr};
+
+  const bool is_attr_used = false;
+  // Neither GCC 4.2 nor clang++ currently set a valid
+  // accessibility in the DWARF for C++ methods...
+  // Default to public for now...
+  const auto accessibility = attrs.accessibility == eAccessNone
+                                 ? eAccessPublic
+                                 : attrs.accessibility;
 
-    // Artificial methods are always handled even when we
-    // don't create a new declaration for them.
-    const bool type_handled = cxx_method_decl != nullptr || attrs.is_artificial;
+  clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
+      class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
+      attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
+      is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
+      attrs.is_artificial);
 
-    return {type_handled, nullptr};
-  }
+  if (cxx_method_decl) {
+    LinkDeclContextToDIE(cxx_method_decl, die);
 
-  // We were asked to parse the type for a method in a
-  // class, yet the class hasn't been asked to complete
-  // itself through the clang::ExternalASTSource protocol,
-  // so we need to just have the class complete itself and
-  // do things the right way, then our
-  // DIE should then have an entry in the
-  // dwarf->GetDIEToType() map. First
-  // we need to modify the dwarf->GetDIEToType() so it
-  // doesn't think we are trying to parse this DIE
-  // anymore...
-  dwarf->GetDIEToType().erase(die.GetDIE());
+    ClangASTMetadata metadata;
+    metadata.SetUserID(die.GetID());
 
-  // Now we get the full type to force our class type to
-  // complete itself using the clang::ExternalASTSource
-  // protocol which will parse all base classes and all
-  // methods (including the method for this DIE).
-  class_type->GetFullCompilerType();
+    char const *object_pointer_name =
+        attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr;
+    if (object_pointer_name) {
+      metadata.SetObjectPtrName(object_pointer_name);
+      LLDB_LOGF(log,
+                "Setting object pointer name: %s on method "
+                "object %p.\n",
+                object_pointer_name, static_cast<void *>(cxx_method_decl));
+    }
+    m_ast.SetMetadata(cxx_method_decl, metadata);
+  } else {
+    ignore_containing_context = true;
+  }
 
-  // The type for this DIE should have been filled in the
-  // function call above.
-  Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE());
-  if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
-    return {true, type_ptr->shared_from_this()};
+  // Artificial methods are always handled even when we
+  // don't create a new declaration for them.
+  const bool type_handled = cxx_method_decl != nullptr || attrs.is_artificial;
 
-  // The previous comment isn't actually true if the class wasn't
-  // resolved using the current method's parent DIE as source
-  // data. We need to ensure that we look up the method correctly
-  // in the class and then link the method's DIE to the unique
-  // CXXMethodDecl appropriately.
-  return {true, nullptr};
+  return {type_handled, nullptr};
 }
 
 TypeSP
@@ -1206,6 +1203,10 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
   const clang::Decl::Kind containing_decl_kind =
       containing_decl_ctx->getDeclKind();
 
+  PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(),
+                                 containing_decl_ctx, die,
+                                 attrs.name.GetCString());
+
   bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind);
   // Start off static. This will be set to false in
   // ParseChildParameters(...) if we find a "this" parameters as the
@@ -1633,6 +1634,30 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) {
   return qualified_name;
 }
 
+static void adjustArgPassing(TypeSystemClang &ast,
+                             ParsedDWARFTypeAttributes const &attrs,
+                             CompilerType const &clang_type) {
+  // If we made a clang type, set the trivial abi if applicable: We only
+  // do this for pass by value - which implies the Trivial ABI. There
+  // isn't a way to assert that something that would normally be pass by
+  // value is pass by reference, so we ignore that attribute if set.
+  if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_value) {
+    clang::CXXRecordDecl *record_decl =
+        ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
+    if (record_decl && record_decl->getDefinition()) {
+      record_decl->setHasTrivialSpecialMemberForCall();
+    }
+  }
+
+  if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_reference) {
+    clang::CXXRecordDecl *record_decl =
+        ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
+    if (record_decl)
+      record_decl->setArgPassingRestrictions(
+          clang::RecordArgPassingKind::CannotPassInRegs);
+  }
+}
+
 TypeSP
 DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
                                            const DWARFDIE &die,
@@ -1644,6 +1669,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
   LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU());
   Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
 
+  clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr);
+
+  const bool should_directly_complete = DirectlyCompleteType(decl_ctx, attrs);
   // UniqueDWARFASTType is large, so don't create a local variables on the
   // stack, put it on the heap. This function is often called recursively and
   // clang isn't good at sharing the stack space for variables in different
@@ -1806,7 +1834,6 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
   assert(tag_decl_kind != -1);
   UNUSED_IF_ASSERT_DISABLED(tag_decl_kind);
   bool clang_type_was_created = false;
-  clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr);
 
   PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(), decl_ctx, die,
                                  attrs.name.GetCString());
@@ -1851,20 +1878,31 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
 
     m_ast.SetMetadata(class_template_decl, metadata);
     m_ast.SetMetadata(class_specialization_decl, metadata);
+
+    RegisterDIE(die.GetDIE(), clang_type);
+    if (auto *source = llvm::dyn_cast_or_null<ImporterBackedASTSource>(
+            m_ast.getASTContext().getExternalSource()))
+      source->MarkRedeclChainsAsOutOfDate(m_ast.getASTContext());
   }
 
   if (!clang_type_was_created) {
     clang_type_was_created = true;
     clang_type = m_ast.CreateRecordType(
         decl_ctx, GetOwningClangModule(die), attrs.accessibility,
-        attrs.name.GetCString(), tag_decl_kind, attrs.class_language, &metadata,
-        attrs.exports_symbols);
+        attrs.name.GetCString(), tag_decl_kind, attrs.class_language,
+        &metadata, attrs.exports_symbols);
+    RegisterDIE(die.GetDIE(), clang_type);
+    if (!should_directly_complete)
+      if (auto *source = llvm::dyn_cast_or_null<ImporterBackedASTSource>(
+              m_ast.getASTContext().getExternalSource()))
+        source->MarkRedeclChainsAsOutOfDate(m_ast.getASTContext());
   }
 
   // Store a forward declaration to this class type in case any
   // parameters in any class methods need it for the clang types for
   // function prototypes.
-  LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die);
+  LinkDeclContextToDIE(GetClangDeclContextContainingDIE(die, nullptr), die);
+
   type_sp = dwarf->MakeType(
       die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID,
       Type::eEncodingIsUID, &attrs.decl, clang_type,
@@ -1882,10 +1920,6 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
                                            *unique_ast_entry_up);
 
   if (!attrs.is_forward_declaration) {
-    // Always start the definition for a class type so that if the class
-    // has child classes or types that require the class to be created
-    // for use as their decl contexts the class will be ready to accept
-    // these child definitions.
     if (!die.HasChildren()) {
       // No children for this struct/union/class, lets finish it
       if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) {
@@ -1918,19 +1952,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
           GetClangASTImporter().SetRecordLayout(record_decl, layout);
         }
       }
-    } else if (clang_type_was_created) {
-      // Start the definition if the class is not objective C since the
-      // underlying decls respond to isCompleteDefinition(). Objective
-      // C decls don't respond to isCompleteDefinition() so we can't
-      // start the declaration definition right away. For C++
-      // class/union/structs we want to start the definition in case the
-      // class is needed as the declaration context for a contained class
-      // or type without the need to complete that type..
-
+    } else if (clang_type_was_created && !should_directly_complete) {
       if (attrs.class_language != eLanguageTypeObjC &&
           attrs.class_language != eLanguageTypeObjC_plus_plus)
-        TypeSystemClang::StartTagDeclarationDefinition(clang_type);
-
       // Leave this as a forward declaration until we need to know the
       // details of the type. lldb_private::Type will automatically call
       // the SymbolFile virtual function
@@ -1946,29 +1970,11 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
       dwarf->GetForwardDeclCompilerTypeToDIE().try_emplace(
           ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(),
           *die.GetDIERef());
-      m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true);
     }
   }
 
-  // If we made a clang type, set the trivial abi if applicable: We only
-  // do this for pass by value - which implies the Trivial ABI. There
-  // isn't a way to assert that something that would normally be pass by
-  // value is pass by reference, so we ignore that attribute if set.
-  if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_value) {
-    clang::CXXRecordDecl *record_decl =
-        m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
-    if (record_decl && record_decl->getDefinition()) {
-      record_decl->setHasTrivialSpecialMemberForCall();
-    }
-  }
+  m_to_complete.push_back({clang_type, die, type_sp});
 
-  if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_reference) {
-    clang::CXXRecordDecl *record_decl =
-        m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
-    if (record_decl)
-      record_decl->setArgPassingRestrictions(
-          clang::RecordArgPassingKind::CannotPassInRegs);
-  }
   return type_sp;
 }
 
@@ -2175,73 +2181,81 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos(
 bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
                                              lldb_private::Type *type,
                                              CompilerType &clang_type) {
+  if (!m_currently_parsed_record_dies.insert(die.GetDIE()).second)
+    return true;
+
   const dw_tag_t tag = die.Tag();
   SymbolFileDWARF *dwarf = die.GetDWARF();
 
   ClangASTImporter::LayoutInfo layout_info;
   std::vector<DWARFDIE> contained_type_dies;
 
-  if (die.HasChildren()) {
-    const bool type_is_objc_object_or_interface =
-        TypeSystemClang::IsObjCObjectOrInterfaceType(clang_type);
-    if (type_is_objc_object_or_interface) {
-      // For objective C we don't start the definition when the class is
-      // created.
-      TypeSystemClang::StartTagDeclarationDefinition(clang_type);
-    }
-
-    AccessType default_accessibility = eAccessNone;
-    if (tag == DW_TAG_structure_type) {
-      default_accessibility = eAccessPublic;
-    } else if (tag == DW_TAG_union_type) {
-      default_accessibility = eAccessPublic;
-    } else if (tag == DW_TAG_class_type) {
-      default_accessibility = eAccessPrivate;
-    }
-
-    std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
-    // Parse members and base classes first
-    std::vector<DWARFDIE> member_function_dies;
-
-    DelayedPropertyList delayed_properties;
-    ParseChildMembers(die, clang_type, bases, member_function_dies,
-                      contained_type_dies, delayed_properties,
-                      default_accessibility, layout_info);
-
-    // Now parse any methods if there were any...
-    for (const DWARFDIE &die : member_function_dies)
-      dwarf->ResolveType(die);
-
-    if (type_is_objc_object_or_interface) {
-      ConstString class_name(clang_type.GetTypeName());
-      if (class_name) {
-        dwarf->GetObjCMethods(class_name, [&](DWARFDIE method_die) {
-          method_die.ResolveType();
-          return true;
-        });
+  ParsedDWARFTypeAttributes attrs(die);
+  if (attrs.is_forward_declaration)
+    return true;
 
-        for (DelayedAddObjCClassProperty &property : delayed_properties)
-          property.Finalize();
-      }
-    }
+  clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr);
 
-    if (!bases.empty()) {
-      // Make sure all base classes refer to complete types and not forward
-      // declarations. If we don't do this, clang will crash with an
-      // assertion in the call to clang_type.TransferBaseClasses()
-      for (const auto &base_class : bases) {
-        clang::TypeSourceInfo *type_source_info =
-            base_class->getTypeSourceInfo();
-        if (type_source_info)
-          TypeSystemClang::RequireCompleteType(
-              m_ast.GetType(type_source_info->getType()));
-      }
+  if (!DirectlyCompleteType(decl_ctx, attrs)) {
+    clang_type = m_ast.CreateRedeclaration(clang_type);
+    RegisterDIE(die.GetDIE(), clang_type);
+  }
+
+  TypeSystemClang::StartTagDeclarationDefinition(clang_type);
+
+  AccessType default_accessibility = eAccessNone;
+  if (tag == DW_TAG_structure_type) {
+    default_accessibility = eAccessPublic;
+  } else if (tag == DW_TAG_union_type) {
+    default_accessibility = eAccessPublic;
+  } else if (tag == DW_TAG_class_type) {
+    default_accessibility = eAccessPrivate;
+  }
+
+  std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
+  // Parse members and base classes first
+  std::vector<DWARFDIE> member_function_dies;
+
+  DelayedPropertyList delayed_properties;
+  ParseChildMembers(die, clang_type, bases, member_function_dies,
+                    contained_type_dies, delayed_properties,
+                    default_accessibility, layout_info);
+
+  // Now parse any methods if there were any...
+  for (const DWARFDIE &die : member_function_dies)
+    dwarf->ResolveType(die);
+
+  if (TypeSystemClang::IsObjCObjectOrInterfaceType(clang_type)) {
+    ConstString class_name(clang_type.GetTypeName());
+    if (class_name) {
+      dwarf->GetObjCMethods(class_name, [&](DWARFDIE method_die) {
+        method_die.ResolveType();
+        return true;
+      });
 
-      m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(),
-                                std::move(bases));
+      for (DelayedAddObjCClassProperty &property : delayed_properties)
+        property.Finalize();
     }
   }
 
+  if (!bases.empty()) {
+    // Make sure all base classes refer to complete types and not forward
+    // declarations. If we don't do this, clang will crash with an
+    // assertion in the call to clang_type.TransferBaseClasses()
+    for (const auto &base_class : bases) {
+      clang::TypeSourceInfo *type_source_info =
+          base_class->getTypeSourceInfo();
+      if (type_source_info)
+        TypeSystemClang::RequireCompleteType(
+            m_ast.GetType(type_source_info->getType()));
+    }
+
+    m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(),
+                              std::move(bases));
+  }
+
+  adjustArgPassing(m_ast, attrs, clang_type);
+
   m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType());
   TypeSystemClang::BuildIndirectFields(clang_type);
   TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
@@ -2293,10 +2307,6 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die,
   std::lock_guard<std::recursive_mutex> guard(
       dwarf->GetObjectFile()->GetModule()->GetMutex());
 
-  // Disable external storage for this type so we don't get anymore
-  // clang::ExternalASTSource queries for this type.
-  m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), false);
-
   if (!die)
     return false;
 
@@ -3673,6 +3683,13 @@ clang::DeclContext *DWARFASTParserClang::GetClangDeclContextContainingDIE(
 clang::DeclContext *
 DWARFASTParserClang::GetCachedClangDeclContextForDIE(const DWARFDIE &die) {
   if (die) {
+    DIEToRecordMap::iterator pos2 = m_die_to_record_map.find(die.GetDIE());
+    if (pos2 != m_die_to_record_map.end())
+      return pos2->second;
+    DIEToObjCInterfaceMap::iterator pos3 =
+        m_die_to_objc_interface_map.find(die.GetDIE());
+    if (pos3 != m_die_to_objc_interface_map.end())
+      return pos3->second;
     DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die.GetDIE());
     if (pos != m_die_to_decl_ctx.end())
       return pos->second;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index 7b5ddbaa2a6b5..50366bdd0e99e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -130,12 +130,30 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
       const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *, clang::Decl *>
       DIEToDeclMap;
 
+  using DIEToRecordMap =
+      llvm::DenseMap<const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *,
+                     clang::TagDecl *>;
+  using DIEToObjCInterfaceMap =
+      llvm::DenseMap<const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *,
+                     clang::ObjCInterfaceDecl *>;
+
   lldb_private::TypeSystemClang &m_ast;
   DIEToDeclMap m_die_to_decl;
   DIEToDeclContextMap m_die_to_decl_ctx;
   DeclContextToDIEMap m_decl_ctx_to_die;
   DIEToModuleMap m_die_to_module;
+  DIEToRecordMap m_die_to_record_map;
+  DIEToObjCInterfaceMap m_die_to_objc_interface_map;
   std::unique_ptr<lldb_private::ClangASTImporter> m_clang_ast_importer_up;
+
+  struct TypeToComplete {
+    lldb_private::CompilerType clang_type;
+    lldb_private::plugin::dwarf::DWARFDIE die;
+    lldb::TypeSP type;
+  };
+  std::vector<TypeToComplete> m_to_complete;
+  llvm::DenseSet<const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *>
+      m_currently_parsed_record_dies;
   /// @}
 
   clang::DeclContext *
@@ -228,6 +246,9 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
   void LinkDeclToDIE(clang::Decl *decl,
                      const lldb_private::plugin::dwarf::DWARFDIE &die);
 
+  void RegisterDIE(lldb_private::plugin::dwarf::DWARFDebugInfoEntry *die,
+                   lldb_private::CompilerType type);
+
   /// If \p type_sp is valid, calculate and set its symbol context scope, and
   /// update the type list for its backing symbol file.
   ///
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 30fd2b0c23271..35846b9270a54 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1623,6 +1623,9 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl(
   class_template_decl->init(template_cxx_decl);
   template_cxx_decl->setDescribedClassTemplate(class_template_decl);
   SetOwningModule(class_template_decl, owning_module);
+  ast.getInjectedClassNameType(
+      template_cxx_decl,
+      class_template_decl->getInjectedClassNameSpecialization());
 
   if (access_type != eAccessNone)
     class_template_decl->setAccess(
@@ -1683,6 +1686,7 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
       static_cast<TagDecl::TagKind>(kind));
   class_template_specialization_decl->setDeclContext(decl_ctx);
   class_template_specialization_decl->setInstantiationOf(class_template_decl);
+  ast.getTypeDeclType(class_template_specialization_decl, nullptr);
   class_template_specialization_decl->setTemplateArgs(
       TemplateArgumentList::CreateCopy(ast, args));
   class_template_specialization_decl->setDeclName(
@@ -2456,9 +2460,6 @@ bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast,
     if (tag_decl->isCompleteDefinition())
       return true;
 
-    if (!tag_decl->hasExternalLexicalStorage())
-      return false;
-
     ast_source->CompleteType(tag_decl);
 
     tag_decl = tag_decl->getDefinition();
@@ -2469,9 +2470,6 @@ bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast,
     if (objc_interface_decl->getDefinition())
       return true;
 
-    if (!objc_interface_decl->hasExternalLexicalStorage())
-      return false;
-
     ast_source->CompleteType(objc_interface_decl);
 
     objc_interface_decl = objc_interface_decl->getDefinition();
@@ -2631,35 +2629,14 @@ static const clang::RecordType *GetCompleteRecordType(clang::ASTContext *ast,
 
   // RecordType with no way of completing it, return the plain
   // TagType.
-  if (!cxx_record_decl || !cxx_record_decl->hasExternalLexicalStorage())
-    return tag_type;
-
-  const bool is_complete = cxx_record_decl->isCompleteDefinition();
-  const bool fields_loaded =
-      cxx_record_decl->hasLoadedFieldsFromExternalStorage();
-
-  // Already completed this type, nothing to be done.
-  if (is_complete && fields_loaded)
+  if (!cxx_record_decl)
     return tag_type;
 
-  if (!allow_completion)
+  clang::CXXRecordDecl *def = cxx_record_decl->getDefinition();
+  if (!def)
     return nullptr;
 
-  // Call the field_begin() accessor to for it to use the external source
-  // to load the fields...
-  //
-  // TODO: if we need to complete the type but have no external source,
-  // shouldn't we error out instead?
-  clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
-  if (external_ast_source) {
-    external_ast_source->CompleteType(cxx_record_decl);
-    if (cxx_record_decl->isCompleteDefinition()) {
-      cxx_record_decl->field_begin();
-      cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
-    }
-  }
-
-  return tag_type;
+  return llvm::dyn_cast_if_present<clang::RecordType>(def->getTypeForDecl());
 }
 
 /// Returns the clang::EnumType of the specified \ref qual_type. This
@@ -2678,31 +2655,17 @@ static const clang::EnumType *GetCompleteEnumType(clang::ASTContext *ast,
   auto *tag_decl = enum_type->getAsTagDecl();
   assert(tag_decl);
 
-  // Already completed, nothing to be done.
-  if (tag_decl->getDefinition())
-    return enum_type;
-
-  if (!allow_completion)
-    return nullptr;
-
-  // No definition but can't complete it, error out.
-  if (!tag_decl->hasExternalLexicalStorage())
-    return nullptr;
-
-  // We can't complete the type without an external source.
-  clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
-  if (!external_ast_source)
-    return nullptr;
+  if (clang::TagDecl *def = tag_decl->getDefinition())
+    return llvm::dyn_cast_if_present<clang::EnumType>(def->getTypeForDecl());
 
-  external_ast_source->CompleteType(tag_decl);
-  return enum_type;
+  return llvm::dyn_cast_if_present<clang::EnumType>(tag_decl->getTypeForDecl());
 }
 
 /// Returns the clang::ObjCObjectType of the specified \ref qual_type. This
 /// function will try to complete the type if necessary (and allowed
 /// by the specified \ref allow_completion). If we fail to return a *complete*
 /// type, returns nullptr.
-static const clang::ObjCObjectType *
+static const clang::Type *
 GetCompleteObjCObjectType(clang::ASTContext *ast, QualType qual_type,
                           bool allow_completion) {
   assert(qual_type->isObjCObjectType());
@@ -2719,22 +2682,9 @@ GetCompleteObjCObjectType(clang::ASTContext *ast, QualType qual_type,
     return objc_class_type;
 
   // Already complete, nothing to be done.
-  if (class_interface_decl->getDefinition())
-    return objc_class_type;
+  if (auto *def = class_interface_decl->getDefinition())
+    return def->getTypeForDecl();
 
-  if (!allow_completion)
-    return nullptr;
-
-  // No definition but can't complete it, error out.
-  if (!class_interface_decl->hasExternalLexicalStorage())
-    return nullptr;
-
-  // We can't complete the type without an external source.
-  clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
-  if (!external_ast_source)
-    return nullptr;
-
-  external_ast_source->CompleteType(class_interface_decl);
   return objc_class_type;
 }
 
@@ -2757,14 +2707,14 @@ static bool GetCompleteQualType(clang::ASTContext *ast,
   case clang::Type::Record: {
     if (const auto *RT =
             GetCompleteRecordType(ast, qual_type, allow_completion))
-      return !RT->isIncompleteType();
+      return true;
 
     return false;
   } break;
 
   case clang::Type::Enum: {
     if (const auto *ET = GetCompleteEnumType(ast, qual_type, allow_completion))
-      return !ET->isIncompleteType();
+      return true;
 
     return false;
   } break;
@@ -2772,7 +2722,7 @@ static bool GetCompleteQualType(clang::ASTContext *ast,
   case clang::Type::ObjCInterface: {
     if (const auto *OT =
             GetCompleteObjCObjectType(ast, qual_type, allow_completion))
-      return !OT->isIncompleteType();
+      return true;
 
     return false;
   } break;
@@ -3491,7 +3441,7 @@ bool TypeSystemClang::IsDefined(lldb::opaque_compiler_type_t type) {
   if (tag_type) {
     clang::TagDecl *tag_decl = tag_type->getDecl();
     if (tag_decl)
-      return tag_decl->isCompleteDefinition();
+      return tag_decl->getDefinition() != nullptr;
     return false;
   } else {
     const clang::ObjCObjectType *objc_class_type =
@@ -5448,6 +5398,7 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
             objc_class_type->getInterface();
 
         if (class_interface_decl) {
+          class_interface_decl = class_interface_decl->getDefinition();;
 
           clang::ObjCInterfaceDecl *superclass_interface_decl =
               class_interface_decl->getSuperClass();
@@ -8498,9 +8449,7 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition(
 
       if (!cxx_record_decl->isCompleteDefinition())
         cxx_record_decl->completeDefinition();
-      cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
-      cxx_record_decl->setHasExternalLexicalStorage(false);
-      cxx_record_decl->setHasExternalVisibleStorage(false);
+
       lldb_ast->SetCXXRecordDeclAccess(cxx_record_decl,
                                        clang::AccessSpecifier::AS_none);
       return true;
@@ -9128,25 +9077,25 @@ static OptionalClangModuleID GetModuleForDecl(clang::Decl *d) {
   return OptionalClangModuleID(d->getOwningModuleID());
 }
 
-void TypeSystemClang::CreateRedeclaration(CompilerType ct) {
+CompilerType TypeSystemClang::CreateRedeclaration(CompilerType ct) {
   // All the cases below just check for a specific declaration kind, create
   // a new declaration with matching data. We don't care about metadata which
   // should only be tracked in the first redeclaration and should be identical
   // for all redeclarations.
 
-  if (clang::ObjCInterfaceDecl *interface = GetAsObjCInterfaceDecl(ct)) {
+  if (clang::ObjCInterfaceDecl *interface = ClangUtil::GetAsObjCDecl(ct)) {
     clang::NamedDecl *res = CreateObjCDecl(
         interface->getName(), interface->getDeclContext()->getRedeclContext(),
         GetModuleForDecl(interface), /*isForwardDecl=*/false,
         interface->isImplicit());
     clang::ObjCInterfaceDecl *redecl = llvm::cast<ObjCInterfaceDecl>(res);
     ConnectRedeclToPrev(*this, interface, redecl);
-    return;
+    return GetTypeForDecl(redecl);
   }
 
   clang::TagDecl *tag_decl = ClangUtil::GetAsTagDecl(ct);
   if (!tag_decl)
-    return;
+    return {};
 
   if (clang::EnumDecl *enum_decl = dyn_cast<EnumDecl>(tag_decl)) {
     Declaration decl;
@@ -9156,7 +9105,7 @@ void TypeSystemClang::CreateRedeclaration(CompilerType ct) {
         GetModuleForDecl(enum_decl), decl, GetType(enum_decl->getIntegerType()),
         enum_decl->isScoped());
     ConnectRedeclToPrev(*this, enum_decl, redecl);
-    return;
+    return GetTypeForDecl(redecl);
   }
 
   if (auto *template_decl =
@@ -9172,7 +9121,7 @@ void TypeSystemClang::CreateRedeclaration(CompilerType ct) {
         template_decl->getSpecializedTemplate(),
         llvm::to_underlying(tag_decl->getTagKind()), template_infos);
     ConnectRedeclToPrev(*this, template_decl, redecl);
-    return;
+    return GetType(clang::QualType(redecl->getTypeForDecl(), 0U));
   }
 
   assert(llvm::isa<RecordDecl>(tag_decl));
@@ -9183,7 +9132,7 @@ void TypeSystemClang::CreateRedeclaration(CompilerType ct) {
       nullptr);
   clang::TagDecl *redecl = llvm::cast<TagDecl>(redecl_record);
   ConnectRedeclToPrev(*this, tag_decl, redecl);
-  return;
+  return GetTypeForDecl(redecl);
 }
 
 DWARFASTParser *TypeSystemClang::GetDWARFParser() {
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 09752124b7453..1f02cd7b13f79 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -581,7 +581,7 @@ class TypeSystemClang : public TypeSystem {
   /// \param type The type which declaration should be redeclared. Has to be
   /// an Objective-C interface type (or Objective-C type), RecordType or
   /// EnumType.
-  void CreateRedeclaration(CompilerType ct);
+  CompilerType CreateRedeclaration(CompilerType ct);
 
   bool LayoutRecordType(
       const clang::RecordDecl *record_decl, uint64_t &size, uint64_t &alignment,
diff --git a/lldb/test/API/lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py b/lldb/test/API/lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py
index a6e419b7fcdfa..7a23559998b3e 100644
--- a/lldb/test/API/lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py
+++ b/lldb/test/API/lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py
@@ -6,7 +6,7 @@
 
 
 class TestCase(TestBase):
-    @unittest.expectedFailure  # The fix for this was reverted due to llvm.org/PR52257
+    @expectedFailureAll(setting=('plugin.typesystem.clang.experimental-redecl-completion', 'false'))
     def test(self):
         self.build()
         self.dbg.CreateTarget(self.getBuildArtifact("a.out"))

>From caacb57a46f34bf663fa5ab2190b361ce29b255b Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Fri, 14 Jun 2024 12:48:33 +0100
Subject: [PATCH 14/14] fixup! clang-format

---
 .../Clang/ClangASTImporter.cpp                |  7 ++--
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 36 +++++++++----------
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  9 ++---
 3 files changed, 25 insertions(+), 27 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 913fd50d4c9af..722df69615368 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -836,10 +836,9 @@ bool ClangASTImporter::CompleteObjCInterfaceDecl(
   if (result)
     return true;
 
-  llvm::handleAllErrors(result.takeError(),
-                        [](const clang::ASTImportError &e) {
-                          llvm::errs() << "ERR: " << e.toString() << "\n";
-                        });
+  llvm::handleAllErrors(result.takeError(), [](const clang::ASTImportError &e) {
+    llvm::errs() << "ERR: " << e.toString() << "\n";
+  });
 
   return false;
 }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 2153c1d300cf8..4eb3a96faaa59 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -277,7 +277,8 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast,
 
   // We have already completed the type, or we have found its definition and are
   // ready to complete it later (cf. ParseStructureLikeDIE).
-  if (tag_decl_ctx->getDefinition() != nullptr || tag_decl_ctx->isBeingDefined())
+  if (tag_decl_ctx->getDefinition() != nullptr ||
+      tag_decl_ctx->isBeingDefined())
     return;
 
   // We reach this point of the tag was present in the debug info as a
@@ -1127,9 +1128,8 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
   // Neither GCC 4.2 nor clang++ currently set a valid
   // accessibility in the DWARF for C++ methods...
   // Default to public for now...
-  const auto accessibility = attrs.accessibility == eAccessNone
-                                 ? eAccessPublic
-                                 : attrs.accessibility;
+  const auto accessibility =
+      attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility;
 
   clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
       class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
@@ -1889,8 +1889,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
     clang_type_was_created = true;
     clang_type = m_ast.CreateRecordType(
         decl_ctx, GetOwningClangModule(die), attrs.accessibility,
-        attrs.name.GetCString(), tag_decl_kind, attrs.class_language,
-        &metadata, attrs.exports_symbols);
+        attrs.name.GetCString(), tag_decl_kind, attrs.class_language, &metadata,
+        attrs.exports_symbols);
     RegisterDIE(die.GetDIE(), clang_type);
     if (!should_directly_complete)
       if (auto *source = llvm::dyn_cast_or_null<ImporterBackedASTSource>(
@@ -1955,15 +1955,15 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
     } else if (clang_type_was_created && !should_directly_complete) {
       if (attrs.class_language != eLanguageTypeObjC &&
           attrs.class_language != eLanguageTypeObjC_plus_plus)
-      // Leave this as a forward declaration until we need to know the
-      // details of the type. lldb_private::Type will automatically call
-      // the SymbolFile virtual function
-      // "SymbolFileDWARF::CompleteType(Type *)" When the definition
-      // needs to be defined.
-      assert(!dwarf->GetForwardDeclCompilerTypeToDIE().count(
-                 ClangUtil::RemoveFastQualifiers(clang_type)
-                     .GetOpaqueQualType()) &&
-             "Type already in the forward declaration map!");
+        // Leave this as a forward declaration until we need to know the
+        // details of the type. lldb_private::Type will automatically call
+        // the SymbolFile virtual function
+        // "SymbolFileDWARF::CompleteType(Type *)" When the definition
+        // needs to be defined.
+        assert(!dwarf->GetForwardDeclCompilerTypeToDIE().count(
+                   ClangUtil::RemoveFastQualifiers(clang_type)
+                       .GetOpaqueQualType()) &&
+               "Type already in the forward declaration map!");
       // Can't assume m_ast.GetSymbolFile() is actually a
       // SymbolFileDWARF, it can be a SymbolFileDWARFDebugMap for Apple
       // binaries.
@@ -2243,15 +2243,13 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
     // declarations. If we don't do this, clang will crash with an
     // assertion in the call to clang_type.TransferBaseClasses()
     for (const auto &base_class : bases) {
-      clang::TypeSourceInfo *type_source_info =
-          base_class->getTypeSourceInfo();
+      clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo();
       if (type_source_info)
         TypeSystemClang::RequireCompleteType(
             m_ast.GetType(type_source_info->getType()));
     }
 
-    m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(),
-                              std::move(bases));
+    m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), std::move(bases));
   }
 
   adjustArgPassing(m_ast, attrs, clang_type);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 35846b9270a54..c88854f275d48 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2665,9 +2665,9 @@ static const clang::EnumType *GetCompleteEnumType(clang::ASTContext *ast,
 /// function will try to complete the type if necessary (and allowed
 /// by the specified \ref allow_completion). If we fail to return a *complete*
 /// type, returns nullptr.
-static const clang::Type *
-GetCompleteObjCObjectType(clang::ASTContext *ast, QualType qual_type,
-                          bool allow_completion) {
+static const clang::Type *GetCompleteObjCObjectType(clang::ASTContext *ast,
+                                                    QualType qual_type,
+                                                    bool allow_completion) {
   assert(qual_type->isObjCObjectType());
   assert(ast);
 
@@ -5398,7 +5398,8 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
             objc_class_type->getInterface();
 
         if (class_interface_decl) {
-          class_interface_decl = class_interface_decl->getDefinition();;
+          class_interface_decl = class_interface_decl->getDefinition();
+          ;
 
           clang::ObjCInterfaceDecl *superclass_interface_decl =
               class_interface_decl->getSuperClass();



More information about the lldb-commits mailing list