Commit bc6ebc6f25

Andrew Kelley <andrew@ziglang.org>
2024-04-26 23:41:45
libcxxabi: update to LLVM 18
release/18.x branch, commit 78b99c73ee4b96fe9ce0e294d4632326afb2db42
1 parent 6295415
lib/libcxxabi/include/cxxabi.h
@@ -36,6 +36,9 @@ class type_info; // forward declaration
 
 // runtime routines use C calling conventions, but are in __cxxabiv1 namespace
 namespace __cxxabiv1 {
+
+struct __cxa_exception;
+
 extern "C"  {
 
 // 2.4.2 Allocating the Exception Object
@@ -43,11 +46,19 @@ extern _LIBCXXABI_FUNC_VIS void *
 __cxa_allocate_exception(size_t thrown_size) throw();
 extern _LIBCXXABI_FUNC_VIS void
 __cxa_free_exception(void *thrown_exception) throw();
+// This function is an LLVM extension, which mirrors the same extension in libsupc++ and libcxxrt
+extern _LIBCXXABI_FUNC_VIS __cxa_exception*
+__cxa_init_primary_exception(void* object, std::type_info* tinfo, void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw();
 
 // 2.4.3 Throwing the Exception Object
 extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
 __cxa_throw(void *thrown_exception, std::type_info *tinfo,
+#ifdef __USING_WASM_EXCEPTIONS__
+            // In Wasm, a destructor returns its argument
+            void *(_LIBCXXABI_DTOR_FUNC *dest)(void *));
+#else
             void (_LIBCXXABI_DTOR_FUNC *dest)(void *));
+#endif
 
 // 2.5.3 Exception Handlers
 extern _LIBCXXABI_FUNC_VIS void *
lib/libcxxabi/src/demangle/DemangleConfig.h
@@ -19,7 +19,7 @@
 #include "../abort_message.h"
 #endif
 
-#include <ciso646>
+#include <version>
 
 #ifdef _MSC_VER
 // snprintf is implemented in VS 2015
@@ -99,6 +99,11 @@
 #define DEMANGLE_FALLTHROUGH
 #endif
 
+#ifndef DEMANGLE_ASSERT
+#include <cassert>
+#define DEMANGLE_ASSERT(__expr, __msg) assert((__expr) && (__msg))
+#endif
+
 #define DEMANGLE_NAMESPACE_BEGIN namespace { namespace itanium_demangle {
 #define DEMANGLE_NAMESPACE_END } }
 
lib/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -21,7 +21,6 @@
 #include "Utility.h"
 #include <__cxxabi_config.h>
 #include <algorithm>
-#include <cassert>
 #include <cctype>
 #include <cstdio>
 #include <cstdlib>
@@ -61,13 +60,13 @@ template <class T, size_t N> class PODSmallVector {
     if (isInline()) {
       auto *Tmp = static_cast<T *>(std::malloc(NewCap * sizeof(T)));
       if (Tmp == nullptr)
-        std::terminate();
+        std::abort();
       std::copy(First, Last, Tmp);
       First = Tmp;
     } else {
       First = static_cast<T *>(std::realloc(First, NewCap * sizeof(T)));
       if (First == nullptr)
-        std::terminate();
+        std::abort();
     }
     Last = First + S;
     Cap = First + NewCap;
@@ -129,12 +128,12 @@ public:
 
   // NOLINTNEXTLINE(readability-identifier-naming)
   void pop_back() {
-    assert(Last != First && "Popping empty vector!");
+    DEMANGLE_ASSERT(Last != First, "Popping empty vector!");
     --Last;
   }
 
-  void dropBack(size_t Index) {
-    assert(Index <= size() && "dropBack() can't expand!");
+  void shrinkToSize(size_t Index) {
+    DEMANGLE_ASSERT(Index <= size(), "shrinkToSize() can't expand!");
     Last = First + Index;
   }
 
@@ -144,11 +143,11 @@ public:
   bool empty() const { return First == Last; }
   size_t size() const { return static_cast<size_t>(Last - First); }
   T &back() {
-    assert(Last != First && "Calling back() on empty vector!");
+    DEMANGLE_ASSERT(Last != First, "Calling back() on empty vector!");
     return *(Last - 1);
   }
   T &operator[](size_t Index) {
-    assert(Index < size() && "Invalid access!");
+    DEMANGLE_ASSERT(Index < size(), "Invalid access!");
     return *(begin() + Index);
   }
   void clear() { Last = First; }
@@ -534,6 +533,23 @@ public:
   }
 };
 
+class TransformedType : public Node {
+  std::string_view Transform;
+  Node *BaseType;
+public:
+  TransformedType(std::string_view Transform_, Node *BaseType_)
+      : Node(KTransformedType), Transform(Transform_), BaseType(BaseType_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Transform, BaseType); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    OB += Transform;
+    OB += '(';
+    BaseType->print(OB);
+    OB += ')';
+  }
+};
+
 struct AbiTagAttr : Node {
   Node *Base;
   std::string_view Tag;
@@ -873,26 +889,53 @@ public:
   }
 };
 
+/// Represents the explicitly named object parameter.
+/// E.g.,
+/// \code{.cpp}
+///   struct Foo {
+///     void bar(this Foo && self);
+///   };
+/// \endcode
+class ExplicitObjectParameter final : public Node {
+  Node *Base;
+
+public:
+  ExplicitObjectParameter(Node *Base_)
+      : Node(KExplicitObjectParameter), Base(Base_) {
+    DEMANGLE_ASSERT(
+        Base != nullptr,
+        "Creating an ExplicitObjectParameter without a valid Base Node.");
+  }
+
+  template <typename Fn> void match(Fn F) const { F(Base); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    OB += "this ";
+    Base->print(OB);
+  }
+};
+
 class FunctionEncoding final : public Node {
   const Node *Ret;
   const Node *Name;
   NodeArray Params;
   const Node *Attrs;
+  const Node *Requires;
   Qualifiers CVQuals;
   FunctionRefQual RefQual;
 
 public:
   FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_,
-                   const Node *Attrs_, Qualifiers CVQuals_,
-                   FunctionRefQual RefQual_)
+                   const Node *Attrs_, const Node *Requires_,
+                   Qualifiers CVQuals_, FunctionRefQual RefQual_)
       : Node(KFunctionEncoding,
              /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
              /*FunctionCache=*/Cache::Yes),
         Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),
-        CVQuals(CVQuals_), RefQual(RefQual_) {}
+        Requires(Requires_), CVQuals(CVQuals_), RefQual(RefQual_) {}
 
   template<typename Fn> void match(Fn F) const {
-    F(Ret, Name, Params, Attrs, CVQuals, RefQual);
+    F(Ret, Name, Params, Attrs, Requires, CVQuals, RefQual);
   }
 
   Qualifiers getCVQuals() const { return CVQuals; }
@@ -935,6 +978,11 @@ public:
 
     if (Attrs != nullptr)
       Attrs->print(OB);
+
+    if (Requires != nullptr) {
+      OB += " requires ";
+      Requires->print(OB);
+    }
   }
 };
 
@@ -1006,6 +1054,24 @@ struct NestedName : Node {
   }
 };
 
+struct MemberLikeFriendName : Node {
+  Node *Qual;
+  Node *Name;
+
+  MemberLikeFriendName(Node *Qual_, Node *Name_)
+      : Node(KMemberLikeFriendName), Qual(Qual_), Name(Name_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Qual, Name); }
+
+  std::string_view getBaseName() const override { return Name->getBaseName(); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    Qual->print(OB);
+    OB += "::friend ";
+    Name->print(OB);
+  }
+};
+
 struct ModuleName : Node {
   ModuleName *Parent;
   Node *Name;
@@ -1171,6 +1237,24 @@ public:
   }
 };
 
+class TemplateParamQualifiedArg final : public Node {
+  Node *Param;
+  Node *Arg;
+
+public:
+  TemplateParamQualifiedArg(Node *Param_, Node *Arg_)
+      : Node(KTemplateParamQualifiedArg), Param(Param_), Arg(Arg_) {}
+
+  template <typename Fn> void match(Fn F) const { F(Param, Arg); }
+
+  Node *getArg() { return Arg; }
+
+  void printLeft(OutputBuffer &OB) const override {
+    // Don't print Param to keep the output consistent.
+    Arg->print(OB);
+  }
+};
+
 /// A template type parameter declaration, 'typename T'.
 class TypeTemplateParamDecl final : public Node {
   Node *Name;
@@ -1186,6 +1270,26 @@ public:
   void printRight(OutputBuffer &OB) const override { Name->print(OB); }
 };
 
+/// A constrained template type parameter declaration, 'C<U> T'.
+class ConstrainedTypeTemplateParamDecl final : public Node {
+  Node *Constraint;
+  Node *Name;
+
+public:
+  ConstrainedTypeTemplateParamDecl(Node *Constraint_, Node *Name_)
+      : Node(KConstrainedTypeTemplateParamDecl, Cache::Yes),
+        Constraint(Constraint_), Name(Name_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Constraint, Name); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    Constraint->print(OB);
+    OB += " ";
+  }
+
+  void printRight(OutputBuffer &OB) const override { Name->print(OB); }
+};
+
 /// A non-type template parameter declaration, 'int N'.
 class NonTypeTemplateParamDecl final : public Node {
   Node *Name;
@@ -1214,13 +1318,14 @@ public:
 class TemplateTemplateParamDecl final : public Node {
   Node *Name;
   NodeArray Params;
+  Node *Requires;
 
 public:
-  TemplateTemplateParamDecl(Node *Name_, NodeArray Params_)
+  TemplateTemplateParamDecl(Node *Name_, NodeArray Params_, Node *Requires_)
       : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_),
-        Params(Params_) {}
+        Params(Params_), Requires(Requires_) {}
 
-  template<typename Fn> void match(Fn F) const { F(Name, Params); }
+  template <typename Fn> void match(Fn F) const { F(Name, Params, Requires); }
 
   void printLeft(OutputBuffer &OB) const override {
     ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
@@ -1229,7 +1334,13 @@ public:
     OB += "> typename ";
   }
 
-  void printRight(OutputBuffer &OB) const override { Name->print(OB); }
+  void printRight(OutputBuffer &OB) const override {
+    Name->print(OB);
+    if (Requires != nullptr) {
+      OB += " requires ";
+      Requires->print(OB);
+    }
+  }
 };
 
 /// A template parameter pack declaration, 'typename ...T'.
@@ -1326,7 +1437,7 @@ public:
 
 /// A variadic template argument. This node represents an occurrence of
 /// J<something>E in some <template-args>. It isn't itself unexpanded, unless
-/// one of it's Elements is. The parser inserts a ParameterPack into the
+/// one of its Elements is. The parser inserts a ParameterPack into the
 /// TemplateParams table if the <template-args> this pack belongs to apply to an
 /// <encoding>.
 class TemplateArgumentPack final : public Node {
@@ -1392,11 +1503,13 @@ public:
 
 class TemplateArgs final : public Node {
   NodeArray Params;
+  Node *Requires;
 
 public:
-  TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}
+  TemplateArgs(NodeArray Params_, Node *Requires_)
+      : Node(KTemplateArgs), Params(Params_), Requires(Requires_) {}
 
-  template<typename Fn> void match(Fn F) const { F(Params); }
+  template<typename Fn> void match(Fn F) const { F(Params, Requires); }
 
   NodeArray getParams() { return Params; }
 
@@ -1405,6 +1518,7 @@ public:
     OB += "<";
     Params.printWithComma(OB);
     OB += ">";
+    // Don't print the requires clause to keep the output simple.
   }
 };
 
