diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index 4dca309e3cbc..a237cf724df0 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -3576,7 +3576,11 @@ Node *AbstractManglingParser::parseType() { StringView Res = parseBareSourceName(); if (Res.empty()) return nullptr; - return make(Res); + // Typically, s are not considered substitution candidates, + // but the exception to that exception is vendor extended types (Itanium C++ + // ABI 5.9.1). + Result = make(Res); + break; } case 'D': switch (look(1)) { diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp index bc99ca7cee9c..4e1c1f5d2340 100644 --- a/libcxxabi/test/test_demangle.pass.cpp +++ b/libcxxabi/test/test_demangle.pass.cpp @@ -29765,7 +29765,10 @@ const char* cases[][2] = {"____Z3foo_block_invoke.25", "invocation function for block in foo"}, {"__Z1fv", "f()"}, - {"_Z2tfIZUb_E1SEiv", "int tf<'block-literal'::S>()"} + {"_Z2tfIZUb_E1SEiv", "int tf<'block-literal'::S>()"}, + + // Vendor extension types are substitution candidates. + {"_Z1fu3fooS_", "f(foo, foo)"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index 4dca309e3cbc..a237cf724df0 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -3576,7 +3576,11 @@ Node *AbstractManglingParser::parseType() { StringView Res = parseBareSourceName(); if (Res.empty()) return nullptr; - return make(Res); + // Typically, s are not considered substitution candidates, + // but the exception to that exception is vendor extended types (Itanium C++ + // ABI 5.9.1). + Result = make(Res); + break; } case 'D': switch (look(1)) {