diff --git a/llvm/unittests/Support/ItaniumManglingCanonicalizerTest.cpp b/llvm/unittests/Support/ItaniumManglingCanonicalizerTest.cpp index 8807aa1abee7..b8a42f64f898 100644 --- a/llvm/unittests/Support/ItaniumManglingCanonicalizerTest.cpp +++ b/llvm/unittests/Support/ItaniumManglingCanonicalizerTest.cpp @@ -8,11 +8,17 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ItaniumManglingCanonicalizer.h" - +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include "gtest/gtest.h" #include #include +#include + +using namespace llvm; + +namespace { using EquivalenceError = llvm::ItaniumManglingCanonicalizer::EquivalenceError; using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind; @@ -24,234 +30,240 @@ struct Equivalence { }; // A set of manglings that should all be considered equivalent. -using EquivalenceClass = std::initializer_list; +using EquivalenceClass = std::vector; struct Testcase { // A set of equivalences to register. - std::initializer_list Equivalences; + std::vector Equivalences; // A set of distinct equivalence classes created by registering the // equivalences. - std::initializer_list Classes; + std::vector Classes; }; -static std::initializer_list Testcases = { - // Three different manglings for std::string (old libstdc++, new libstdc++, - // libc++). - { +// A function that returns a set of test cases. +static std::vector getTestcases() { + return { + // Three different manglings for std::string (old libstdc++, new libstdc++, + // libc++). { - {FragmentKind::Type, "Ss", - "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE"}, - {FragmentKind::Type, "Ss", - "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, + { + {FragmentKind::Type, "Ss", + "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE"}, + {FragmentKind::Type, "Ss", + "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, + }, + { + {"_Z1fv"}, + {"_Z1fSs", + "_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", + "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, + {"_ZNKSs4sizeEv", + "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4sizeEv", + "_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv"}, + } }, - { - {"_Z1fv"}, - {"_Z1fSs", - "_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", - "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, - {"_ZNKSs4sizeEv", - "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4sizeEv", - "_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv"}, - } - }, - // Check that substitutions are properly handled. - { + // Check that substitutions are properly handled. { - // ::X <-> ::N::X - {FragmentKind::Type, "1X", "N1N1XIiEE"}, - // ::T, T> <-> T - {FragmentKind::Type, "1TIS_IiiES0_E", "1TIiE"}, - // A::B::foo <-> AB::foo - {FragmentKind::Name, "N1A1B3fooE", "N2AB3fooE"}, + { + // ::X <-> ::N::X + {FragmentKind::Type, "1X", "N1N1XIiEE"}, + // ::T, T> <-> T + {FragmentKind::Type, "1TIS_IiiES0_E", "1TIiE"}, + // A::B::foo <-> AB::foo + {FragmentKind::Name, "N1A1B3fooE", "N2AB3fooE"}, + }, + { + {"_Z1f1XPS_RS_", "_Z1fN1N1XIiEEPS1_RS1_"}, + {"_ZN1A1B3fooE1TIS1_IiiES2_EPS3_RS3_", "_ZN2AB3fooE1TIiEPS1_RS1_"}, + } }, - { - {"_Z1f1XPS_RS_", "_Z1fN1N1XIiEEPS1_RS1_"}, - {"_ZN1A1B3fooE1TIS1_IiiES2_EPS3_RS3_", "_ZN2AB3fooE1TIiEPS1_RS1_"}, - } - }, - // Check that nested equivalences are properly handled. - { + // Check that nested equivalences are properly handled. { - // std::__1::char_traits == std::__cxx11::char_traits - // (Note that this is unused and should make no difference, - // but it should not cause us to fail to match up the cases - // below.) - {FragmentKind::Name, - "NSt3__111char_traitsE", - "NSt7__cxx1111char_traitsE"}, - // std::__1::allocator == std::allocator - {FragmentKind::Name, - "NSt3__19allocatorE", - "Sa"}, // "Sa" is not strictly a but we accept it as one. - // std::__1::vector == std::vector - {FragmentKind::Name, - "St6vector", - "NSt3__16vectorE"}, - // std::__1::basic_string< - // char - // std::__1::char_traits, - // std::__1::allocator> == - // std::__cxx11::basic_string< - // char, - // std::char_traits, - // std::allocator> - {FragmentKind::Type, - "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", - "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, - // X <-> X - {FragmentKind::Type, "1XI1AE", "1XI1BE"}, - // X <-> Y - {FragmentKind::Name, "1X", "1Y"}, + { + // std::__1::char_traits == std::__cxx11::char_traits + // (Note that this is unused and should make no difference, + // but it should not cause us to fail to match up the cases + // below.) + {FragmentKind::Name, + "NSt3__111char_traitsE", + "NSt7__cxx1111char_traitsE"}, + // std::__1::allocator == std::allocator + {FragmentKind::Name, + "NSt3__19allocatorE", + "Sa"}, // "Sa" is not strictly a but we accept it as one. + // std::__1::vector == std::vector + {FragmentKind::Name, + "St6vector", + "NSt3__16vectorE"}, + // std::__1::basic_string< + // char + // std::__1::char_traits, + // std::__1::allocator> == + // std::__cxx11::basic_string< + // char, + // std::char_traits, + // std::allocator> + {FragmentKind::Type, + "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", + "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, + // X <-> X + {FragmentKind::Type, "1XI1AE", "1XI1BE"}, + // X <-> Y + {FragmentKind::Name, "1X", "1Y"}, + }, + { + // f(std::string) + {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", + "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, + // f(std::vector) + {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, + // f(X), f(X), f(Y), f(Y) + {"_Z1f1XI1AE", "_Z1f1XI1BE", "_Z1f1YI1AE", "_Z1f1YI1BE"}, + // f(X), f(Y) + {"_Z1f1XI1CE", "_Z1f1YI1CE"}, + } }, - { - // f(std::string) - {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", - "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, - // f(std::vector) - {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, - // f(X), f(X), f(Y), f(Y) - {"_Z1f1XI1AE", "_Z1f1XI1BE", "_Z1f1YI1AE", "_Z1f1YI1BE"}, - // f(X), f(Y) - {"_Z1f1XI1CE", "_Z1f1YI1CE"}, - } - }, - // Check namespace equivalences. - { + // Check namespace equivalences. { - // std::__1 == std::__cxx11 - {FragmentKind::Name, "St3__1", "St7__cxx11"}, - // std::__1::allocator == std::allocator - {FragmentKind::Name, "NSt3__19allocatorE", "Sa"}, - // std::vector == std::__1::vector - {FragmentKind::Name, "St6vector", "NSt3__16vectorE"}, - // std::__cxx11::char_traits == std::char_traits - // (This indirectly means that std::__1::char_traits == std::char_traits, - // due to the std::__cxx11 == std::__1 equivalence, which is what we rely - // on below.) - {FragmentKind::Name, "NSt7__cxx1111char_traitsE", "St11char_traits"}, + { + // std::__1 == std::__cxx11 + {FragmentKind::Name, "St3__1", "St7__cxx11"}, + // std::__1::allocator == std::allocator + {FragmentKind::Name, "NSt3__19allocatorE", "Sa"}, + // std::vector == std::__1::vector + {FragmentKind::Name, "St6vector", "NSt3__16vectorE"}, + // std::__cxx11::char_traits == std::char_traits + // (This indirectly means that std::__1::char_traits == std::char_traits, + // due to the std::__cxx11 == std::__1 equivalence, which is what we rely + // on below.) + {FragmentKind::Name, "NSt7__cxx1111char_traitsE", "St11char_traits"}, + }, + { + // f(std::foo) + {"_Z1fNSt7__cxx113fooE", + "_Z1fNSt3__13fooE"}, + // f(std::string) + {"_Z1fNSt7__cxx1111char_traitsIcEE", + "_Z1fNSt3__111char_traitsIcEE", + "_Z1fSt11char_traitsIcE"}, + // f(std::string) + {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", + "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, + // f(std::vector) + {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, + } }, - { - // f(std::foo) - {"_Z1fNSt7__cxx113fooE", - "_Z1fNSt3__13fooE"}, - // f(std::string) - {"_Z1fNSt7__cxx1111char_traitsIcEE", - "_Z1fNSt3__111char_traitsIcEE", - "_Z1fSt11char_traitsIcE"}, - // f(std::string) - {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", - "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, - // f(std::vector) - {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, - } - }, - // Check namespace equivalences for namespace 'std'. We support using 'St' - // for this, despite it not technically being a . - { + // Check namespace equivalences for namespace 'std'. We support using 'St' + // for this, despite it not technically being a . { - // std::__1 == std - {FragmentKind::Name, "St3__1", "St"}, - // std::__1 == std::__cxx11 - {FragmentKind::Name, "St3__1", "St7__cxx11"}, - // FIXME: Should a 'std' equivalence also cover the predefined - // substitutions? - // std::__1::allocator == std::allocator - {FragmentKind::Name, "NSt3__19allocatorE", "Sa"}, + { + // std::__1 == std + {FragmentKind::Name, "St3__1", "St"}, + // std::__1 == std::__cxx11 + {FragmentKind::Name, "St3__1", "St7__cxx11"}, + // FIXME: Should a 'std' equivalence also cover the predefined + // substitutions? + // std::__1::allocator == std::allocator + {FragmentKind::Name, "NSt3__19allocatorE", "Sa"}, + }, + { + {"_Z1fSt3foo", "_Z1fNSt3__13fooE", "_Z1fNSt7__cxx113fooE"}, + {"_Z1fNSt3bar3bazE", "_Z1fNSt3__13bar3bazE"}, + // f(std::string) + {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", + "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, + // f(std::vector) + {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, + } }, - { - {"_Z1fSt3foo", "_Z1fNSt3__13fooE", "_Z1fNSt7__cxx113fooE"}, - {"_Z1fNSt3bar3bazE", "_Z1fNSt3__13bar3bazE"}, - // f(std::string) - {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", - "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, - // f(std::vector) - {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, - } - }, - // Check mutually-recursive equivalences. - { + // Check mutually-recursive equivalences. { - {FragmentKind::Type, "1A", "1B"}, - {FragmentKind::Type, "1A", "1C"}, - {FragmentKind::Type, "1D", "1B"}, - {FragmentKind::Type, "1C", "1E"}, + { + {FragmentKind::Type, "1A", "1B"}, + {FragmentKind::Type, "1A", "1C"}, + {FragmentKind::Type, "1D", "1B"}, + {FragmentKind::Type, "1C", "1E"}, + }, + { + {"_Z1f1A", "_Z1f1B", "_Z1f1C", "_Z1f1D", "_Z1f1E"}, + {"_Z1f1F"}, + } }, - { - {"_Z1f1A", "_Z1f1B", "_Z1f1C", "_Z1f1D", "_Z1f1E"}, - {"_Z1f1F"}, - } - }, - // Check s. - { + // Check s. { - {FragmentKind::Encoding, "1fv", "1gv"}, + { + {FragmentKind::Encoding, "1fv", "1gv"}, + }, + { + // f(void) -> g(void) + {"_Z1fv", "_Z1gv"}, + // static local 'n' in f(void) -> static local 'n' in g(void) + {"_ZZ1fvE1n", "_ZZ1gvE1n"}, + } }, - { - // f(void) -> g(void) - {"_Z1fv", "_Z1gv"}, - // static local 'n' in f(void) -> static local 'n' in g(void) - {"_ZZ1fvE1n", "_ZZ1gvE1n"}, - } - }, - // Corner case: the substitution can appear within its own expansion. - { + // Corner case: the substitution can appear within its own expansion. { - // X <-> Y - {FragmentKind::Type, "1X", "1YI1XE"}, - // A <-> B - {FragmentKind::Type, "1AI1BE", "1B"}, + { + // X <-> Y + {FragmentKind::Type, "1X", "1YI1XE"}, + // A <-> B + {FragmentKind::Type, "1AI1BE", "1B"}, + }, + { + // f(X) == f(Y) == f(Y>) == f(Y>>) + {"_Z1f1X", "_Z1f1YI1XE", "_Z1f1YIS_I1XEE", "_Z1f1YIS_IS_I1XEEE"}, + // f(B) == f(A) == f(A>) == f(A>>) + {"_Z1f1B", "_Z1f1AI1BE", "_Z1f1AIS_I1BEE", "_Z1f1AIS_IS_I1BEEE"}, + } }, - { - // f(X) == f(Y) == f(Y>) == f(Y>>) - {"_Z1f1X", "_Z1f1YI1XE", "_Z1f1YIS_I1XEE", "_Z1f1YIS_IS_I1XEEE"}, - // f(B) == f(A) == f(A>) == f(A>>) - {"_Z1f1B", "_Z1f1AI1BE", "_Z1f1AIS_I1BEE", "_Z1f1AIS_IS_I1BEEE"}, - } - }, - // Redundant equivalences are accepted (and have no effect). - { + // Redundant equivalences are accepted (and have no effect). { - {FragmentKind::Name, "3std", "St"}, - {FragmentKind::Name, "1X", "1Y"}, - {FragmentKind::Name, "N1X1ZE", "N1Y1ZE"}, + { + {FragmentKind::Name, "3std", "St"}, + {FragmentKind::Name, "1X", "1Y"}, + {FragmentKind::Name, "N1X1ZE", "N1Y1ZE"}, + }, + {} }, - {} - }, -}; + }; +} -static std::initializer_list ForwardTemplateReferenceTestcases = { - // ForwardTemplateReference does not support canonicalization. - // FIXME: We should consider ways of fixing this, perhaps by eliminating - // the ForwardTemplateReference node with a tree transformation. - { +// A function to get a set of test cases for forward template references. +static std::vector getForwardTemplateReferenceTestcases() { + return { + // ForwardTemplateReference does not support canonicalization. + // FIXME: We should consider ways of fixing this, perhaps by eliminating + // the ForwardTemplateReference node with a tree transformation. { - // X::operator T() == Y::operator T() - {FragmentKind::Encoding, "N1XcvT_I1AEEv", "N1YcvT_I1AEEv"}, - // A == B - {FragmentKind::Name, "1A", "1B"}, + { + // X::operator T() == Y::operator T() + {FragmentKind::Encoding, "N1XcvT_I1AEEv", "N1YcvT_I1AEEv"}, + // A == B + {FragmentKind::Name, "1A", "1B"}, + }, + { + // All combinations result in unique equivalence classes. + {"_ZN1XcvT_I1AEEv"}, + {"_ZN1XcvT_I1BEEv"}, + {"_ZN1YcvT_I1AEEv"}, + {"_ZN1YcvT_I1BEEv"}, + // Even giving the same string twice gives a new class. + {"_ZN1XcvT_I1AEEv"}, + } }, - { - // All combinations result in unique equivalence classes. - {"_ZN1XcvT_I1AEEv"}, - {"_ZN1XcvT_I1BEEv"}, - {"_ZN1YcvT_I1AEEv"}, - {"_ZN1YcvT_I1BEEv"}, - // Even giving the same string twice gives a new class. - {"_ZN1XcvT_I1AEEv"}, - } - }, -}; + }; +} template -static void testTestcases(std::initializer_list Testcases) { +static void testTestcases(ArrayRef Testcases) { for (const auto &Testcase : Testcases) { llvm::ItaniumManglingCanonicalizer Canonicalizer; for (const auto &Equiv : Testcase.Equivalences) { @@ -293,17 +305,17 @@ static void testTestcases(std::initializer_list Testcases) { } TEST(ItaniumManglingCanonicalizerTest, TestCanonicalize) { - testTestcases(Testcases); + testTestcases(getTestcases()); } TEST(ItaniumManglingCanonicalizerTest, TestLookup) { - testTestcases(Testcases); + testTestcases(getTestcases()); } TEST(ItaniumManglingCanonicalizerTest, TestForwardTemplateReference) { // lookup(...) after canonicalization (intentionally) returns different // values for this testcase. - testTestcases(ForwardTemplateReferenceTestcases); + testTestcases(getForwardTemplateReferenceTestcases()); } @@ -344,3 +356,5 @@ TEST(ItaniumManglingCanonicalizerTest, TestBadEquivalenceOrder) { EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1B", "1D"), EquivalenceError::ManglingAlreadyUsed); } + +} // end anonymous namespace