@@ -1589,7 +1703,7 @@ public:
     std::string_view SV = ExpandedSpecialSubstitution::getBaseName();
     if (isInstantiation()) {
       // The instantiations are typedefs that drop the "basic_" prefix.
-      assert(starts_with(SV, "basic_"));
+      DEMANGLE_ASSERT(starts_with(SV, "basic_"), "");
       SV.remove_prefix(sizeof("basic_") - 1);
     }
     return SV;
@@ -1655,17 +1769,21 @@ public:
 
 class ClosureTypeName : public Node {
   NodeArray TemplateParams;
+  const Node *Requires1;
   NodeArray Params;
+  const Node *Requires2;
   std::string_view Count;
 
 public:
-  ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,
+  ClosureTypeName(NodeArray TemplateParams_, const Node *Requires1_,
+                  NodeArray Params_, const Node *Requires2_,
                   std::string_view Count_)
       : Node(KClosureTypeName), TemplateParams(TemplateParams_),
-        Params(Params_), Count(Count_) {}
+        Requires1(Requires1_), Params(Params_), Requires2(Requires2_),
+        Count(Count_) {}
 
   template<typename Fn> void match(Fn F) const {
-    F(TemplateParams, Params, Count);
+    F(TemplateParams, Requires1, Params, Requires2, Count);
   }
 
   void printDeclarator(OutputBuffer &OB) const {
@@ -1675,12 +1793,22 @@ public:
       TemplateParams.printWithComma(OB);
       OB += ">";
     }
+    if (Requires1 != nullptr) {
+      OB += " requires ";
+      Requires1->print(OB);
+      OB += " ";
+    }
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
+    if (Requires2 != nullptr) {
+      OB += " requires ";
+      Requires2->print(OB);
+    }
   }
 
   void printLeft(OutputBuffer &OB) const override {
+    // FIXME: This demangling is not particularly readable.
     OB += "\'lambda";
     OB += Count;
     OB += "\'";
@@ -2309,6 +2437,95 @@ public:
   }
 };
 
+class RequiresExpr : public Node {
+  NodeArray Parameters;
+  NodeArray Requirements;
+public:
+  RequiresExpr(NodeArray Parameters_, NodeArray Requirements_)
+      : Node(KRequiresExpr), Parameters(Parameters_),
+        Requirements(Requirements_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Parameters, Requirements); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    OB += "requires";
+    if (!Parameters.empty()) {
+      OB += ' ';
+      OB.printOpen();
+      Parameters.printWithComma(OB);
+      OB.printClose();
+    }
+    OB += ' ';
+    OB.printOpen('{');
+    for (const Node *Req : Requirements) {
+      Req->print(OB);
+    }
+    OB += ' ';
+    OB.printClose('}');
+  }
+};
+
+class ExprRequirement : public Node {
+  const Node *Expr;
+  bool IsNoexcept;
+  const Node *TypeConstraint;
+public:
+  ExprRequirement(const Node *Expr_, bool IsNoexcept_,
+                  const Node *TypeConstraint_)
+      : Node(KExprRequirement), Expr(Expr_), IsNoexcept(IsNoexcept_),
+        TypeConstraint(TypeConstraint_) {}
+
+  template <typename Fn> void match(Fn F) const {
+    F(Expr, IsNoexcept, TypeConstraint);
+  }
+
+  void printLeft(OutputBuffer &OB) const override {
+    OB += " ";
+    if (IsNoexcept || TypeConstraint)
+      OB.printOpen('{');
+    Expr->print(OB);
+    if (IsNoexcept || TypeConstraint)
+      OB.printClose('}');
+    if (IsNoexcept)
+      OB += " noexcept";
+    if (TypeConstraint) {
+      OB += " -> ";
+      TypeConstraint->print(OB);
+    }
+    OB += ';';
+  }
+};
+
+class TypeRequirement : public Node {
+  const Node *Type;
+public:
+  TypeRequirement(const Node *Type_)
+      : Node(KTypeRequirement), Type(Type_) {}
+
+  template <typename Fn> void match(Fn F) const { F(Type); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    OB += " typename ";
+    Type->print(OB);
+    OB += ';';
+  }
+};
+
+class NestedRequirement : public Node {
+  const Node *Constraint;
+public:
+  NestedRequirement(const Node *Constraint_)
+      : Node(KNestedRequirement), Constraint(Constraint_) {}
+
+  template <typename Fn> void match(Fn F) const { F(Constraint); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    OB += " requires ";
+    Constraint->print(OB);
+    OB += ';';
+  }
+};
+
 template <class Float> struct FloatData;
 
 namespace float_literal_impl {
@@ -2377,7 +2594,7 @@ void Node::visit(Fn F) const {
     return F(static_cast<const X *>(this));
 #include "ItaniumNodes.def"
   }
-  assert(0 && "unknown mangling node kind");
+  DEMANGLE_ASSERT(0, "unknown mangling node kind");
 }
 
 /// Determine the kind of a node from its type.
@@ -2403,6 +2620,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
   // table.
   PODSmallVector<Node *, 32> Subs;
 
+  // A list of template argument values corresponding to a template parameter
+  // list.
   using TemplateParamList = PODSmallVector<Node *, 8>;
 
   class ScopedTemplateParamList {
@@ -2417,9 +2636,11 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
       Parser->TemplateParams.push_back(&Params);
     }
     ~ScopedTemplateParamList() {
-      assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists);
-      Parser->TemplateParams.dropBack(OldNumTemplateParamLists);
+      DEMANGLE_ASSERT(Parser->TemplateParams.size() >= OldNumTemplateParamLists,
+                      "");
+      Parser->TemplateParams.shrinkToSize(OldNumTemplateParamLists);
     }
+    TemplateParamList *params() { return &Params; }
   };
 
   // Template parameter table. Like the above, but referenced like "T42_".
@@ -2434,12 +2655,31 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
   // parameter list, the corresponding parameter list pointer will be null.
   PODSmallVector<TemplateParamList *, 4> TemplateParams;
 
+  class SaveTemplateParams {
+    AbstractManglingParser *Parser;
+    decltype(TemplateParams) OldParams;
+    decltype(OuterTemplateParams) OldOuterParams;
+
+  public:
+    SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
+      OldParams = std::move(Parser->TemplateParams);
+      OldOuterParams = std::move(Parser->OuterTemplateParams);
+      Parser->TemplateParams.clear();
+      Parser->OuterTemplateParams.clear();
+    }
+    ~SaveTemplateParams() {
+      Parser->TemplateParams = std::move(OldParams);
+      Parser->OuterTemplateParams = std::move(OldOuterParams);
+    }
+  };
+
   // Set of unresolved forward <template-param> references. These can occur in a
   // conversion operator's type, and are resolved in the enclosing <encoding>.
   PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs;
 
   bool TryToParseTemplateArgs = true;
   bool PermitForwardTemplateReferences = false;
+  bool InConstraintExpr = false;
   size_t ParsingLambdaParamsAtLevel = (size_t)-1;
 
   unsigned NumSyntheticTemplateParameters[3] = {};
@@ -2478,10 +2718,10 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
   }
 
   NodeArray popTrailingNodeArray(size_t FromPosition) {
-    assert(FromPosition <= Names.size());
+    DEMANGLE_ASSERT(FromPosition <= Names.size(), "");
     NodeArray res =
         makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
-    Names.dropBack(FromPosition);
+    Names.shrinkToSize(FromPosition);
     return res;
   }
 
@@ -2519,11 +2759,16 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
   bool parseSeqId(size_t *Out);
   Node *parseSubstitution();
   Node *parseTemplateParam();
-  Node *parseTemplateParamDecl();
+  Node *parseTemplateParamDecl(TemplateParamList *Params);
   Node *parseTemplateArgs(bool TagTemplates = false);
   Node *parseTemplateArg();
 
-  /// Parse the <expr> production.
+  bool isTemplateParamDecl() {
+    return look() == 'T' &&
+           std::string_view("yptnk").find(look(1)) != std::string_view::npos;
+  }
+
+  /// Parse the <expression> production.
   Node *parseExpr();
   Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec);
   Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec);
@@ -2536,6 +2781,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
   Node *parseFoldExpr();
   Node *parsePointerToMemberConversionExpr(Node::Prec Prec);
   Node *parseSubobjectExpr();
+  Node *parseConstraintExpr();
+  Node *parseRequiresExpr();
 
   /// Parse the <type> production.
   Node *parseType();
@@ -2547,7 +2794,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
   Node *parseClassEnumType();
   Node *parseQualifiedType();
 
-  Node *parseEncoding();
+  Node *parseEncoding(bool ParseParams = true);
   bool parseCallOffset();
   Node *parseSpecialName();
 
@@ -2559,6 +2806,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
     Qualifiers CVQualifiers = QualNone;
     FunctionRefQual ReferenceQualifier = FrefQualNone;
     size_t ForwardTemplateRefsBegin;
+    bool HasExplicitObjectParameter = false;
 
     NameState(AbstractManglingParser *Enclosing)
         : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}
@@ -2574,7 +2822,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
         return true;
       ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx];
     }
-    ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
+    ForwardTemplateRefs.shrinkToSize(State.ForwardTemplateRefsBegin);
     return false;
   }
 
@@ -2638,8 +2886,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
     std::string_view getSymbol() const {
       std::string_view Res = Name;
       if (Kind < Unnameable) {
-        assert(starts_with(Res, "operator") &&
-               "operator name does not start with 'operator'");
+        DEMANGLE_ASSERT(starts_with(Res, "operator"),
+                        "operator name does not start with 'operator'");
         Res.remove_prefix(sizeof("operator") - 1);
         if (starts_with(Res, ' '))
           Res.remove_prefix(1);
@@ -2663,7 +2911,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
   Node *parseDestructorName();
 
   /// Top-level entry point into the parser.
-  Node *parse();
+  Node *parse(bool ParseParams = true);
 };
 
 const char* parse_discriminator(const char* first, const char* last);
@@ -2727,6 +2975,10 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
     return make<LocalName>(Encoding, StringLitName);
   }
 
+  // The template parameters of the inner name are unrelated to those of the
+  // enclosing context.
+  SaveTemplateParams SaveTemplateParamsScope(this);
+
   if (consumeIf('d')) {
     parseNumber(true);
     if (!consumeIf('_'))
@@ -2782,9 +3034,9 @@ AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State,
   return Res;
 }
 
-// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>]
+// <unqualified-name> ::= [<module-name>] F? L? <operator-name> [<abi-tags>]
 //                    ::= [<module-name>] <ctor-dtor-name> [<abi-tags>]
-//                    ::= [<module-name>] L? <source-name> [<abi-tags>]
+//                    ::= [<module-name>] F? L? <source-name> [<abi-tags>]
 //                    ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>]
 //			# structured binding declaration
 //                    ::= [<module-name>] L? DC <source-name>+ E
@@ -2794,6 +3046,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
   if (getDerived().parseModuleNameOpt(Module))
     return nullptr;
 
+  bool IsMemberLikeFriend = Scope && consumeIf('F');
+
   consumeIf('L');
 
   Node *Result;
