diff options
author | Erik Pilkington <erik.pilkington@gmail.com> | 2018-02-14 01:08:20 +0000 |
---|---|---|
committer | Erik Pilkington <erik.pilkington@gmail.com> | 2018-02-14 01:08:20 +0000 |
commit | 7e027acf6917a3b90159b1b4b8a800f0d20bf6f8 (patch) | |
tree | 63b7a3a31edff244d935ad268a2456107727b383 | |
parent | bdaf882003ff55c1f7d0397e42b4cfca92629257 (diff) |
[demangler] Support for exception specifications on function types.
git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@325093 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | src/cxa_demangle.cpp | 84 | ||||
-rw-r--r-- | test/test_demangle.pass.cpp | 16 |
2 files changed, 96 insertions, 4 deletions
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp index 82b9de0..2a004e6 100644 --- a/src/cxa_demangle.cpp +++ b/src/cxa_demangle.cpp @@ -175,6 +175,8 @@ public: KPointerToMemberType, KArrayType, KFunctionType, + KNoexceptSpec, + KDynamicExceptionSpec, KFunctionEncoding, KLiteralOperator, KSpecialName, @@ -720,16 +722,21 @@ class FunctionType final : public Node { NodeArray Params; Qualifiers CVQuals; FunctionRefQual RefQual; + Node *ExceptionSpec; public: FunctionType(Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, - FunctionRefQual RefQual_) + FunctionRefQual RefQual_, Node *ExceptionSpec_) : Node(KFunctionType, Ret_->ParameterPackSize, /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, /*FunctionCache=*/Cache::Yes), - Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_) { + Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), + ExceptionSpec(ExceptionSpec_) { for (Node *P : Params) ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize); + if (ExceptionSpec != nullptr) + ParameterPackSize = + std::min(ParameterPackSize, ExceptionSpec->ParameterPackSize); } bool hasRHSComponentSlow(OutputStream &) const override { return true; } @@ -764,6 +771,39 @@ public: S += " &"; else if (RefQual == FrefQualRValue) S += " &&"; + + if (ExceptionSpec != nullptr) { + S += ' '; + ExceptionSpec->print(S); + } + } +}; + +class NoexceptSpec : public Node { + Node *E; +public: + NoexceptSpec(Node *E_) : Node(KNoexceptSpec, E_->ParameterPackSize), E(E_) {} + + void printLeft(OutputStream &S) const override { + S += "noexcept("; + E->print(S); + S += ")"; + } +}; + +class DynamicExceptionSpec : public Node { + NodeArray Types; +public: + DynamicExceptionSpec(NodeArray Types_) + : Node(KDynamicExceptionSpec), Types(Types_) { + for (Node *T : Types) + ParameterPackSize = std::min(ParameterPackSize, T->ParameterPackSize); + } + + void printLeft(OutputStream &S) const override { + S += "throw("; + Types.printWithComma(S); + S += ')'; } }; @@ -2370,6 +2410,29 @@ StringView Db::parseBareSourceName() { // <ref-qualifier> ::= O # && ref-qualifier Node *Db::parseFunctionType() { Qualifiers CVQuals = parseCVQualifiers(); + + Node *ExceptionSpec = nullptr; + if (consumeIf("Do")) { + ExceptionSpec = make<NameType>("noexcept"); + } else if (consumeIf("DO")) { + Node *E = parseExpr(); + if (E == nullptr || !consumeIf('E')) + return nullptr; + ExceptionSpec = make<NoexceptSpec>(E); + } else if (consumeIf("Dw")) { + size_t SpecsBegin = Names.size(); + while (!consumeIf('E')) { + Node *T = parseType(); + if (T == nullptr) + return nullptr; + Names.push_back(T); + } + ExceptionSpec = + make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin)); + } + + consumeIf("Dx"); // transaction safe + if (!consumeIf('F')) return nullptr; consumeIf('Y'); // extern "C" @@ -2399,7 +2462,8 @@ Node *Db::parseFunctionType() { } NodeArray Params = popTrailingNodeArray(ParamsBegin); - return make<FunctionType>(ReturnType, Params, CVQuals, ReferenceQualifier); + return make<FunctionType>(ReturnType, Params, CVQuals, + ReferenceQualifier, ExceptionSpec); } // extension: @@ -2599,7 +2663,11 @@ Node *Db::parseType() { if (look(AfterQuals) == 'r') ++AfterQuals; if (look(AfterQuals) == 'V') ++AfterQuals; if (look(AfterQuals) == 'K') ++AfterQuals; - if (look(AfterQuals) == 'F') { + + if (look(AfterQuals) == 'F' || + (look(AfterQuals) == 'D' && + (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' || + look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) { Result = parseFunctionType(); break; } @@ -2761,6 +2829,14 @@ Node *Db::parseType() { Result = make<ParameterPackExpansion>(Child); break; } + // Exception specifier on a function type. + case 'o': + case 'O': + case 'w': + // Transaction safe function type. + case 'x': + Result = parseFunctionType(); + break; } break; // ::= <function-type> diff --git a/test/test_demangle.pass.cpp b/test/test_demangle.pass.cpp index 37c6292..9c1e9e3 100644 --- a/test/test_demangle.pass.cpp +++ b/test/test_demangle.pass.cpp @@ -29694,6 +29694,22 @@ const char* cases[][2] = // Inheriting constructors: {"_ZN1BCI21AEi", "B::B(int)"}, {"_ZN1DCI21CIiEET_", "D::D(int)"}, + + // Exception specifiers: + {"_Z1bPDoFivE", "b(int (*)() noexcept)"}, + {"_Z1fILb0EEvPDOT_EFivE", "void f<false>(int (*)() noexcept(false))"}, + {"_Z1fILb1EEvPDOT_EFivE", "void f<true>(int (*)() noexcept(true))"}, + {"_Z1gIJEEvPDwDpT_EFivE", "void g<>(int (*)() throw())"}, + {"_Z1gIJfEEvPDwDpT_EFivE", "void g<float>(int (*)() throw(float))"}, + {"_Z1hIJEEPDwDpT_iEFivEPDwiS1_EFivE", "int (*h<>(int (*)() throw(int)))() throw(int)"}, + {"_Z1hIJfEEPDwDpT_iEFivEPDwiS1_EFivE", "int (*h<float>(int (*)() throw(int, float)))() throw(float, int)"}, + {"_Z1iIJEEPDwiDpT_EFivEPS2_", "int (*i<>(int (*)() throw(int)))() throw(int)"}, + {"_Z1iIJEEPDwiDpT_EFivES3_", "int (*i<>(int (*)() throw(int)))() throw(int)"}, + {"_Z1iIJfEEPDwiDpT_EFivEPS2_", "int (*i<float>(int (*)() throw(int, float)))() throw(int, float)"}, + {"_Z1iIJfEEPDwiDpT_EFivES3_", "int (*i<float>(int (*)() throw(int, float)))() throw(int, float)"}, + {"_Z1pILb1EEiM1SKDOT_EFivRE", "int p<true>(int (S::*)() const & noexcept(true))"}, + {"_Z1pIJicfEEiM1SVKDwDpT_EFivOE", "int p<int, char, float>(int (S::*)() const volatile && throw(int, char, float))"}, + {"_Z1pM1SDoFivE", "p(int (S::*)() noexcept)"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); |