libcxxabi: update to LLVM 21

This commit is contained in:
Alex Rønne Petersen 2025-07-16 10:35:26 +02:00
parent ce7339e80a
commit e84e9d3a01
No known key found for this signature in database
5 changed files with 124 additions and 70 deletions

View file

@ -9,6 +9,7 @@
// new_handler.
//===----------------------------------------------------------------------===//
#include <cstdlib> // std::abort
#include <exception>
#include <new>
#include "abort_message.h"
@ -94,7 +95,7 @@ static void demangling_unexpected_handler()
static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
#else // !LIBCXXABI_SILENT_TERMINATE
static constexpr std::terminate_handler default_terminate_handler = ::abort;
static constexpr std::terminate_handler default_terminate_handler = std::abort;
static constexpr std::terminate_handler default_unexpected_handler = std::terminate;
#endif // !LIBCXXABI_SILENT_TERMINATE

View file

@ -19,6 +19,14 @@
#include "../abort_message.h"
#endif
#ifndef _LIBCPP_LOG_HARDENING_FAILURE
// Libc++abi does not have any functionality to log and continue, so we drop
// error messages when we build the demangler with `observe` assertion semantic.
// Once the layering with libc++ is improved, this could use the libc++
// functionality to log hardening failures.
#define _LIBCPP_LOG_HARDENING_FAILURE(message) ((void)0)
#endif
#include <version>
#ifdef _MSC_VER

View file