@@ -2824,7 +3078,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
     Result = make<ModuleEntity>(Module, Result);
   if (Result != nullptr)
     Result = getDerived().parseAbiTags(Result);
-  if (Result != nullptr && Scope != nullptr)
+  if (Result != nullptr && IsMemberLikeFriend)
+    Result = make<MemberLikeFriendName>(Scope, Result);
+  else if (Result != nullptr && Scope != nullptr)
     Result = make<NestedName>(Scope, Result);
 
   return Result;
@@ -2856,7 +3112,8 @@ bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt(
 //
 // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
 //
-// <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters
+// <lambda-sig> ::= <template-param-decl>* [Q <requires-clause expression>]
+//                  <parameter type>+  # or "v" if the lambda has no parameters
 template <typename Derived, typename Alloc>
 Node *
 AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
@@ -2877,10 +3134,10 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
     ScopedTemplateParamList LambdaTemplateParams(this);
 
     size_t ParamsBegin = Names.size();
-    while (look() == 'T' &&
-           std::string_view("yptn").find(look(1)) != std::string_view::npos) {
-      Node *T = parseTemplateParamDecl();
-      if (!T)
+    while (getDerived().isTemplateParamDecl()) {
+      Node *T =
+          getDerived().parseTemplateParamDecl(LambdaTemplateParams.params());
+      if (T == nullptr)
         return nullptr;
       Names.push_back(T);
     }
@@ -2911,20 +3168,38 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
     if (TempParams.empty())
       TemplateParams.pop_back();
 
-    if (!consumeIf("vE")) {
+    Node *Requires1 = nullptr;
+    if (consumeIf('Q')) {
+      Requires1 = getDerived().parseConstraintExpr();
+      if (Requires1 == nullptr)
+        return nullptr;
+    }
+
+    if (!consumeIf("v")) {
       do {
         Node *P = getDerived().parseType();
         if (P == nullptr)
           return nullptr;
         Names.push_back(P);
-      } while (!consumeIf('E'));
+      } while (look() != 'E' && look() != 'Q');
     }
     NodeArray Params = popTrailingNodeArray(ParamsBegin);
 
+    Node *Requires2 = nullptr;
+    if (consumeIf('Q')) {
+      Requires2 = getDerived().parseConstraintExpr();
+      if (Requires2 == nullptr)
+        return nullptr;
+    }
+
+    if (!consumeIf('E'))
+      return nullptr;
+
     std::string_view Count = parseNumber();
     if (!consumeIf('_'))
       return nullptr;
-    return make<ClosureTypeName>(TempParams, Params, Count);
+    return make<ClosureTypeName>(TempParams, Requires1, Params, Requires2,
+                                 Count);
   }
   if (consumeIf("Ub")) {
     (void)parseNumber();
@@ -3190,15 +3465,25 @@ AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
   if (!consumeIf('N'))
     return nullptr;
 
-  Qualifiers CVTmp = parseCVQualifiers();
-  if (State) State->CVQualifiers = CVTmp;
+  // 'H' specifies that the encoding that follows
+  // has an explicit object parameter.
+  if (!consumeIf('H')) {
+    Qualifiers CVTmp = parseCVQualifiers();
+    if (State)
+      State->CVQualifiers = CVTmp;
 
-  if (consumeIf('O')) {
-    if (State) State->ReferenceQualifier = FrefQualRValue;
-  } else if (consumeIf('R')) {
-    if (State) State->ReferenceQualifier = FrefQualLValue;
-  } else {
-    if (State) State->ReferenceQualifier = FrefQualNone;
+    if (consumeIf('O')) {
+      if (State)
+        State->ReferenceQualifier = FrefQualRValue;
+    } else if (consumeIf('R')) {
+      if (State)
+        State->ReferenceQualifier = FrefQualLValue;
+    } else {
+      if (State)
+        State->ReferenceQualifier = FrefQualNone;
+    }
+  } else if (State) {
+    State->HasExplicitObjectParameter = true;
   }
 
   Node *SoFar = nullptr;
@@ -3446,7 +3731,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName(bool Global) {
     }
   }
 
-  assert(SoFar != nullptr);
+  DEMANGLE_ASSERT(SoFar != nullptr, "");
 
   Node *Base = getDerived().parseBaseUnresolvedName();
   if (Base == nullptr)
@@ -3894,7 +4179,15 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
     // Typically, <builtin-type>s are not considered substitution candidates,
     // but the exception to that exception is vendor extended types (Itanium C++
     // ABI 5.9.1).
-    Result = make<NameType>(Res);
+    if (consumeIf('I')) {
+      Node *BaseType = parseType();
+      if (BaseType == nullptr)
+        return nullptr;
+      if (!consumeIf('E'))
+        return nullptr;
+      Result = make<TransformedType>(Res, BaseType);
+    } else
+      Result = make<NameType>(Res);
     break;
   }
   case 'D':
@@ -3961,6 +4254,17 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
     case 'c':
       First += 2;
       return make<NameType>("decltype(auto)");
+    //                ::= Dk <type-constraint> # constrained auto
+    //                ::= DK <type-constraint> # constrained decltype(auto)
+    case 'k':
+    case 'K': {
+      std::string_view Kind = look(1) == 'k' ? " auto" : " decltype(auto)";
+      First += 2;
+      Node *Constraint = getDerived().parseName();
+      if (!Constraint)
+        return nullptr;
+      return make<PostfixQualifiedType>(Constraint, Kind);
+    }
     //                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr))
     case 'n':
       First += 2;
@@ -4512,6 +4816,75 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
       Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
 }
 
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseConstraintExpr() {
+  // Within this expression, all enclosing template parameter lists are in
+  // scope.
+  ScopedOverride<bool> SaveInConstraintExpr(InConstraintExpr, true);
+  return getDerived().parseExpr();
+}
+
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseRequiresExpr() {
+  NodeArray Params;
+  if (consumeIf("rQ")) {
+    // <expression> ::= rQ <bare-function-type> _ <requirement>+ E
+    size_t ParamsBegin = Names.size();
+    while (!consumeIf('_')) {
+      Node *Type = getDerived().parseType();
+      if (Type == nullptr)
+        return nullptr;
+      Names.push_back(Type);
+    }
+    Params = popTrailingNodeArray(ParamsBegin);
+  } else if (!consumeIf("rq")) {
+    // <expression> ::= rq <requirement>+ E
+    return nullptr;
+  }
+
+  size_t ReqsBegin = Names.size();
+  do {
+    Node *Constraint = nullptr;
+    if (consumeIf('X')) {
+      // <requirement> ::= X <expression> [N] [R <type-constraint>]
+      Node *Expr = getDerived().parseExpr();
+      if (Expr == nullptr)
+        return nullptr;
+      bool Noexcept = consumeIf('N');
+      Node *TypeReq = nullptr;
+      if (consumeIf('R')) {
+        TypeReq = getDerived().parseName();
+        if (TypeReq == nullptr)
+          return nullptr;
+      }
+      Constraint = make<ExprRequirement>(Expr, Noexcept, TypeReq);
+    } else if (consumeIf('T')) {
+      // <requirement> ::= T <type>
+      Node *Type = getDerived().parseType();
+      if (Type == nullptr)
+        return nullptr;
+      Constraint = make<TypeRequirement>(Type);
+    } else if (consumeIf('Q')) {
+      // <requirement> ::= Q <constraint-expression>
+      //
+      // FIXME: We use <expression> instead of <constraint-expression>. Either
+      // the requires expression is already inside a constraint expression, in
+      // which case it makes no difference, or we're in a requires-expression
+      // that might be partially-substituted, where the language behavior is
+      // not yet settled and clang mangles after substitution.
+      Node *NestedReq = getDerived().parseExpr();
+      if (NestedReq == nullptr)
+        return nullptr;
+      Constraint = make<NestedRequirement>(NestedReq);
+    }
+    if (Constraint == nullptr)
+      return nullptr;
+    Names.push_back(Constraint);
+  } while (!consumeIf('E'));
+
+  return make<RequiresExpr>(Params, popTrailingNodeArray(ReqsBegin));
+}
+
 // <expression> ::= <unary operator-name> <expression>
 //              ::= <binary operator-name> <expression> <expression>
 //              ::= <ternary operator-name> <expression> <expression> <expression>
@@ -4748,6 +5121,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
       return Ex;
     return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary);
   }
+  if (look() == 'r' && (look(1) == 'q' || look(1) == 'Q'))
+    return parseRequiresExpr();
   if (consumeIf("so"))
     return parseSubobjectExpr();
   if (consumeIf("sp")) {
@@ -5026,29 +5401,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
 }
 
 // <encoding> ::= <function name> <bare-function-type>
+//                    [`Q` <requires-clause expr>]
 //            ::= <data name>
 //            ::= <special-name>
 template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
+Node *AbstractManglingParser<Derived, Alloc>::parseEncoding(bool ParseParams) {
   // The template parameters of an encoding are unrelated to those of the
   // enclosing context.
-  class SaveTemplateParams {
-    AbstractManglingParser *Parser;
-    decltype(TemplateParams) OldParams;
-    decltype(OuterTemplateParams) OldOuterParams;
-
-  public:
-    SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
-      OldParams = std::move(Parser->TemplateParams);
-      OldOuterParams = std::move(Parser->OuterTemplateParams);
-      Parser->TemplateParams.clear();
-      Parser->OuterTemplateParams.clear();
-    }
-    ~SaveTemplateParams() {
-      Parser->TemplateParams = std::move(OldParams);
-      Parser->OuterTemplateParams = std::move(OldOuterParams);
-    }
-  } SaveTemplateParams(this);
+  SaveTemplateParams SaveTemplateParamsScope(this);
 
   if (look() == 'G' || look() == 'T')
     return getDerived().parseSpecialName();
@@ -5071,6 +5431,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
   if (IsEndOfEncoding())
     return Name;
 
+  // ParseParams may be false at the top level only, when called from parse().
+  // For example in the mangled name _Z3fooILZ3BarEET_f, ParseParams may be
+  // false when demangling 3fooILZ3BarEET_f but is always true when demangling
+  // 3Bar.
+  if (!ParseParams) {
+    while (consume())
+      ;
+    return Name;
+  }
+
   Node *Attrs = nullptr;
   if (consumeIf("Ua9enable_ifI")) {
     size_t BeforeArgs = Names.size();
@@ -5092,22 +5462,35 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
       return nullptr;
   }
 
-  if (consumeIf('v'))
-    return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
-                                  Attrs, NameInfo.CVQualifiers,
-                                  NameInfo.ReferenceQualifier);
+  NodeArray Params;
+  if (!consumeIf('v')) {
+    size_t ParamsBegin = Names.size();
+    do {
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return nullptr;
 
-  size_t ParamsBegin = Names.size();
-  do {
-    Node *Ty = getDerived().parseType();
-    if (Ty == nullptr)
+      const bool IsFirstParam = ParamsBegin == Names.size();
+      if (NameInfo.HasExplicitObjectParameter && IsFirstParam)
+        Ty = make<ExplicitObjectParameter>(Ty);
+
+      if (Ty == nullptr)
+        return nullptr;
+
+      Names.push_back(Ty);
+    } while (!IsEndOfEncoding() && look() != 'Q');
+    Params = popTrailingNodeArray(ParamsBegin);
+  }
+
+  Node *Requires = nullptr;
+  if (consumeIf('Q')) {
+    Requires = getDerived().parseConstraintExpr();
+    if (!Requires)
       return nullptr;
-    Names.push_back(Ty);
-  } while (!IsEndOfEncoding());
+  }
 
