Index: src/cxa_demangle.cpp =================================================================== --- src/cxa_demangle.cpp +++ src/cxa_demangle.cpp @@ -12,6 +12,7 @@ // - enable_if attribute // - decomposition declarations // - C++ modules TS +// - inheriting constructors #define _LIBCPP_NO_EXCEPTIONS @@ -3128,11 +3129,33 @@ return first; } +// Parse a type in the context of a function parameter. Here, the type can be +// optionally followed by a pass_object_size attribute. Unlike other vendor +// extension attributes, clang emits this attribute after the mangling for the +// type it applies to, so we have to special-case it. +// +// ::= U17pass_object_size [0-9] # extension +const char* +parse_function_param_type(const char* first, const char* last, Db& db) +{ + const char* t = parse_type(first, last, db); + if (t != first && StringView(t, last).startsWith("U17pass_object_size")) + { + const char* t2 = t + std::strlen("U17pass_object_size"); + if (t2 != last && *t2 >= '0' && *t2 <= '9' && !db.Names.empty()) + { + db.Names.back() = db.make( + db.make(StringView(t+3, t2+1)), db.Names.back()); + t = t2+1; + } + } + return t; +} + // ::= R # & ref-qualifier // ::= O # && ref-qualifier - -// ::= F [Y] [] E - +// +// ::= F [Y] [] E const char* parse_function_type(const char* first, const char* last, Db& db) { @@ -3186,7 +3209,7 @@ continue; } size_t k0 = db.Names.size(); - t1 = parse_type(t, last, db); + t1 = parse_function_param_type(t, last, db); size_t k1 = db.Names.size(); if (t1 == t || t1 == last || k1 < k0) return first; @@ -4454,7 +4477,7 @@ { while (true) { - const char* t1 = parse_type(t0, last, db); + const char* t1 = parse_function_param_type(t0, last, db); if (t1 == t0) break; t0 = t1; @@ -6021,7 +6044,7 @@ size_t params_begin = db.Names.size(); while (true) { - t2 = parse_type(t, last, db); + t2 = parse_function_param_type(t, last, db); if (t2 == t) break; t = t2; Index: test/test_demangle.pass.cpp =================================================================== --- test/test_demangle.pass.cpp +++ test/test_demangle.pass.cpp @@ -29611,6 +29611,12 @@ {"_ZN1SB5outer1fB5innerEv", "S[abi:outer]::f[abi:inner]()"}, {"_ZN1SC2B8ctor_tagEv", "S::S[abi:ctor_tag]()"}, {"_ZplB4MERP1SS_", "operator+[abi:MERP](S, S)"}, + // attribute pass_object_size + {"_Z27NoViableOverloadObjectSize0PvU17pass_object_size0", "NoViableOverloadObjectSize0(pass_object_size0 void*)"}, + {"_ZN14noninline_virt1AC2EiO1QPvU17pass_object_size0", "noninline_virt::A::A(int, Q&&, pass_object_size0 void*)"}, + {"_ZZN7lambdas7LambdasEPcENK3$_0clEPvU17pass_object_size0", "lambdas::Lambdas(char*)::$_0::operator()(pass_object_size0 void*) const"}, + {"_ZN8variadic6AsCtorC1EPKcU17pass_object_size0dz", "variadic::AsCtor::AsCtor(pass_object_size0 char const*, double, ...)"}, + {"_Z1fPvU17pass_object_size0S_U17pass_object_size1S_U17pass_object_size2S_U17pass_object_size3", "f(pass_object_size0 void*, pass_object_size1 void*, pass_object_size2 void*, pass_object_size3 void*)"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]);