@ -21,6 +21,7 @@
#include "Utility.h"
#include <algorithm>
#include <cctype>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@ -38,8 +39,10 @@
DEMANGLE_NAMESPACE_BEGIN
template <class T, size_t N> class PODSmallVector {
static_assert(std::is_trivial<T>::value,
"T is required to be a trivial type");
static_assert(std::is_trivially_copyable<T>::value,
"T is required to be a trivially copyable type");
static_assert(std::is_trivially_default_constructible<T>::value,
"T is required to be trivially default constructible");
T *First = nullptr;
T *Last = nullptr;
T *Cap = nullptr;
@ -162,18 +165,18 @@ class NodeArray;
// traversed by the printLeft/Right functions to produce a demangled string.
class Node {
public:
enum Kind : unsigned char {
enum Kind : uint8_t {
#define NODE(NodeKind) K##NodeKind,
#include "ItaniumNodes.def"
};
/// Three-way bool to track a cached value. Unknown is possible if this node
/// has an unexpanded parameter pack below it that may affect this cache.
enum class Cache : unsigned char { Yes, No, Unknown, };
enum class Cache : uint8_t { Yes, No, Unknown, };
/// Operator precedence for expression nodes. Used to determine required
/// parens in expression emission.
enum class Prec {
enum class Prec : uint8_t {
Primary,
Postfix,
Unary,
@ -281,20 +284,11 @@ public:
}
void print(OutputBuffer &OB) const {
printLeft(OB);
OB.printLeft(*this);
if (RHSComponentCache != Cache::No)
printRight(OB);
OB.printRight(*this);
}
// Print the "left" side of this Node into OutputBuffer.
virtual void printLeft(OutputBuffer &) const = 0;
// Print the "right". This distinction is necessary to represent C++ types
// that appear on the RHS of their subtype, such as arrays or functions.
// Since most types don't have such a component, provide a default
// implementation.
virtual void printRight(OutputBuffer &) const {}
// Print an initializer list of this type. Returns true if we printed a custom
// representation, false if nothing has been printed and the default
// representation should be used.
@ -310,6 +304,24 @@ public:
#ifndef NDEBUG
DEMANGLE_DUMP_METHOD void dump() const;
#endif
private:
friend class OutputBuffer;
// Print the "left" side of this Node into OutputBuffer.
//
// Note, should only be called from OutputBuffer implementations.
// Call \ref OutputBuffer::printLeft instead.
virtual void printLeft(OutputBuffer &) const = 0;
// Print the "right". This distinction is necessary to represent C++ types
// that appear on the RHS of their subtype, such as arrays or functions.
// Since most types don't have such a component, provide a default
// implementation.
//
// Note, should only be called from OutputBuffer implementations.
// Call \ref OutputBuffer::printRight instead.
virtual void printRight(OutputBuffer &) const {}
};
class NodeArray {
@ -458,11 +470,11 @@ public:
}
void printLeft(OutputBuffer &OB) const override {
Child->printLeft(OB);
OB.printLeft(*Child);
printQuals(OB);
}
void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
};
class ConversionOperatorType final : public Node {
@ -491,7 +503,7 @@ public:
template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
void printLeft(OutputBuffer &OB) const override {
Ty->printLeft(OB);
OB.printLeft(*Ty);
OB += Postfix;
}
};
@ -577,7 +589,7 @@ struct AbiTagAttr : Node {
std::string_view getBaseName() const override { return Base->getBaseName(); }
void printLeft(OutputBuffer &OB) const override {
Base->printLeft(OB);
OB.printLeft(*Base);
OB += "[abi:";
OB += Tag;
OB += "]";
@ -603,8 +615,6 @@ class ObjCProtoName : public Node {
const Node *Ty;
std::string_view Protocol;
friend class PointerType;
public:
ObjCProtoName(const Node *Ty_, std::string_view Protocol_)
: Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
@ -616,6 +626,8 @@ public:
static_cast<const NameType *>(Ty)->getName() == "objc_object";
}
std::string_view getProtocol() const { return Protocol; }
void printLeft(OutputBuffer &OB) const override {
Ty->print(OB);
OB += "<";
@ -644,7 +656,7 @@ public:
// We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
if (Pointee->getKind() != KObjCProtoName ||
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
Pointee->printLeft(OB);
OB.printLeft(*Pointee);
if (Pointee->hasArray(OB))
OB += " ";
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@ -653,7 +665,7 @@ public:
} else {
const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
OB += "id<";
OB += objcProto->Protocol;
OB += objcProto->getProtocol();
OB += ">";
}
}
@ -663,7 +675,7 @@ public:
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
OB += ")";
Pointee->printRight(OB);
OB.printRight(*Pointee);
}
}
};
@ -729,7 +741,7 @@ public:
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
if (!Collapsed.second)
return;
Collapsed.second->printLeft(OB);
OB.printLeft(*Collapsed.second);
if (Collapsed.second->hasArray(OB))
OB += " ";
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@ -746,7 +758,7 @@ public:
return;
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
OB += ")";
Collapsed.second->printRight(OB);
OB.printRight(*Collapsed.second);
}
};
@ -766,7 +778,7 @@ public:
}
void printLeft(OutputBuffer &OB) const override {
MemberType->printLeft(OB);
OB.printLeft(*MemberType);
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
OB += "(";
else
@ -778,7 +790,7 @@ public:
void printRight(OutputBuffer &OB) const override {
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
OB += ")";
MemberType->printRight(OB);
OB.printRight(*MemberType);
}
};
@ -798,7 +810,7 @@ public:
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
bool hasArraySlow(OutputBuffer &) const override { return true; }
void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
void printRight(OutputBuffer &OB) const override {
if (OB.back() != ']')
@ -807,7 +819,7 @@ public:
if (Dimension)
Dimension->print(OB);
OB += "]";
Base->printRight(OB);
OB.printRight(*Base);
}
bool printInitListAsType(OutputBuffer &OB,
@ -851,7 +863,7 @@ public:
// by printing out the return types's left, then print our parameters, then
// finally print right of the return type.
void printLeft(OutputBuffer &OB) const override {
Ret->printLeft(OB);
OB.printLeft(*Ret);
OB += " ";
}
@ -859,7 +871,7 @@ public:
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
Ret->printRight(OB);
OB.printRight(*Ret);
if (CVQuals & QualConst)
OB += " const";
@ -964,6 +976,8 @@ public:
FunctionRefQual getRefQual() const { return RefQual; }
NodeArray getParams() const { return Params; }
const Node *getReturnType() const { return Ret; }
const Node *getAttrs() const { return Attrs; }
const Node *getRequires() const { return Requires; }
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@ -972,10 +986,11 @@ public:
void printLeft(OutputBuffer &OB) const override {
if (Ret) {
Ret->printLeft(OB);
OB.printLeft(*Ret);
if (!Ret->hasRHSComponent(OB))
OB += " ";
}
Name->print(OB);
}
@ -983,8 +998,9 @@ public:
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
if (Ret)
Ret->printRight(OB);
OB.printRight(*Ret);
if (CVQuals & QualConst)
OB += " const";
@ -1324,14 +1340,14 @@ public:
template<typename Fn> void match(Fn F) const { F(Name, Type); }
void printLeft(OutputBuffer &OB) const override {
Type->printLeft(OB);
OB.printLeft(*Type);
if (!Type->hasRHSComponent(OB))
OB += " ";
}
void printRight(OutputBuffer &OB) const override {
Name->print(OB);
Type->printRight(OB);
OB.printRight(*Type);
}
};
@ -1376,11 +1392,11 @@ public:
template<typename Fn> void match(Fn F) const { F(Param); }
void printLeft(OutputBuffer &OB) const override {
Param->printLeft(OB);
OB.printLeft(*Param);
OB += "...";
}
void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
};
/// An unexpanded parameter pack (either in the expression or type context). If
@ -1445,13 +1461,13 @@ public:
initializePackExpansion(OB);
size_t Idx = OB.CurrentPackIndex;
if (Idx < Data.size())
Data[Idx]->printLeft(OB);
OB.printLeft(*Data[Idx]);
}
void printRight(OutputBuffer &OB) const override {
initializePackExpansion(OB);
size_t Idx = OB.CurrentPackIndex;
if (Idx < Data.size())
Data[Idx]->printRight(OB);
OB.printRight(*Data[Idx]);
}
};
@ -1609,13 +1625,13 @@ struct ForwardTemplateReference : Node {
if (Printing)
return;
ScopedOverride<bool> SavePrinting(Printing, true);
Ref->printLeft(OB);
OB.printLeft(*Ref);
}
void printRight(OutputBuffer &OB) const override {
if (Printing)
return;
ScopedOverride<bool> SavePrinting(Printing, true);
Ref->printRight(OB);
OB.printRight(*Ref);
}
};
@ -1767,7 +1783,7 @@ public:
void printLeft(OutputBuffer &OB) const override {
OB += "~";
Base->printLeft(OB);
OB.printLeft(*Base);
}
};
@ -2047,7 +2063,7 @@ public:
{
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
OB += "<";
To->printLeft(OB);
OB.printLeft(*To);
OB += ">";
}
OB.printOpen();
@ -3406,7 +3422,7 @@ const typename AbstractManglingParser<
{"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"},
{"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="},
{"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"},
{"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
{"pm", OperatorInfo::Member, /*Named*/ true, Node::Prec::PtrMem,
"operator->*"},
{"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"},
{"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"},
@ -4452,7 +4468,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
return nullptr;
if (!consumeIf('_'))
return nullptr;
return make<BitIntType>(Size, Signed);
// The front end expects this to be available for Substitution
Result = make<BitIntType>(Size, Signed);
break;
}
// ::= Di # char32_t
case 'i':
@ -5739,14 +5757,16 @@ struct FloatData<double>
template <>
struct FloatData<long double>
{
#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
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;
#if __LDBL_MANT_DIG__ == 113 || __LDBL_MANT_DIG__ == 106
static const size_t mangled_size = 32;
#elif __LDBL_MANT_DIG__ == 53 || defined(_MSC_VER)
// MSVC doesn't define __LDBL_MANT_DIG__, but it has long double equal to
// regular double on all current architectures.
static const size_t mangled_size = 16;
#elif __LDBL_MANT_DIG__ == 64
static const size_t mangled_size = 20;
#else
static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
#error Unknown size for __LDBL_MANT_DIG__
#endif
// `-0x1.ffffffffffffffffffffffffffffp+16383` + 'L' + '\0' == 42 bytes.
// 28 'f's * 4 bits == 112 bits, which is the number of mantissa bits.
@ -6176,6 +6196,10 @@ struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
Alloc>::AbstractManglingParser;
};
inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
DEMANGLE_NAMESPACE_END
#if defined(__clang__)