-  return make<FunctionEncoding>(ReturnType, Name,
-                                popTrailingNodeArray(ParamsBegin),
-                                Attrs, NameInfo.CVQualifiers,
+  return make<FunctionEncoding>(ReturnType, Name, Params, Attrs, Requires,
+                                NameInfo.CVQualifiers,
                                 NameInfo.ReferenceQualifier);
 }
 
@@ -5134,7 +5517,8 @@ template <>
 struct FloatData<long double>
 {
 #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
-    defined(__wasm__) || defined(__riscv) || defined(__loongarch__)
+    defined(__wasm__) || defined(__riscv) || defined(__loongarch__) || \
+    defined(__ve__)
     static const size_t mangled_size = 32;
 #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
     static const size_t mangled_size = 16;
@@ -5268,6 +5652,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
 //                  ::= TL <level-1> _ <parameter-2 non-negative number> _
 template <typename Derived, typename Alloc>
 Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
+  const char *Begin = First;
   if (!consumeIf('T'))
     return nullptr;
 
@@ -5289,6 +5674,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
       return nullptr;
   }
 
+  // We don't track enclosing template parameter levels well enough to reliably
+  // substitute them all within a <constraint-expression>, so print the
+  // parameter numbering instead for now.
+  // TODO: Track all enclosing template parameters and substitute them here.
+  if (InConstraintExpr) {
+    return make<NameType>(std::string_view(Begin, First - 1 - Begin));
+  }
+
   // If we're in a context where this <template-param> refers to a
   // <template-arg> further ahead in the mangled name (currently just conversion
   // operator types), then we should only look it up in the right context.
@@ -5297,7 +5690,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
     Node *ForwardRef = make<ForwardTemplateReference>(Index);
     if (!ForwardRef)
       return nullptr;
-    assert(ForwardRef->getKind() == Node::KForwardTemplateReference);
+    DEMANGLE_ASSERT(ForwardRef->getKind() == Node::KForwardTemplateReference,
+                    "");
     ForwardTemplateRefs.push_back(
         static_cast<ForwardTemplateReference *>(ForwardRef));
     return ForwardRef;
@@ -5326,11 +5720,13 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
 //                       ::= Tt <template-param-decl>* E # template parameter
 //                       ::= Tp <template-param-decl>    # parameter pack
 template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl(
+    TemplateParamList *Params) {
   auto InventTemplateParamName = [&](TemplateParamKind Kind) {
     unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++;
     Node *N = make<SyntheticTemplateParamName>(Kind, Index);
-    if (N) TemplateParams.back()->push_back(N);
+    if (N && Params)
+      Params->push_back(N);
     return N;
   };
 
@@ -5341,6 +5737,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
     return make<TypeTemplateParamDecl>(Name);
   }
 
+  if (consumeIf("Tk")) {
+    Node *Constraint = getDerived().parseName();
+    if (!Constraint)
+      return nullptr;
+    Node *Name = InventTemplateParamName(TemplateParamKind::Type);
+    if (!Name)
+      return nullptr;
+    return make<ConstrainedTypeTemplateParamDecl>(Constraint, Name);
+  }
+
   if (consumeIf("Tn")) {
     Node *Name = InventTemplateParamName(TemplateParamKind::NonType);
     if (!Name)
@@ -5357,18 +5763,25 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
       return nullptr;
     size_t ParamsBegin = Names.size();
     ScopedTemplateParamList TemplateTemplateParamParams(this);
-    while (!consumeIf("E")) {
-      Node *P = parseTemplateParamDecl();
+    Node *Requires = nullptr;
+    while (!consumeIf('E')) {
+      Node *P = parseTemplateParamDecl(TemplateTemplateParamParams.params());
       if (!P)
         return nullptr;
       Names.push_back(P);
+      if (consumeIf('Q')) {
+        Requires = getDerived().parseConstraintExpr();
+        if (Requires == nullptr || !consumeIf('E'))
+          return nullptr;
+        break;
+      }
     }
-    NodeArray Params = popTrailingNodeArray(ParamsBegin);
-    return make<TemplateTemplateParamDecl>(Name, Params);
+    NodeArray InnerParams = popTrailingNodeArray(ParamsBegin);
+    return make<TemplateTemplateParamDecl>(Name, InnerParams, Requires);
   }
 
   if (consumeIf("Tp")) {
-    Node *P = parseTemplateParamDecl();
+    Node *P = parseTemplateParamDecl(Params);
     if (!P)
       return nullptr;
     return make<TemplateParamPackDecl>(P);
@@ -5382,6 +5795,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
 //                ::= <expr-primary>            # simple expressions
 //                ::= J <template-arg>* E       # argument pack
 //                ::= LZ <encoding> E           # extension
+//                ::= <template-param-decl> <template-arg>
 template <typename Derived, typename Alloc>
 Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
   switch (look()) {
@@ -5416,6 +5830,18 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
     //                ::= <expr-primary>            # simple expressions
     return getDerived().parseExprPrimary();
   }
+  case 'T': {
+    // Either <template-param> or a <template-param-decl> <template-arg>.
+    if (!getDerived().isTemplateParamDecl())
+      return getDerived().parseType();
+    Node *Param = getDerived().parseTemplateParamDecl(nullptr);
+    if (!Param)
+      return nullptr;
+    Node *Arg = getDerived().parseTemplateArg();
+    if (!Arg)
+      return nullptr;
+    return make<TemplateParamQualifiedArg>(Param, Arg);
+  }
   default:
     return getDerived().parseType();
   }
@@ -5438,30 +5864,39 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
   }
 
   size_t ArgsBegin = Names.size();
+  Node *Requires = nullptr;
   while (!consumeIf('E')) {
     if (TagTemplates) {
-      auto OldParams = std::move(TemplateParams);
       Node *Arg = getDerived().parseTemplateArg();
-      TemplateParams = std::move(OldParams);
       if (Arg == nullptr)
         return nullptr;
       Names.push_back(Arg);
       Node *TableEntry = Arg;
+      if (Arg->getKind() == Node::KTemplateParamQualifiedArg) {
+        TableEntry =
+            static_cast<TemplateParamQualifiedArg *>(TableEntry)->getArg();
+      }
       if (Arg->getKind() == Node::KTemplateArgumentPack) {
         TableEntry = make<ParameterPack>(
             static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
         if (!TableEntry)
           return nullptr;
       }
-      TemplateParams.back()->push_back(TableEntry);
+      OuterTemplateParams.push_back(TableEntry);
     } else {
       Node *Arg = getDerived().parseTemplateArg();
       if (Arg == nullptr)
         return nullptr;
       Names.push_back(Arg);
     }
+    if (consumeIf('Q')) {
+      Requires = getDerived().parseConstraintExpr();
+      if (!Requires || !consumeIf('E'))
+        return nullptr;
+      break;
+    }
   }
-  return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
+  return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin), Requires);
 }
 
 // <mangled-name> ::= _Z <encoding>
@@ -5470,9 +5905,9 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
 // extension      ::= ___Z <encoding> _block_invoke<decimal-digit>+
 // extension      ::= ___Z <encoding> _block_invoke_<decimal-digit>+
 template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parse() {
+Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
   if (consumeIf("_Z") || consumeIf("__Z")) {
-    Node *Encoding = getDerived().parseEncoding();
+    Node *Encoding = getDerived().parseEncoding(ParseParams);
     if (Encoding == nullptr)
       return nullptr;
     if (look() == '.') {
@@ -5486,7 +5921,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() {
   }
 
   if (consumeIf("___Z") || consumeIf("____Z")) {
-    Node *Encoding = getDerived().parseEncoding();
+    Node *Encoding = getDerived().parseEncoding(ParseParams);
     if (Encoding == nullptr || !consumeIf("_block_invoke"))
       return nullptr;
     bool RequireNumber = consumeIf('_');
lib/libcxxabi/src/demangle/ItaniumNodes.def
@@ -19,6 +19,7 @@ NODE(QualType)
 NODE(ConversionOperatorType)
 NODE(PostfixQualifiedType)
 NODE(ElaboratedTypeSpefType)
+NODE(TransformedType)
 NODE(NameType)
 NODE(AbiTagAttr)
 NODE(EnableIfAttr)
@@ -36,6 +37,7 @@ NODE(SpecialName)
 NODE(CtorVtableSpecialName)
 NODE(QualifiedName)
 NODE(NestedName)
+NODE(MemberLikeFriendName)
 NODE(LocalName)
 NODE(ModuleName)
 NODE(ModuleEntity)
@@ -44,7 +46,9 @@ NODE(PixelVectorType)
 NODE(BinaryFPType)
 NODE(BitIntType)
 NODE(SyntheticTemplateParamName)
+NODE(TemplateParamQualifiedArg)
 NODE(TypeTemplateParamDecl)
+NODE(ConstrainedTypeTemplateParamDecl)
 NODE(NonTypeTemplateParamDecl)
 NODE(TemplateTemplateParamDecl)
 NODE(TemplateParamPackDecl)
@@ -91,5 +95,10 @@ NODE(DoubleLiteral)
 NODE(LongDoubleLiteral)
 NODE(BracedExpr)
 NODE(BracedRangeExpr)
+NODE(RequiresExpr)
+NODE(ExprRequirement)
+NODE(TypeRequirement)
+NODE(NestedRequirement)
+NODE(ExplicitObjectParameter)
 
 #undef NODE
lib/libcxxabi/src/demangle/Utility.h
@@ -19,11 +19,9 @@
 #include "DemangleConfig.h"
 
 #include <array>
-#include <cassert>
 #include <cstdint>
 #include <cstdlib>
 #include <cstring>
-#include <exception>
 #include <limits>
 #include <string_view>
 
@@ -49,7 +47,7 @@ class OutputBuffer {
         BufferCapacity = Need;
       Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
       if (Buffer == nullptr)
-        std::terminate();
+        std::abort();
     }
   }
 
@@ -160,7 +158,7 @@ public:
   }
 
   void insert(size_t Pos, const char *S, size_t N) {
-    assert(Pos <= CurrentPosition);
+    DEMANGLE_ASSERT(Pos <= CurrentPosition, "");
     if (N == 0)
       return;
     grow(N);
@@ -173,7 +171,7 @@ public:
   void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
 
   char back() const {
-    assert(CurrentPosition);
+    DEMANGLE_ASSERT(CurrentPosition, "");
     return Buffer[CurrentPosition - 1];
   }
 
lib/libcxxabi/src/abort_message.h
@@ -14,4 +14,15 @@
 extern "C" _LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void
 abort_message(const char *format, ...) __attribute__((format(printf, 1, 2)));
 
+#ifndef _LIBCXXABI_ASSERT
+#  define _LIBCXXABI_ASSERT(expr, msg)                                                                                 \
+    do {                                                                                                               \
+      if (!(expr)) {                                                                                                   \
+        char const* __msg = (msg);                                                                                     \
+        ::abort_message("%s:%d: %s", __FILE__, __LINE__, __msg);                                                       \
+      }                                                                                                                \
+    } while (false)
+
 #endif
+
+#endif // __ABORT_MESSAGE_H_
lib/libcxxabi/src/aix_state_tab_eh.inc
@@ -740,6 +740,6 @@ __catchThrownException(void (*cdfunc)(void),   // function which may fail
   return 0;
 }
 
-}  // extern "C"
+} // extern "C"
 
 }  // __cxxabiv1
