Index: libcxxabi/src/demangle/ItaniumDemangle.h =================================================================== --- libcxxabi/src/demangle/ItaniumDemangle.h +++ libcxxabi/src/demangle/ItaniumDemangle.h @@ -16,10 +16,6 @@ #ifndef DEMANGLE_ITANIUMDEMANGLE_H #define DEMANGLE_ITANIUMDEMANGLE_H -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - #include "DemangleConfig.h" #include "StringView.h" #include "Utility.h" @@ -58,6 +54,8 @@ X(QualifiedName) \ X(NestedName) \ X(LocalName) \ + X(ModuleName) \ + X(ModuleEntity) \ X(VectorType) \ X(PixelVectorType) \ X(BinaryFPType) \ @@ -1049,6 +1047,44 @@ } }; +struct ModuleName : Node { + ModuleName *Parent; + Node *Name; + bool IsPartition; + + ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false) + : Node(KModuleName), Parent(Parent_), Name(Name_), + IsPartition(IsPartition_) {} + + template void match(Fn F) const { F(Parent, Name); } + + void printLeft(OutputBuffer &OB) const override { + if (Parent) + Parent->print(OB); + if (Parent || IsPartition) + OB += IsPartition ? ':' : '.'; + Name->print(OB); + } +}; + +struct ModuleEntity : Node { + ModuleName *Module; + Node *Name; + + ModuleEntity(ModuleName *Module_, Node *Name_) + : Node(KModuleEntity), Module(Module_), Name(Name_) {} + + template void match(Fn F) const { F(Module, Name); } + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + OB += '@'; + Module->print(OB); + } +}; + struct LocalName : Node { Node *Encoding; Node *Entity; @@ -2591,10 +2627,11 @@ Node *parseName(NameState *State = nullptr); Node *parseLocalName(NameState *State); Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(NameState *State, Node *Scope); + bool parseModuleNameOpt(ModuleName *&Module); + Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module); Node *parseUnnamedTypeName(NameState *State); Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State); + Node *parseUnscopedName(NameState *State, bool *isSubstName); Node *parseNestedName(NameState *State); Node *parseCtorDtorName(Node *&SoFar, NameState *State); @@ -2687,18 +2724,10 @@ return getDerived().parseLocalName(State); Node *Result = nullptr; - bool IsSubst = look() == 'S' && look(1) != 't'; - if (IsSubst) { - // A substitution must lead to: - // ::= - Result = getDerived().parseSubstitution(); - } else { - // An unscoped name can be one of: - // ::= - // ::= - Result = getDerived().parseUnscopedName(State); - } - if (Result == nullptr) + bool IsSubst = false; + + Result = getDerived().parseUnscopedName(State, &IsSubst); + if (!Result) return nullptr; if (look() == 'I') { @@ -2761,7 +2790,9 @@ // [*] extension template Node * -AbstractManglingParser::parseUnscopedName(NameState *State) { +AbstractManglingParser::parseUnscopedName(NameState *State, + bool *IsSubst) { + Node *Std = nullptr; if (consumeIf("St")) { Std = make("std"); @@ -2770,24 +2801,45 @@ } consumeIf('L'); - return getDerived().parseUnqualifiedName(State, Std); + Node *Res = nullptr; + ModuleName *Module = nullptr; + if (look() == 'S') { + Node *S = getDerived().parseSubstitution(); + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) + Module = static_cast(S); + else if (IsSubst && Std == nullptr) { + Res = S; + *IsSubst = true; + } else { + return nullptr; + } + } + + if (Res == nullptr) + Res = getDerived().parseUnqualifiedName(State, Std, Module); + + return Res; } -// ::= [abi-tags] -// ::= [] -// ::= [] -// ::= [] -// ::= DC + E # structured binding declaration +// ::= [] [] +// ::= [] [] +// ::= [] [] +// ::= [] [] +// ::= [] DC + E # structured binding declaration template -Node * -AbstractManglingParser::parseUnqualifiedName(NameState *State, - Node *Scope) { +Node *AbstractManglingParser::parseUnqualifiedName( + NameState *State, Node *Scope, ModuleName *Module) { + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + Node *Result; - if (look() == 'U') + if (look() == 'U') { Result = getDerived().parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') + } else if (look() >= '1' && look() <= '9') { Result = getDerived().parseSourceName(State); - else if (consumeIf("DC")) { + } else if (consumeIf("DC")) { // Structured binding size_t BindingsBegin = Names.size(); do { @@ -2799,19 +2851,44 @@ Result = make(popTrailingNodeArray(BindingsBegin)); } else if (look() == 'C' || look() == 'D') { // A . - if (Scope == nullptr) + if (Scope == nullptr || Module != nullptr) return nullptr; Result = getDerived().parseCtorDtorName(Scope, State); } else { Result = getDerived().parseOperatorName(State); } + + if (Module) + Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); if (Result != nullptr && Scope != nullptr) Result = make(Scope, Result); + return Result; } +// ::= +// ::= +// ::= # passed in by caller +// ::= S +// ::= S P +template +bool AbstractManglingParser::parseModuleNameOpt( + ModuleName *&Module) { + while (consumeIf('W')) { + bool IsPartition = consumeIf('P'); + Node *Sub = getDerived().parseSourceName(nullptr); + if (!Sub) + return true; + Module = + static_cast(make(Module, Sub, IsPartition)); + Subs.push_back(Module); + } + + return false; +} + // ::= Ut [] _ // ::= // @@ -3204,25 +3281,35 @@ if (SoFar != nullptr) return nullptr; // Cannot have a prefix. SoFar = getDerived().parseDecltype(); - } else if (look() == 'S') { - // ::= - if (SoFar != nullptr) - return nullptr; // Cannot have a prefix. - if (look(1) == 't') { - // parseSubstition does not handle 'St'. - First += 2; - SoFar = make("std"); - } else { - SoFar = getDerived().parseSubstitution(); - } - if (SoFar == nullptr) - return nullptr; - continue; // Do not push a new substitution. } else { - consumeIf('L'); // extension + ModuleName *Module = nullptr; + bool IsLocal = consumeIf('L'); // extension + + if (look() == 'S') { + // ::= + Node *S = nullptr; + if (look(1) == 't') { + First += 2; + S = make("std"); + } else { + S = getDerived().parseSubstitution(); + } + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) { + Module = static_cast(S); + } else if (SoFar != nullptr || IsLocal) { + return nullptr; // Cannot have a prefix. + } else { + SoFar = S; + continue; // Do not push a new substitution. + } + } + // ::= [] - SoFar = getDerived().parseUnqualifiedName(State, SoFar); + SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module); } + if (SoFar == nullptr) return nullptr; Subs.push_back(SoFar); @@ -4035,8 +4122,9 @@ // ::= # See Compression below case 'S': { if (look(1) != 't') { - Result = getDerived().parseSubstitution(); - if (Result == nullptr) + bool IsSubst = false; + Result = getDerived().parseUnscopedName(nullptr, &IsSubst); + if (!Result) return nullptr; // Sub could be either of: @@ -4049,12 +4137,14 @@ // If this is followed by some , and we're permitted to // parse them, take the second production. - if (TryToParseTemplateArgs && look() == 'I') { + if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) { + if (!IsSubst) + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; Result = make(Result, TA); - } else { + } else if (IsSubst) { // If all we parsed was a substitution, don't re-insert into the // substitution table. return Result; @@ -4813,6 +4903,7 @@ // ::= GR _ # Subsequent temporaries // extension ::= TC _ # construction vtable for second-in-first // extension ::= GR # reference temporary for object +// extension ::= GI # module global initializer template Node *AbstractManglingParser::parseSpecialName() { switch (look()) { @@ -4939,6 +5030,16 @@ return nullptr; return make("reference temporary for ", Name); } + // GI v + case 'I': { + First += 2; + ModuleName *Module = nullptr; + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + if (Module == nullptr) + return nullptr; + return make("initializer for module ", Module); + } } } return nullptr; Index: libcxxabi/test/test_demangle.pass.cpp =================================================================== --- libcxxabi/test/test_demangle.pass.cpp +++ libcxxabi/test/test_demangle.pass.cpp @@ -29869,6 +29869,47 @@ {"_ZN2FnIXdlLj4EEXgsdaLj4EEEEvv", "void Fn()"}, {"_Z3TPLIiET_S0_", "int TPL(int)"}, + + // C++20 modules + {"_ZN5Outer5InnerW3FOO2FnERNS0_1XE", + "Outer::Inner::Fn@FOO(Outer::Inner::X&)"}, + {"_ZN5OuterW3FOO5Inner2FnERNS1_1XE", + "Outer::Inner@FOO::Fn(Outer::Inner@FOO::X&)"}, + {"_ZN4Quux4TotoW3FooW3Bar3BazEPNS0_S2_5PlughE", + "Quux::Toto::Baz@Foo.Bar(Quux::Toto::Plugh@Foo.Bar*)"}, + {"_ZW6Module1fNS_1a1bENS0_1cE", + "f@Module(a@Module::b, a@Module::c)"}, + {"_ZN3BobW3FOOW3BAR3BarEPS1_1APNS_S1_1BE", + "Bob::Bar@FOO.BAR(A@FOO.BAR*, Bob::B@FOO.BAR*)"}, + {"_ZW3FOOW3BAR3FooPS0_1APN3BobS0_1BE", + "Foo@FOO.BAR(A@FOO.BAR*, Bob::B@FOO.BAR*)"}, + {"_ZN3BobW3FOOW3BAZ3FooEPS0_W3BAR1APNS_S2_1BE", + "Bob::Foo@FOO.BAZ(A@FOO.BAR*, Bob::B@FOO.BAR*)"}, + {"_ZW3FOOW3BAZ3BarPS_W3BAR1APN3BobS1_1BE", + "Bar@FOO.BAZ(A@FOO.BAR*, Bob::B@FOO.BAR*)"}, + {"_ZNW3FOO3TPLIS_3OneE1MEPS1_", + "TPL@FOO::M(One@FOO*)"}, + {"_ZNW3FOO3TPLIS_3OneE1NIS_3TwoEEvPS1_PT_", + "void TPL@FOO::N(One@FOO*, Two@FOO*)"}, + {"_ZN3NMSW3FOO3TPLINS_S0_3OneEE1MEPS2_", + "NMS::TPL@FOO::M(NMS::One@FOO*)"}, + {"_ZN3NMSW3FOO3TPLINS_S0_3OneEE1NINS_S0_3TwoEEEvPS2_PT_", + "void NMS::TPL@FOO::N(NMS::One@FOO*, NMS::Two@FOO*)"}, + {"_ZNStW3STD9allocatorIiE1MEPi", + "std::allocator@STD::M(int*)"}, + {"_ZNStW3STD9allocatorIiE1NIfEEPT_Pi", + "float* std::allocator@STD::N(int*)"}, + {"_ZNStW3STD9allocatorI4PoohE1MEPS1_", + "std::allocator@STD::M(Pooh*)"}, + {"_ZNStW3STD9allocatorI4PoohE1NI6PigletEEPT_PS1_", + "Piglet* std::allocator@STD::N(Pooh*)"}, + {"_ZW3FooDC1a1bE", "[a, b]@Foo"}, + {"_ZN1NW3FooDC1a1bEE", "N::[a, b]@Foo"}, + {"_ZN3NMSW3MOD3FooB3ABIEv", + "NMS::Foo@MOD[abi:ABI]()"}, + {"_ZGIW3Foo", "initializer for module Foo"}, + {"_ZGIW3FooW3Bar", "initializer for module Foo.Bar"}, + {"_ZGIW3FooWP3BarW3Baz", "initializer for module Foo:Bar.Baz"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); @@ -29954,6 +29995,10 @@ "_ZN1fIiEEvNTUt_E", "_ZNDTUt_Ev", + "_ZNWUt_3FOOEv", + "_ZWDC3FOOEv", + "_ZGI3Foo", + "_ZGIW3Foov", }; const unsigned NI = sizeof(invalid_cases) / sizeof(invalid_cases[0]); Index: llvm/include/llvm/Demangle/ItaniumDemangle.h =================================================================== --- llvm/include/llvm/Demangle/ItaniumDemangle.h +++ llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -16,10 +16,6 @@ #ifndef DEMANGLE_ITANIUMDEMANGLE_H #define DEMANGLE_ITANIUMDEMANGLE_H -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - #include "DemangleConfig.h" #include "StringView.h" #include "Utility.h" @@ -58,6 +54,8 @@ X(QualifiedName) \ X(NestedName) \ X(LocalName) \ + X(ModuleName) \ + X(ModuleEntity) \ X(VectorType) \ X(PixelVectorType) \ X(BinaryFPType) \ @@ -1049,6 +1047,44 @@ } }; +struct ModuleName : Node { + ModuleName *Parent; + Node *Name; + bool IsPartition; + + ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false) + : Node(KModuleName), Parent(Parent_), Name(Name_), + IsPartition(IsPartition_) {} + + template void match(Fn F) const { F(Parent, Name); } + + void printLeft(OutputBuffer &OB) const override { + if (Parent) + Parent->print(OB); + if (Parent || IsPartition) + OB += IsPartition ? ':' : '.'; + Name->print(OB); + } +}; + +struct ModuleEntity : Node { + ModuleName *Module; + Node *Name; + + ModuleEntity(ModuleName *Module_, Node *Name_) + : Node(KModuleEntity), Module(Module_), Name(Name_) {} + + template void match(Fn F) const { F(Module, Name); } + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + OB += '@'; + Module->print(OB); + } +}; + struct LocalName : Node { Node *Encoding; Node *Entity; @@ -2591,10 +2627,11 @@ Node *parseName(NameState *State = nullptr); Node *parseLocalName(NameState *State); Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(NameState *State, Node *Scope); + bool parseModuleNameOpt(ModuleName *&Module); + Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module); Node *parseUnnamedTypeName(NameState *State); Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State); + Node *parseUnscopedName(NameState *State, bool *isSubstName); Node *parseNestedName(NameState *State); Node *parseCtorDtorName(Node *&SoFar, NameState *State); @@ -2687,18 +2724,10 @@ return getDerived().parseLocalName(State); Node *Result = nullptr; - bool IsSubst = look() == 'S' && look(1) != 't'; - if (IsSubst) { - // A substitution must lead to: - // ::= - Result = getDerived().parseSubstitution(); - } else { - // An unscoped name can be one of: - // ::= - // ::= - Result = getDerived().parseUnscopedName(State); - } - if (Result == nullptr) + bool IsSubst = false; + + Result = getDerived().parseUnscopedName(State, &IsSubst); + if (!Result) return nullptr; if (look() == 'I') { @@ -2761,7 +2790,9 @@ // [*] extension template Node * -AbstractManglingParser::parseUnscopedName(NameState *State) { +AbstractManglingParser::parseUnscopedName(NameState *State, + bool *IsSubst) { + Node *Std = nullptr; if (consumeIf("St")) { Std = make("std"); @@ -2770,24 +2801,45 @@ } consumeIf('L'); - return getDerived().parseUnqualifiedName(State, Std); + Node *Res = nullptr; + ModuleName *Module = nullptr; + if (look() == 'S') { + Node *S = getDerived().parseSubstitution(); + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) + Module = static_cast(S); + else if (IsSubst && Std == nullptr) { + Res = S; + *IsSubst = true; + } else { + return nullptr; + } + } + + if (Res == nullptr) + Res = getDerived().parseUnqualifiedName(State, Std, Module); + + return Res; } -// ::= [abi-tags] -// ::= [] -// ::= [] -// ::= [] -// ::= DC + E # structured binding declaration +// ::= [] [] +// ::= [] [] +// ::= [] [] +// ::= [] [] +// ::= [] DC + E # structured binding declaration template -Node * -AbstractManglingParser::parseUnqualifiedName(NameState *State, - Node *Scope) { +Node *AbstractManglingParser::parseUnqualifiedName( + NameState *State, Node *Scope, ModuleName *Module) { + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + Node *Result; - if (look() == 'U') + if (look() == 'U') { Result = getDerived().parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') + } else if (look() >= '1' && look() <= '9') { Result = getDerived().parseSourceName(State); - else if (consumeIf("DC")) { + } else if (consumeIf("DC")) { // Structured binding size_t BindingsBegin = Names.size(); do { @@ -2799,19 +2851,44 @@ Result = make(popTrailingNodeArray(BindingsBegin)); } else if (look() == 'C' || look() == 'D') { // A . - if (Scope == nullptr) + if (Scope == nullptr || Module != nullptr) return nullptr; Result = getDerived().parseCtorDtorName(Scope, State); } else { Result = getDerived().parseOperatorName(State); } + + if (Module) + Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); if (Result != nullptr && Scope != nullptr) Result = make(Scope, Result); + return Result; } +// ::= +// ::= +// ::= # passed in by caller +// ::= S +// ::= S P +template +bool AbstractManglingParser::parseModuleNameOpt( + ModuleName *&Module) { + while (consumeIf('W')) { + bool IsPartition = consumeIf('P'); + Node *Sub = getDerived().parseSourceName(nullptr); + if (!Sub) + return true; + Module = + static_cast(make(Module, Sub, IsPartition)); + Subs.push_back(Module); + } + + return false; +} + // ::= Ut [] _ // ::= // @@ -3204,25 +3281,35 @@ if (SoFar != nullptr) return nullptr; // Cannot have a prefix. SoFar = getDerived().parseDecltype(); - } else if (look() == 'S') { - // ::= - if (SoFar != nullptr) - return nullptr; // Cannot have a prefix. - if (look(1) == 't') { - // parseSubstition does not handle 'St'. - First += 2; - SoFar = make("std"); - } else { - SoFar = getDerived().parseSubstitution(); - } - if (SoFar == nullptr) - return nullptr; - continue; // Do not push a new substitution. } else { - consumeIf('L'); // extension + ModuleName *Module = nullptr; + bool IsLocal = consumeIf('L'); // extension + + if (look() == 'S') { + // ::= + Node *S = nullptr; + if (look(1) == 't') { + First += 2; + S = make("std"); + } else { + S = getDerived().parseSubstitution(); + } + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) { + Module = static_cast(S); + } else if (SoFar != nullptr || IsLocal) { + return nullptr; // Cannot have a prefix. + } else { + SoFar = S; + continue; // Do not push a new substitution. + } + } + // ::= [] - SoFar = getDerived().parseUnqualifiedName(State, SoFar); + SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module); } + if (SoFar == nullptr) return nullptr; Subs.push_back(SoFar); @@ -4035,8 +4122,9 @@ // ::= # See Compression below case 'S': { if (look(1) != 't') { - Result = getDerived().parseSubstitution(); - if (Result == nullptr) + bool IsSubst = false; + Result = getDerived().parseUnscopedName(nullptr, &IsSubst); + if (!Result) return nullptr; // Sub could be either of: @@ -4049,12 +4137,14 @@ // If this is followed by some , and we're permitted to // parse them, take the second production. - if (TryToParseTemplateArgs && look() == 'I') { + if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) { + if (!IsSubst) + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; Result = make(Result, TA); - } else { + } else if (IsSubst) { // If all we parsed was a substitution, don't re-insert into the // substitution table. return Result; @@ -4813,6 +4903,7 @@ // ::= GR _ # Subsequent temporaries // extension ::= TC _ # construction vtable for second-in-first // extension ::= GR # reference temporary for object +// extension ::= GI # module global initializer template Node *AbstractManglingParser::parseSpecialName() { switch (look()) { @@ -4939,6 +5030,16 @@ return nullptr; return make("reference temporary for ", Name); } + // GI v + case 'I': { + First += 2; + ModuleName *Module = nullptr; + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + if (Module == nullptr) + return nullptr; + return make("initializer for module ", Module); + } } } return nullptr; Index: llvm/lib/Demangle/ItaniumDemangle.cpp =================================================================== --- llvm/lib/Demangle/ItaniumDemangle.cpp +++ llvm/lib/Demangle/ItaniumDemangle.cpp @@ -404,6 +404,9 @@ case Node::KAbiTagAttr: Name = static_cast(Name)->Base; continue; + case Node::KModuleEntity: + Name = static_cast(Name)->Name; + continue; case Node::KNestedName: Name = static_cast(Name)->Name; continue; @@ -442,6 +445,9 @@ break; } + if (Name->getKind() == Node::KModuleEntity) + Name = static_cast(Name)->Name; + switch (Name->getKind()) { case Node::KNestedName: static_cast(Name)->Qual->print(OB); @@ -544,6 +550,9 @@ case Node::KNestedName: N = static_cast(N)->Name; break; + case Node::KModuleEntity: + N = static_cast(N)->Name; + break; } } return false;