View file

@ -27,6 +27,8 @@
DEMANGLE_NAMESPACE_BEGIN
class Node;
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputBuffer {
@ -79,10 +81,24 @@ public:
OutputBuffer(const OutputBuffer &) = delete;
OutputBuffer &operator=(const OutputBuffer &) = delete;
virtual ~OutputBuffer() {}
operator std::string_view() const {
return std::string_view(Buffer, CurrentPosition);
}
/// Called by the demangler when printing the demangle tree. By
/// default calls into \c Node::print{Left|Right} but can be overriden
/// by clients to track additional state when printing the demangled name.
virtual void printLeft(const Node &N);
virtual void printRight(const Node &N);
/// Called when we write to this object anywhere other than the end.
virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {}
/// Called when we make the \c CurrentPosition of this object smaller.
virtual void notifyDeletion(size_t /*OldPos*/, size_t /*NewPos*/) {}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
@ -120,12 +136,16 @@ public:
OutputBuffer &prepend(std::string_view R) {
size_t Size = R.size();
if (!Size)
return *this;
grow(Size);
std::memmove(Buffer + Size, Buffer, CurrentPosition);
std::memcpy(Buffer, &*R.begin(), Size);
CurrentPosition += Size;
notifyInsertion(/*Position=*/0, /*Count=*/Size);
return *this;
}
@ -161,14 +181,20 @@ public:
DEMANGLE_ASSERT(Pos <= CurrentPosition, "");
if (N == 0)
return;
grow(N);
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
std::memcpy(Buffer + Pos, S, N);
CurrentPosition += N;
notifyInsertion(Pos, N);
}
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
void setCurrentPosition(size_t NewPos) {
notifyDeletion(CurrentPosition, NewPos);
CurrentPosition = NewPos;
}
char back() const {
DEMANGLE_ASSERT(CurrentPosition, "");

View file

@ -63,7 +63,7 @@ static void* operator_new_impl(std::size_t size) {
return p;
}
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size)) _THROW_BAD_ALLOC {
void* p = operator_new_impl(size);
if (p == nullptr)
__throw_bad_alloc_shim();
@ -74,7 +74,7 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
#if !_LIBCPP_HAS_EXCEPTIONS
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
_LIBCPP_ASSERT_SHIM(
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
(!std::__is_function_overridden < 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 "
@ -94,15 +94,13 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
#endif
}
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
return ::operator new(size);
}
_LIBCPP_OVERRIDABLE_FUNCTION(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 {
#if !_LIBCPP_HAS_EXCEPTIONS
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
_LIBCPP_ASSERT_SHIM(
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
(!std::__is_function_overridden < 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 "
@ -156,8 +154,7 @@ static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignm
return p;
}
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
_LIBCPP_OVERRIDABLE_FUNCTION(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();
@ -168,7 +165,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
# if !_LIBCPP_HAS_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)),
(!std::__is_function_overridden < 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 "
@ -188,8 +185,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
# endif
}
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
return ::operator new(size, alignment);
}
@ -197,14 +193,13 @@ _LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const
# if !_LIBCPP_HAS_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[])),
(!std::__is_function_overridden < 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.");
"override `operator new[](size_t, align_val_t, nothrow_t)` as well.");
# endif
return operator_new_aligned_impl(size, alignment);