lib/libcxxabi/src/cxa_demangle.cpp
@@ -10,14 +10,17 @@
 // file does not yet support:
 //   - C++ modules TS
 
+#include "abort_message.h"
+#define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg)
+
 #include "demangle/DemangleConfig.h"
 #include "demangle/ItaniumDemangle.h"
 #include "__cxxabi_config.h"
-#include <cassert>
 #include <cctype>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
+#include <exception>
 #include <functional>
 #include <numeric>
 #include <string_view>
@@ -394,7 +397,7 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
     InternalStatus = demangle_invalid_mangled_name;
   else {
     OutputBuffer O(Buf, N);
-    assert(Parser.ForwardTemplateRefs.empty());
+    DEMANGLE_ASSERT(Parser.ForwardTemplateRefs.empty(), "");
     AST->print(O);
     O += '\0';
     if (N != nullptr)
lib/libcxxabi/src/cxa_exception.cpp
@@ -206,6 +206,19 @@ void __cxa_free_exception(void *thrown_object) throw() {
     __aligned_free_with_fallback((void *)raw_buffer);
 }
 
+__cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo,
+                                              void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() {
+  __cxa_exception* exception_header = cxa_exception_from_thrown_object(object);
+  exception_header->referenceCount = 0;
+  exception_header->unexpectedHandler = std::get_unexpected();
+  exception_header->terminateHandler = std::get_terminate();
+  exception_header->exceptionType = tinfo;
+  exception_header->exceptionDestructor = dest;
+  setOurExceptionClass(&exception_header->unwindHeader);
+  exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
+
+  return exception_header;
+}
 
 //  This function shall allocate a __cxa_dependent_exception and
 //  return a pointer to it. (Really to the object, not past its' end).
@@ -254,23 +267,21 @@ will call terminate, assuming that there was no handler for the
 exception.
 */
 void
+#ifdef __USING_WASM_EXCEPTIONS__
+// In Wasm, a destructor returns its argument
+__cxa_throw(void *thrown_object, std::type_info *tinfo, void *(_LIBCXXABI_DTOR_FUNC *dest)(void *)) {
+#else
 __cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) {
-    __cxa_eh_globals *globals = __cxa_get_globals();
-    __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
-
-    exception_header->unexpectedHandler = std::get_unexpected();
-    exception_header->terminateHandler  = std::get_terminate();
-    exception_header->exceptionType = tinfo;
-    exception_header->exceptionDestructor = dest;
-    setOurExceptionClass(&exception_header->unwindHeader);
-    exception_header->referenceCount = 1;  // This is a newly allocated exception, no need for thread safety.
-    globals->uncaughtExceptions += 1;   // Not atomically, since globals are thread-local
+#endif
+  __cxa_eh_globals* globals = __cxa_get_globals();
+  globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
 
-    exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
+  __cxa_exception* exception_header = __cxa_init_primary_exception(thrown_object, tinfo, dest);
+  exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
 
 #if __has_feature(address_sanitizer)
-    // Inform the ASan runtime that now might be a good time to clean stuff up.
-    __asan_handle_no_return();
+  // Inform the ASan runtime that now might be a good time to clean stuff up.
+  __asan_handle_no_return();
 #endif
 
 #ifdef __USING_SJLJ_EXCEPTIONS__
@@ -771,6 +782,6 @@ __cxa_uncaught_exceptions() throw()
     return globals->uncaughtExceptions;
 }
 
-}  // extern "C"
+} // extern "C"
 
 }  // abi
lib/libcxxabi/src/cxa_exception.h
@@ -43,7 +43,12 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
 
     //  Manage the exception object itself.
     std::type_info *exceptionType;
+#ifdef __USING_WASM_EXCEPTIONS__
+    // In Wasm, a destructor returns its argument
+    void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
+#else
     void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
+#endif
     std::unexpected_handler unexpectedHandler;
     std::terminate_handler  terminateHandler;
 
lib/libcxxabi/src/cxa_guard.cpp
@@ -48,6 +48,6 @@ _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) {
   SelectedImplementation imp(raw_guard_object);
   imp.cxa_guard_abort();
 }
-}  // extern "C"
+} // extern "C"
 
 }  // __cxxabiv1
lib/libcxxabi/src/cxa_noexception.cpp
@@ -49,7 +49,7 @@ __cxa_uncaught_exception() throw() { return false; }
 unsigned int
 __cxa_uncaught_exceptions() throw() { return 0; }
 
-}  // extern "C"
+} // extern "C"
 
 // provide dummy implementations for the 'no exceptions' case.
 uint64_t __getExceptionClass  (const _Unwind_Exception*)           { return 0; }
lib/libcxxabi/src/cxa_personality.cpp
@@ -70,7 +70,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
 +------------------+--+-----+-----+------------------------+--------------------------+
 | callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table |
 +---------------------+-----------+---------------------------------------------------+
-#ifndef __USING_SJLJ_EXCEPTIONS__
+#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
 +---------------------+-----------+------------------------------------------------+
 | Beginning of Call Site Table            The current ip lies within the           |
 | ...                                     (start, length) range of one of these    |
@@ -84,7 +84,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
 | +-------------+---------------------------------+------------------------------+ |
 | ...                                                                              |
 +----------------------------------------------------------------------------------+
-#else  // __USING_SJLJ_EXCEPTIONS__
+#else  // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
 +---------------------+-----------+------------------------------------------------+
 | Beginning of Call Site Table            The current ip is a 1-based index into   |
 | ...                                     this table.  Or it is -1 meaning no      |
@@ -97,7 +97,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
 | +-------------+---------------------------------+------------------------------+ |
 | ...                                                                              |
 +----------------------------------------------------------------------------------+
-#endif // __USING_SJLJ_EXCEPTIONS__
+#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
 +---------------------------------------------------------------------+
 | Beginning of Action Table       ttypeIndex == 0 : cleanup           |
 | ...                             ttypeIndex  > 0 : catch             |
@@ -547,7 +547,7 @@ void
 set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
               const scan_results& results)
 {
-#if defined(__USING_SJLJ_EXCEPTIONS__)
+#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
 #define __builtin_eh_return_data_regno(regno) regno
 #elif defined(__ibmxl__)
 // IBM xlclang++ compiler does not support __builtin_eh_return_data_regno.
@@ -642,7 +642,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
     // Get beginning current frame's code (as defined by the
     // emitted dwarf code)
     uintptr_t funcStart = _Unwind_GetRegionStart(context);
-#ifdef __USING_SJLJ_EXCEPTIONS__
+#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
     if (ip == uintptr_t(-1))
     {
         // no action
@@ -652,18 +652,17 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
     else if (ip == 0)
         call_terminate(native_exception, unwind_exception);
     // ip is 1-based index into call site table
-#else  // !__USING_SJLJ_EXCEPTIONS__
+#else  // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
     uintptr_t ipOffset = ip - funcStart;
-#endif // !defined(_USING_SLJL_EXCEPTIONS__)
+#endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
     const uint8_t* classInfo = NULL;
     // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
     //       dwarf emission
     // Parse LSDA header.
     uint8_t lpStartEncoding = *lsda++;
-    const uint8_t* lpStart =
-        (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
-    if (lpStart == 0)
-        lpStart = (const uint8_t*)funcStart;
+    const uint8_t* lpStart = lpStartEncoding == DW_EH_PE_omit
+                                 ? (const uint8_t*)funcStart
+                                 : (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
     uint8_t ttypeEncoding = *lsda++;
     if (ttypeEncoding != DW_EH_PE_omit)
     {
@@ -676,8 +675,8 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
     // Walk call-site table looking for range that
     // includes current PC.
     uint8_t callSiteEncoding = *lsda++;
-#ifdef __USING_SJLJ_EXCEPTIONS__
-    (void)callSiteEncoding;  // When using SjLj exceptions, callSiteEncoding is never used
+#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
+    (void)callSiteEncoding;  // When using SjLj/Wasm exceptions, callSiteEncoding is never used
 #endif
     uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
     const uint8_t* callSiteTableStart = lsda;
@@ -687,7 +686,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
     while (callSitePtr < callSiteTableEnd)
     {
         // There is one entry per call site.
-#ifndef __USING_SJLJ_EXCEPTIONS__
+#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
         // The call sites are non-overlapping in [start, start+length)
         // The call sites are ordered in increasing value of start
         uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
@@ -695,15 +694,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
         uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if ((start <= ipOffset) && (ipOffset < (start + length)))
-#else  // __USING_SJLJ_EXCEPTIONS__
+#else  // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
         // ip is 1-based index into this table
         uintptr_t landingPad = readULEB128(&callSitePtr);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if (--ip == 0)
-#endif // __USING_SJLJ_EXCEPTIONS__
+#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
         {
             // Found the call site containing ip.
-#ifndef __USING_SJLJ_EXCEPTIONS__
+#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
             if (landingPad == 0)
             {
                 // No handler here
@@ -711,9 +710,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
                 return;
             }
             landingPad = (uintptr_t)lpStart + landingPad;
-#else  // __USING_SJLJ_EXCEPTIONS__
+#else  // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
             ++landingPad;
-#endif // __USING_SJLJ_EXCEPTIONS__
+#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
             results.landingPad = landingPad;
             if (actionEntry == 0)
             {
@@ -841,7 +840,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
                 action += actionOffset;
             }  // there is no break out of this loop, only return
         }
-#ifndef __USING_SJLJ_EXCEPTIONS__
+#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
         else if (ipOffset < start)
         {
             // There is no call site for this ip
@@ -849,7 +848,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
             // Possible stack corruption.
             call_terminate(native_exception, unwind_exception);
         }
-#endif // !__USING_SJLJ_EXCEPTIONS__
+#endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
     }  // there might be some tricky cases which break out of this loop
 
     // It is possible that no eh table entry specify how to handle
@@ -906,7 +905,9 @@ _UA_CLEANUP_PHASE
 */
 
 #if !defined(_LIBCXXABI_ARM_EHABI)
-#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+#ifdef __USING_WASM_EXCEPTIONS__
+_Unwind_Reason_Code __gxx_personality_wasm0
+#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
 static _Unwind_Reason_Code __gxx_personality_imp
 #else
 _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
@@ -973,6 +974,11 @@ __gxx_personality_v0
             exc->languageSpecificData = results.languageSpecificData;
             exc->catchTemp = reinterpret_cast<void*>(results.landingPad);
             exc->adjustedPtr = results.adjustedPtr;
+#ifdef __USING_WASM_EXCEPTIONS__
+            // Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
+            // results here.
+            set_registers(unwind_exception, context, results);
+#endif
         }
         return _URC_HANDLER_FOUND;
     }
@@ -1304,7 +1310,7 @@ _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1(
     __attribute__((__alias__("__gxx_personality_v0")));
 #endif
 
-}  // extern "C"
+} // extern "C"
 
 }  // __cxxabiv1
 
lib/libcxxabi/src/cxa_vector.cpp
@@ -416,6 +416,6 @@ __cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
 }
 
 
-}  // extern "C"
+} // extern "C"
 
 }  // abi
lib/libcxxabi/src/fallback_malloc.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "fallback_malloc.h"
+#include "abort_message.h"
 
 #include <__threading_support>
 #ifndef _LIBCXXABI_HAS_NO_THREADS
@@ -16,7 +17,7 @@
 #endif
 
 #include <__memory/aligned_alloc.h>
-#include <assert.h>
+#include <__assert>
 #include <stdlib.h> // for malloc, calloc, free
 #include <string.h> // for memset
 
@@ -142,7 +143,7 @@ void* fallback_malloc(size_t len) {
 
     // Check the invariant that all heap_nodes pointers 'p' are aligned
     // so that 'p + 1' has an alignment of at least RequiredAlignment
-    assert(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0);
+    _LIBCXXABI_ASSERT(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0, "");
 
     // Calculate the number of extra padding elements needed in order
     // to split 'p' and create a properly aligned heap_node from the tail
@@ -163,7 +164,7 @@ void* fallback_malloc(size_t len) {
       q->next_node = 0;
       q->len = static_cast<heap_size>(aligned_nelems);
       void* ptr = q + 1;
-      assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
+      _LIBCXXABI_ASSERT(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0, "");
       return ptr;
     }
 
@@ -176,7 +177,7 @@ void* fallback_malloc(size_t len) {
         prev->next_node = p->next_node;
       p->next_node = 0;
       void* ptr = p + 1;
-      assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
+      _LIBCXXABI_ASSERT(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0, "");
       return ptr;
     }
   }
lib/libcxxabi/src/private_typeinfo.cpp
@@ -42,6 +42,7 @@
 // is_equal() with use_strcmp=false so the string names are not compared.
 
 #include <cstdint>
+#include <cassert>
 #include <string.h>
 
 #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
@@ -75,6 +76,242 @@ static inline ptrdiff_t update_offset_to_base(const char* vtable,
 namespace __cxxabiv1
 {
 
+namespace {
+
+struct derived_object_info {
+    const void* dynamic_ptr;
+    const __class_type_info* dynamic_type;
+    std::ptrdiff_t offset_to_derived;
+};
+
+/// A helper function that gets (dynamic_ptr, dynamic_type, offset_to_derived) from static_ptr.
+void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr)
+{
+#if __has_feature(cxx_abi_relative_vtable)
+    // The vtable address will point to the first virtual function, which is 8
+    // bytes after the start of the vtable (4 for the offset from top + 4 for
+    // the typeinfo component).
+    const int32_t* vtable =
+        *reinterpret_cast<const int32_t* const*>(static_ptr);
+    info->offset_to_derived = static_cast<std::ptrdiff_t>(vtable[-2]);
+    info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;
+
+    // The typeinfo component is now a relative offset to a proxy.
+    int32_t offset_to_ti_proxy = vtable[-1];
+    const uint8_t* ptr_to_ti_proxy =
+        reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy;
+    info->dynamic_type = *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));
+#else
+    void **vtable = *static_cast<void ** const *>(static_ptr);
+    info->offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
+    info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;
+    info->dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
+#endif
+}
+
+/// A helper function for __dynamic_cast that casts a base sub-object pointer
+/// to the object's dynamic type.
+///
+/// This function returns the casting result directly. No further processing
+/// required.
+///
+/// Specifically, this function can only be called if the following pre-
+/// condition holds:
+///   * The dynamic type of the object pointed to by `static_ptr` is exactly
+///     the same as `dst_type`.
+const void* dyn_cast_to_derived(const void* static_ptr,
+                                const void* dynamic_ptr,
+                                const __class_type_info* static_type,
+                                const __class_type_info* dst_type,
+                                std::ptrdiff_t offset_to_derived,
+                                std::ptrdiff_t src2dst_offset)
+{
+    // We're downcasting from src_type to the complete object's dynamic type.
+    //   This is a really hot path that can be further optimized with the
+    //   `src2dst_offset` hint.
+    // In such a case, dynamic_ptr already gives the casting result if the
+    //   casting ever succeeds. All we have to do now is to check static_ptr
+    //   points to a public base sub-object of dynamic_ptr.
+
+    if (src2dst_offset >= 0)
+    {
+        // The static type is a unique public non-virtual base type of
+        //   dst_type at offset `src2dst_offset` from the origin of dst.
+        // Note that there might be other non-public static_type bases. The
+        //   hint only guarantees that the public base is non-virtual and
+        //   unique. So we have to check whether static_ptr points to that
+        //   unique public base sub-object.
+        if (offset_to_derived != -src2dst_offset)
+            return nullptr;
+        return dynamic_ptr;
+    }
+
+    if (src2dst_offset == -2)
+    {
+        // static_type is not a public base of dst_type.
+        return nullptr;
+    }
+
+    // If src2dst_offset == -3, then:
+    //   src_type is a multiple public base type but never a virtual
+    //   base type. We can't conclude that static_ptr points to those
+    //   public base sub-objects because there might be other non-
+    //   public static_type bases. The search is inevitable.
+
+    // Fallback to the slow path to check that static_type is a public
+    //   base type of dynamic_type.
+    // Using giant short cut.  Add that information to info.
+    __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0,      0, 0, 0, 0, 0, 0, 0,
+                                1, // number_of_dst_type
+                                false,    false,      false,       true,           nullptr};
+    // Do the  search
+    dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+    // The following if should always be false because we should
+    //   definitely find (static_ptr, static_type), either on a public
+    //   or private path
+    if (info.path_dst_ptr_to_static_ptr == unknown)
+    {
+        // We get here only if there is some kind of visibility problem
+        //   in client code.
+        static_assert(std::atomic<size_t>::is_always_lock_free, "");
+        static std::atomic<size_t> error_count(0);
+        size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
+        if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
+            syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
+                    "should have public visibility. At least one of them is hidden. %s"
+                    ", %s.\n", static_type->name(), dst_type->name());
+        // Redo the search comparing type_info's using strcmp
+        info = {dst_type, static_ptr, static_type, src2dst_offset, 0,     0,     0,    0,      0, 0,
+                0,        0,          0,           false,          false, false, true, nullptr};
+        info.number_of_dst_type = 1;
+        dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
+    }
+#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+    // Query the search.
+    if (info.path_dst_ptr_to_static_ptr != public_path)
+        return nullptr;
+
+    return dynamic_ptr;
+}
+
+/// A helper function for __dynamic_cast that tries to perform a downcast
+/// before giving up and falling back to the slow path.
+const void* dyn_cast_try_downcast(const void* static_ptr,
+                                  const void* dynamic_ptr,
+                                  const __class_type_info* dst_type,
+                                  const __class_type_info* dynamic_type,
+                                  std::ptrdiff_t src2dst_offset)
+{
+    if (src2dst_offset < 0)
+    {
+        // We can only optimize the case if the static type is a unique public
+        //   base of dst_type. Give up.
+        return nullptr;
+    }
+
+    // Pretend there is a dst_type object that leads to static_ptr. Later we
+    //   will check whether this imagined dst_type object exists. If it exists
+    //   then it will be the casting result.
+    const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset;
+
+    if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) < reinterpret_cast<std::intptr_t>(dynamic_ptr))
+    {
+        // The imagined dst_type object does not exist. Bail-out quickly.
+        return nullptr;
+    }
+
+    // Try to search a path from dynamic_type to dst_type.
+    __dynamic_cast_info dynamic_to_dst_info = {dynamic_type,
+                                               dst_ptr_to_static,
+                                               dst_type,
+                                               src2dst_offset,
+                                               0,
+                                               0,
+                                               0,
+                                               0,
+                                               0,
+                                               0,
+                                               0,
+                                               0,
+                                               1, // number_of_dst_type
+                                               false,
+                                               false,
+                                               false,
+                                               true,
+                                               nullptr};
+    dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
+    if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {
+        // We have found at least one path from dynamic_ptr to dst_ptr. The
+        //   downcast can succeed.
+        return dst_ptr_to_static;
+    }
+
+    return nullptr;
+}
+
+const void* dyn_cast_slow(const void* static_ptr,
+                          const void* dynamic_ptr,
+                          const __class_type_info* static_type,
+                          const __class_type_info* dst_type,
+                          const __class_type_info* dynamic_type,
+                          std::ptrdiff_t src2dst_offset)
+{
+    // Not using giant short cut.  Do the search
+
+    // Initialize info struct for this search.
+    __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0,     0,     0,    0,      0, 0,
+                                0,        0,          0,           false,          false, false, true, nullptr};
+
+    dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+    // The following if should always be false because we should
+    //   definitely find (static_ptr, static_type), either on a public
+    //   or private path
+    if (info.path_dst_ptr_to_static_ptr == unknown &&
+        info.path_dynamic_ptr_to_static_ptr == unknown)
+    {
+        static_assert(std::atomic<size_t>::is_always_lock_free, "");
+        static std::atomic<size_t> error_count(0);
+        size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
+        if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
+            syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
+                            "has hidden visibility or is defined in more than one translation "
+                            "unit. They should all have public visibility. "
+                            "%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
+                    dst_type->name());
+        // Redo the search comparing type_info's using strcmp
+        info = {dst_type, static_ptr, static_type, src2dst_offset, 0,     0,     0,    0,      0, 0,
+                0,        0,          0,           false,          false, false, true, nullptr};
+        dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
+    }
+#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+    // Query the search.
+    switch (info.number_to_static_ptr)
+    {
+    case 0:
+        if (info.number_to_dst_ptr == 1 &&
+                info.path_dynamic_ptr_to_static_ptr == public_path &&
+                info.path_dynamic_ptr_to_dst_ptr == public_path)
+            return info.dst_ptr_not_leading_to_static_ptr;
+        break;
+    case 1:
+        if (info.path_dst_ptr_to_static_ptr == public_path ||
+            (
+                info.number_to_dst_ptr == 0 &&
+                info.path_dynamic_ptr_to_static_ptr == public_path &&
+                info.path_dynamic_ptr_to_dst_ptr == public_path
+            )
+        )
+            return info.dst_ptr_leading_to_static_ptr;
+        break;
+    }
+
+    return nullptr;
+}
+
+}  // namespace
+
 // __shim_type_info
 
 __shim_type_info::~__shim_type_info()
@@ -233,7 +470,8 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type,
     if (thrown_class_type == 0)
         return false;
     // bullet 2
-    __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
+    assert(adjustedPtr && "catching a class without an object?");
+    __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true, nullptr};
     info.number_of_dst_type = 1;
     thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
     if (info.path_dst_ptr_to_static_ptr == public_path)
@@ -248,32 +486,46 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type,
 #pragma clang diagnostic pop
 #endif
 
+// When we have an object to inspect - we just pass the pointer to the sub-
+// object that matched the static_type we just checked.  If that is different
+// from any previously recorded pointer to that object type, then we have
+// an ambiguous case.
+
+// When we have no object to inspect, we need to account for virtual bases
+// explicitly.
+// info->vbase_cookie is a pointer to the name of the innermost virtual base
+// type, or nullptr if there is no virtual base on the path so far.
+// adjustedPtr points to the subobject we just found.
+// If vbase_cookie != any previously recorded (including the case of nullptr
+// representing an already-found static sub-object) then we have an ambiguous
+// case.  Assuming that the vbase_cookie values agree; if then we have a
+// different offset (adjustedPtr) from any previously recorded, this indicates
+// an ambiguous case within the virtual base.
+
 void
 __class_type_info::process_found_base_class(__dynamic_cast_info* info,
                                                void* adjustedPtr,
                                                int path_below) const
 {
-    if (info->dst_ptr_leading_to_static_ptr == 0)
-    {
-        // First time here
-        info->dst_ptr_leading_to_static_ptr = adjustedPtr;
-        info->path_dst_ptr_to_static_ptr = path_below;
-        info->number_to_static_ptr = 1;
-    }
-    else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr)
-    {
-        // We've been here before.  Update path to "most public"
-        if (info->path_dst_ptr_to_static_ptr == not_public_path)
-            info->path_dst_ptr_to_static_ptr = path_below;
-    }
-    else
-    {
-        // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
-        //   to a static_type
-        info->number_to_static_ptr += 1;
-        info->path_dst_ptr_to_static_ptr = not_public_path;
-        info->search_done = true;
-    }
+  if (info->number_to_static_ptr == 0) {
+    // First time we found this base
+    info->dst_ptr_leading_to_static_ptr = adjustedPtr;
+    info->path_dst_ptr_to_static_ptr = path_below;
+    // stash the virtual base cookie.
+    info->dst_ptr_not_leading_to_static_ptr = info->vbase_cookie;
+    info->number_to_static_ptr = 1;
+  } else if (info->dst_ptr_not_leading_to_static_ptr == info->vbase_cookie &&
+             info->dst_ptr_leading_to_static_ptr == adjustedPtr) {
+    // We've been here before.  Update path to "most public"
+    if (info->path_dst_ptr_to_static_ptr == not_public_path)
+      info->path_dst_ptr_to_static_ptr = path_below;
+  } else {
+    // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
+    // to a static_type.
+    info->number_to_static_ptr += 1;
+    info->path_dst_ptr_to_static_ptr = not_public_path;
+    info->search_done = true;
+  }
 }
 
 void
@@ -301,16 +553,30 @@ __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
                                                     void* adjustedPtr,
                                                     int path_below) const
 {
-    ptrdiff_t offset_to_base = 0;
-    if (adjustedPtr != nullptr)
-    {
-        offset_to_base = __offset_flags >> __offset_shift;
-        if (__offset_flags & __virtual_mask)
-        {
-            const char* vtable = *static_cast<const char*const*>(adjustedPtr);
-            offset_to_base = update_offset_to_base(vtable, offset_to_base);
-        }
+  bool is_virtual = __offset_flags & __virtual_mask;
+  ptrdiff_t offset_to_base = 0;
+  if (info->have_object) {
+    /* We have an object to inspect, we can look through its vtables to
+       find the layout.  */
+    offset_to_base = __offset_flags >> __offset_shift;
+    if (is_virtual) {
+      const char* vtable = *static_cast<const char* const*>(adjustedPtr);
+      offset_to_base = update_offset_to_base(vtable, offset_to_base);
     }
+  } else if (!is_virtual) {
+    /* We have no object; however, for non-virtual bases, (since we do not
+       need to inspect any content) we can pretend to have an object based
+       at '0'.  */
+    offset_to_base = __offset_flags >> __offset_shift;
+  } else {
+    /* No object to inspect, and the next base is virtual.
+       We cannot indirect through the vtable to find the actual object offset.
+       So, update vbase_cookie to the new innermost virtual base using the
+       pointer to the typeinfo name as a key.  */
+    info->vbase_cookie = static_cast<const void*>(__base_type->name());
+    // .. and reset the pointer.
+    adjustedPtr = nullptr;
+  }
     __base_type->has_unambiguous_public_base(
             info,
             static_cast<char*>(adjustedPtr) + offset_to_base,
@@ -431,14 +697,22 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type,
         dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);
     if (thrown_class_type == 0)
         return false;
-    __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
+    bool have_object = adjustedPtr != nullptr;
+    __dynamic_cast_info info = {thrown_class_type, 0,      catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                have_object,       nullptr};
     info.number_of_dst_type = 1;
     thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
     if (info.path_dst_ptr_to_static_ptr == public_path)
     {
-        if (adjustedPtr != NULL)
-            adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
-        return true;
+      // In the case of a thrown null pointer, we have no object but we might
+      // well have computed the offset to where a public sub-object would be.
+      // However, we do not want to return that offset to the user; we still
+      // want them to catch a null ptr.
+      if (have_object)
+        adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
+      else
+        adjustedPtr = nullptr;
+      return true;
     }
     return false;
 }
@@ -623,174 +897,46 @@ extern "C" _LIBCXXABI_FUNC_VIS void *
 __dynamic_cast(const void *static_ptr, const __class_type_info *static_type,
                const __class_type_info *dst_type,
                std::ptrdiff_t src2dst_offset) {
-    // Possible future optimization:  Take advantage of src2dst_offset
-
     // Get (dynamic_ptr, dynamic_type) from static_ptr
-#if __has_feature(cxx_abi_relative_vtable)
-    // The vtable address will point to the first virtual function, which is 8
-    // bytes after the start of the vtable (4 for the offset from top + 4 for the typeinfo component).
-    const int32_t* vtable =
-        *reinterpret_cast<const int32_t* const*>(static_ptr);
-    int32_t offset_to_derived = vtable[-2];
-    const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
-
-    // The typeinfo component is now a relative offset to a proxy.
-    int32_t offset_to_ti_proxy = vtable[-1];
-    const uint8_t* ptr_to_ti_proxy =
-        reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy;
-    const __class_type_info* dynamic_type =
-        *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));
-#else
-    void **vtable = *static_cast<void ** const *>(static_ptr);
-    ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
-    const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
-    const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
-#endif
+    derived_object_info derived_info;
+    dyn_cast_get_derived_info(&derived_info, static_ptr);
 
     // Initialize answer to nullptr.  This will be changed from the search
     //    results if a non-null answer is found.  Regardless, this is what will
     //    be returned.
     const void* dst_ptr = 0;
-    // Initialize info struct for this search.
-    __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
 
     // Find out if we can use a giant short cut in the search
-    if (is_equal(dynamic_type, dst_type, false))
+    if (is_equal(derived_info.dynamic_type, dst_type, false))
     {
-        // We're downcasting from src_type to the complete object's dynamic
-        //   type. This is a really hot path that can be further optimized
-        //   with the `src2dst_offset` hint.
-        // In such a case, dynamic_ptr already gives the casting result if the
-        //   casting ever succeeds. All we have to do now is to check
-        //   static_ptr points to a public base sub-object of dynamic_ptr.
-
-        if (src2dst_offset >= 0)
-        {
-            // The static type is a unique public non-virtual base type of
-            //   dst_type at offset `src2dst_offset` from the origin of dst.
-            // Note that there might be other non-public static_type bases. The
-            //   hint only guarantees that the public base is non-virtual and
-            //   unique. So we have to check whether static_ptr points to that
-            //   unique public base sub-object.
-            if (offset_to_derived == -src2dst_offset)
-                dst_ptr = dynamic_ptr;
-        }
-        else if (src2dst_offset == -2)
-        {
-            // static_type is not a public base of dst_type.
-            dst_ptr = nullptr;
-        }
-        else
-        {
-            // If src2dst_offset == -3, then:
-            //   src_type is a multiple public base type but never a virtual
-            //   base type. We can't conclude that static_ptr points to those
-            //   public base sub-objects because there might be other non-
-            //   public static_type bases. The search is inevitable.
-
-            // Fallback to the slow path to check that static_type is a public
-            //   base type of dynamic_type.
-            // Using giant short cut.  Add that information to info.
-            info.number_of_dst_type = 1;
-            // Do the  search
-            dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
-#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
-            // The following if should always be false because we should
-            //   definitely find (static_ptr, static_type), either on a public
-            //   or private path
-            if (info.path_dst_ptr_to_static_ptr == unknown)
-            {
-                // We get here only if there is some kind of visibility problem
-                //   in client code.
-                static_assert(std::atomic<size_t>::is_always_lock_free, "");
-                static std::atomic<size_t> error_count(0);
-                size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
-                if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
-                    syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
-                            "should have public visibility. At least one of them is hidden. %s"
-                            ", %s.\n", static_type->name(), dynamic_type->name());
-                // Redo the search comparing type_info's using strcmp
-                info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
-                info.number_of_dst_type = 1;
-                dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
-            }
-#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
-            // Query the search.
-            if (info.path_dst_ptr_to_static_ptr == public_path)
-                dst_ptr = dynamic_ptr;
-        }
+        dst_ptr = dyn_cast_to_derived(static_ptr,
+                                      derived_info.dynamic_ptr,
+                                      static_type,
+                                      dst_type,
+                                      derived_info.offset_to_derived,
+                                      src2dst_offset);
     }
     else
     {
-        if (src2dst_offset >= 0)
-        {
-            // Optimize toward downcasting: dst_type has one unique public
-            //   static_type bases. Let's first try to do a downcast before
-            //   falling back to the slow path. The downcast succeeds if there
-            //   is at least one path regardless of visibility from
-            //   dynamic_type to dst_type.
-            const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset;
-            if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) >= reinterpret_cast<std::intptr_t>(dynamic_ptr))
-            {
-                // Try to search a path from dynamic_type to dst_type.
-                __dynamic_cast_info dynamic_to_dst_info = {dynamic_type, dst_ptr_to_static, dst_type, src2dst_offset};
-                dynamic_to_dst_info.number_of_dst_type = 1;
-                dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
-                if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {
-                    // We have found at least one path from dynamic_ptr to
-                    //   dst_ptr. The downcast can succeed.
-                    dst_ptr = dst_ptr_to_static;
-                }
-            }
-        }
+        // Optimize toward downcasting: let's first try to do a downcast before
+        //   falling back to the slow path.
+        dst_ptr = dyn_cast_try_downcast(static_ptr,
+                                        derived_info.dynamic_ptr,
+                                        dst_type,
+                                        derived_info.dynamic_type,
+                                        src2dst_offset);
 
         if (!dst_ptr)
         {
-            // Not using giant short cut.  Do the search
-            dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
-#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
-            // The following if should always be false because we should
-            //   definitely find (static_ptr, static_type), either on a public
-            //   or private path
-            if (info.path_dst_ptr_to_static_ptr == unknown &&
-                info.path_dynamic_ptr_to_static_ptr == unknown)
-            {
-                static_assert(std::atomic<size_t>::is_always_lock_free, "");
-                static std::atomic<size_t> error_count(0);
-                size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
-                if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
-                    syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
-                                    "has hidden visibility or is defined in more than one translation "
-                                    "unit. They should all have public visibility. "
-                                    "%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
-                            dst_type->name());
-                // Redo the search comparing type_info's using strcmp
-                info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
-                dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
-            }
-#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
-            // Query the search.
-            switch (info.number_to_static_ptr)
-            {
-            case 0:
-                if (info.number_to_dst_ptr == 1 &&
-                        info.path_dynamic_ptr_to_static_ptr == public_path &&
-                        info.path_dynamic_ptr_to_dst_ptr == public_path)
-                    dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
-                break;
-            case 1:
-                if (info.path_dst_ptr_to_static_ptr == public_path ||
-                    (
-                        info.number_to_dst_ptr == 0 &&
-                        info.path_dynamic_ptr_to_static_ptr == public_path &&
-                        info.path_dynamic_ptr_to_dst_ptr == public_path
-                    )
-                )
-                    dst_ptr = info.dst_ptr_leading_to_static_ptr;
-                break;
-            }
+            dst_ptr = dyn_cast_slow(static_ptr,
+                                    derived_info.dynamic_ptr,
+                                    static_type,
+                                    dst_type,
+                                    derived_info.dynamic_type,
+                                    src2dst_offset);
         }
     }
+
     return const_cast<void*>(dst_ptr);
 }
 
@@ -1075,7 +1221,7 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
                     if (info->search_done)
                         break;
                     // If we just found a dst_type with a public path to (static_ptr, static_type),
-                    //    then the only reason to continue the search is to make sure sure
+                    //    then the only reason to continue the search is to make sure
                     //    no other dst_type points to (static_ptr, static_type).
                     //    If !diamond, then we don't need to search here.
                     // if we just found a dst_type with a private path to (static_ptr, static_type),
lib/libcxxabi/src/private_typeinfo.h
@@ -110,6 +110,13 @@ struct _LIBCXXABI_HIDDEN __dynamic_cast_info
     bool found_any_static_type;
     // Set whenever a search can be stopped
     bool search_done;
+
+    // Data that modifies the search mechanism.
+
+    // There is no object (seen when we throw a null pointer to object).
+    bool have_object;
+    // Virtual base
+    const void* vbase_cookie;
 };
 
 // Has no base class
lib/libcxxabi/src/stdlib_new_delete.cpp
@@ -7,7 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "__cxxabi_config.h"
+#include "abort_message.h"
+#include "include/overridable_function.h" // from libc++
 #include <__memory/aligned_alloc.h>
+#include <cstddef>
 #include <cstdlib>
 #include <new>
 
@@ -25,241 +28,216 @@
 #  error libc++ and libc++abi seem to disagree on whether exceptions are enabled
 #endif
 
-// ------------------ BEGIN COPY ------------------
-// Implement all new and delete operators as weak definitions
-// in this shared library, so that they can be overridden by programs
-// that define non-weak copies of the functions.
-
-_LIBCPP_WEAK
-void *
-operator new(std::size_t size) _THROW_BAD_ALLOC
-{
-    if (size == 0)
-        size = 1;
-    void* p;
-    while ((p = std::malloc(size)) == nullptr)
-    {
-        // If malloc fails and there is a new_handler,
-        // call it to try free up memory.
-        std::new_handler nh = std::get_new_handler();
-        if (nh)
-            nh();
-        else
+inline void __throw_bad_alloc_shim() {
 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-            throw std::bad_alloc();
+  throw std::bad_alloc();
 #else
-            break;
+  abort_message("bad_alloc was thrown in -fno-exceptions mode");
 #endif
-    }
-    return p;
-}
-
-_LIBCPP_WEAK
-void*
-operator new(size_t size, const std::nothrow_t&) noexcept
-{
-    void* p = nullptr;
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-    try
-    {
-#endif // _LIBCPP_HAS_NO_EXCEPTIONS
-        p = ::operator new(size);
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-    }
-    catch (...)
-    {
-    }
-#endif // _LIBCPP_HAS_NO_EXCEPTIONS
-    return p;
-}
-
-_LIBCPP_WEAK
-void*
-operator new[](size_t size) _THROW_BAD_ALLOC
-{
-    return ::operator new(size);
 }
 
-_LIBCPP_WEAK
-void*
-operator new[](size_t size, const std::nothrow_t&) noexcept
-{
-    void* p = nullptr;
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-    try
-    {
-#endif // _LIBCPP_HAS_NO_EXCEPTIONS
-        p = ::operator new[](size);
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-    }
-    catch (...)
-    {
-    }
-#endif // _LIBCPP_HAS_NO_EXCEPTIONS
-    return p;
-}
+#define _LIBCPP_ASSERT_SHIM(expr, str)                                                                                 \
+  do {                                                                                                                 \
+    if (!expr)                                                                                                         \
+      abort_message(str);                                                                                              \
+  } while (false)
 
-_LIBCPP_WEAK
-void
-operator delete(void* ptr) noexcept
-{
-    std::free(ptr);
-}
-
-_LIBCPP_WEAK
-void
-operator delete(void* ptr, const std::nothrow_t&) noexcept
-{
-    ::operator delete(ptr);
-}
-
-_LIBCPP_WEAK
-void
-operator delete(void* ptr, size_t) noexcept
-{
-    ::operator delete(ptr);
-}
-
-_LIBCPP_WEAK
-void
-operator delete[] (void* ptr) noexcept
-{
-    ::operator delete(ptr);
-}
+// ------------------ BEGIN COPY ------------------
+// Implement all new and delete operators as weak definitions
+// in this shared library, so that they can be overridden by programs
+// that define non-weak copies of the functions.
 
-_LIBCPP_WEAK
-void
-operator delete[] (void* ptr, const std::nothrow_t&) noexcept
-{
-    ::operator delete[](ptr);
+static void* operator_new_impl(std::size_t size) {
+  if (size == 0)
+    size = 1;
+  void* p;
+  while ((p = std::malloc(size)) == nullptr) {
+    // If malloc fails and there is a new_handler,
+    // call it to try free up memory.
+    std::new_handler nh = std::get_new_handler();
+    if (nh)
+      nh();
+    else
+      break;
+  }
+  return p;
+}
+
+_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
+  void* p = operator_new_impl(size);
+  if (p == nullptr)
+    __throw_bad_alloc_shim();
+  return p;
+}
+
+_LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
+#ifdef _LIBCPP_HAS_NO_EXCEPTIONS
+#  if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
+  _LIBCPP_ASSERT_SHIM(
+      !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
+      "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
+      "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
+      "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case "
+      "it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its "
+      "contract (since it should return nullptr upon failure). Please make sure you override "
+      "`operator new(size_t, nothrow_t)` as well.");
+#  endif
+
+  return operator_new_impl(size);
+#else
+  void* p = nullptr;
+  try {
+    p = ::operator new(size);
+  } catch (...) {
+  }
+  return p;
+#endif
 }
 
-_LIBCPP_WEAK
-void
-operator delete[] (void* ptr, size_t) noexcept
-{
-    ::operator delete[](ptr);
+_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
+  return ::operator new(size);
 }
 
-#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
+_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept {
+#ifdef _LIBCPP_HAS_NO_EXCEPTIONS
+#  if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
+  _LIBCPP_ASSERT_SHIM(
+      !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
+      "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
+      "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
+      "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case "
+      "it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its "
+      "contract (since it should return nullptr upon failure). Please make sure you override "
+      "`operator new[](size_t, nothrow_t)` as well.");
+#  endif
 
-_LIBCPP_WEAK
-void *
-operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
-{
-    if (size == 0)
-        size = 1;
-    if (static_cast<size_t>(alignment) < sizeof(void*))
-      alignment = std::align_val_t(sizeof(void*));
-
-    // Try allocating memory. If allocation fails and there is a new_handler,
-    // call it to try free up memory, and try again until it succeeds, or until
-    // the new_handler decides to terminate.
-    //
-    // If allocation fails and there is no new_handler, we throw bad_alloc
-    // (or return nullptr if exceptions are disabled).
-    void* p;
-    while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr)
-    {
-        std::new_handler nh = std::get_new_handler();
-        if (nh)
-            nh();
-        else {
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-            throw std::bad_alloc();
+  return operator_new_impl(size);
 #else
-            break;
+  void* p = nullptr;
+  try {
+    p = ::operator new[](size);
+  } catch (...) {
+  }
+  return p;
 #endif
-        }
-    }
-    return p;
 }
 
-_LIBCPP_WEAK
-void*
-operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
-{
-    void* p = nullptr;
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-    try
-    {
-#endif // _LIBCPP_HAS_NO_EXCEPTIONS
-        p = ::operator new(size, alignment);
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-    }
-    catch (...)
-    {
-    }
-#endif // _LIBCPP_HAS_NO_EXCEPTIONS
-    return p;
-}
+_LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); }
 
-_LIBCPP_WEAK
-void*
-operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
-{
-    return ::operator new(size, alignment);
-}
+_LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); }
 
-_LIBCPP_WEAK
-void*
-operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
-{
-    void* p = nullptr;
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-    try
-    {
-#endif // _LIBCPP_HAS_NO_EXCEPTIONS
-        p = ::operator new[](size, alignment);
-#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-    }
-    catch (...)
-    {
-    }
-#endif // _LIBCPP_HAS_NO_EXCEPTIONS
-    return p;
-}
-
-_LIBCPP_WEAK
-void
-operator delete(void* ptr, std::align_val_t) noexcept
-{
-    std::__libcpp_aligned_free(ptr);
-}
+_LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); }
 
-_LIBCPP_WEAK
-void
-operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
-{
-    ::operator delete(ptr, alignment);
-}
+_LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); }
 
-_LIBCPP_WEAK
-void
-operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept
-{
-    ::operator delete(ptr, alignment);
-}
+_LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); }
 
-_LIBCPP_WEAK
-void
-operator delete[] (void* ptr, std::align_val_t alignment) noexcept
-{
-    ::operator delete(ptr, alignment);
-}
+_LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); }
 
-_LIBCPP_WEAK
-void
-operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
-{
-    ::operator delete[](ptr, alignment);
-}
+#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
 
-_LIBCPP_WEAK
-void
-operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept
-{
-    ::operator delete[](ptr, alignment);
+static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
+  if (size == 0)
+    size = 1;
+  if (static_cast<size_t>(alignment) < sizeof(void*))
+    alignment = std::align_val_t(sizeof(void*));
+
+  // Try allocating memory. If allocation fails and there is a new_handler,
+  // call it to try free up memory, and try again until it succeeds, or until
+  // the new_handler decides to terminate.
+  void* p;
+  while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr) {
+    std::new_handler nh = std::get_new_handler();
+    if (nh)
+      nh();
+    else
+      break;
+  }
+  return p;
+}
+
+_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
+operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
+  void* p = operator_new_aligned_impl(size, alignment);
+  if (p == nullptr)
+    __throw_bad_alloc_shim();
+  return p;
+}
+
+_LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
+#  ifdef _LIBCPP_HAS_NO_EXCEPTIONS
+#    if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
+  _LIBCPP_ASSERT_SHIM(
+      !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)),
+      "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
+      "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
+      "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
+      "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` "
+      "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override "
+      "`operator new(size_t, align_val_t, nothrow_t)` as well.");
+#    endif
+
+  return operator_new_aligned_impl(size, alignment);
+#  else
+  void* p = nullptr;
+  try {
+    p = ::operator new(size, alignment);
+  } catch (...) {
+  }
+  return p;
+#  endif
+}
+
+_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
+operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
+  return ::operator new(size, alignment);
+}
+
+_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
+#  ifdef _LIBCPP_HAS_NO_EXCEPTIONS
+#    if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
+  _LIBCPP_ASSERT_SHIM(
+      !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])),
+      "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
+      "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
+      "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
+      "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
+      "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
+      "override "
+      "`operator new[](size_t, align_val_t, nothrow_t)` as well.");
+#    endif
+
+  return operator_new_aligned_impl(size, alignment);
+#  else
+  void* p = nullptr;
+  try {
+    p = ::operator new[](size, alignment);
+  } catch (...) {
+  }
+  return p;
+#  endif
+}
+
+_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); }
+
+_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
+  ::operator delete(ptr, alignment);
+}
+
+_LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept {
+  ::operator delete(ptr, alignment);
+}
+
+_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept {
+  ::operator delete(ptr, alignment);
+}
+
+_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
+  ::operator delete[](ptr, alignment);
+}
+
+_LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept {
+  ::operator delete[](ptr, alignment);
 }
 
 #endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION