1 //===-------------- ItaniumManglingCanonicalizerTest.cpp ------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include <cstdlib> 11 #include "llvm/Support/ItaniumManglingCanonicalizer.h" 12 #include "gtest/gtest.h" 13 14 using EquivalenceError = llvm::ItaniumManglingCanonicalizer::EquivalenceError; 15 using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind; 16 17 struct Equivalence { 18 FragmentKind Kind; 19 llvm::StringRef First; 20 llvm::StringRef Second; 21 }; 22 23 // A set of manglings that should all be considered equivalent. 24 using EquivalenceClass = std::initializer_list<llvm::StringRef>; 25 26 struct Testcase { 27 // A set of equivalences to register. 28 std::initializer_list<Equivalence> Equivalences; 29 // A set of distinct equivalence classes created by registering the 30 // equivalences. 31 std::initializer_list<EquivalenceClass> Classes; 32 }; 33 34 static std::initializer_list<Testcase> Testcases = { 35 // Three different manglings for std::string (old libstdc++, new libstdc++, 36 // libc++). 37 { 38 { 39 {FragmentKind::Type, "Ss", 40 "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE"}, 41 {FragmentKind::Type, "Ss", 42 "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, 43 }, 44 { 45 {"_Z1fv"}, 46 {"_Z1fSs", 47 "_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", 48 "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, 49 {"_ZNKSs4sizeEv", 50 "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4sizeEv", 51 "_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv"}, 52 } 53 }, 54 55 // Check that substitutions are properly handled. 56 { 57 { 58 // ::X <-> ::N::X<int> 59 {FragmentKind::Type, "1X", "N1N1XIiEE"}, 60 // ::T<T<int, int>, T<int, int>> <-> T<int> 61 {FragmentKind::Type, "1TIS_IiiES0_E", "1TIiE"}, 62 // A::B::foo <-> AB::foo 63 {FragmentKind::Name, "N1A1B3fooE", "N2AB3fooE"}, 64 }, 65 { 66 {"_Z1f1XPS_RS_", "_Z1fN1N1XIiEEPS1_RS1_"}, 67 {"_ZN1A1B3fooE1TIS1_IiiES2_EPS3_RS3_", "_ZN2AB3fooE1TIiEPS1_RS1_"}, 68 } 69 }, 70 71 // Check that nested equivalences are properly handled. 72 { 73 { 74 // std::__1::char_traits == std::__cxx11::char_traits 75 // (Note that this is unused and should make no difference, 76 // but it should not cause us to fail to match up the cases 77 // below.) 78 {FragmentKind::Name, 79 "NSt3__111char_traitsE", 80 "NSt7__cxx1111char_traitsE"}, 81 // std::__1::allocator == std::allocator 82 {FragmentKind::Name, 83 "NSt3__19allocatorE", 84 "Sa"}, // "Sa" is not strictly a <name> but we accept it as one. 85 // std::__1::vector == std::vector 86 {FragmentKind::Name, 87 "St6vector", 88 "NSt3__16vectorE"}, 89 // std::__1::basic_string< 90 // char 91 // std::__1::char_traits<char>, 92 // std::__1::allocator<char>> == 93 // std::__cxx11::basic_string< 94 // char, 95 // std::char_traits<char>, 96 // std::allocator<char>> 97 {FragmentKind::Type, 98 "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", 99 "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, 100 // X<A> <-> X<B> 101 {FragmentKind::Type, "1XI1AE", "1XI1BE"}, 102 // X <-> Y 103 {FragmentKind::Name, "1X", "1Y"}, 104 }, 105 { 106 // f(std::string) 107 {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", 108 "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, 109 // f(std::vector<int>) 110 {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, 111 // f(X<A>), f(X<B>), f(Y<A>), f(Y<B>) 112 {"_Z1f1XI1AE", "_Z1f1XI1BE", "_Z1f1YI1AE", "_Z1f1YI1BE"}, 113 // f(X<C>), f(Y<C>) 114 {"_Z1f1XI1CE", "_Z1f1YI1CE"}, 115 } 116 }, 117 118 // Check namespace equivalences. 119 { 120 { 121 // std::__1 == std::__cxx11 122 {FragmentKind::Name, "St3__1", "St7__cxx11"}, 123 // std::__1::allocator == std::allocator 124 {FragmentKind::Name, "NSt3__19allocatorE", "Sa"}, 125 // std::vector == std::__1::vector 126 {FragmentKind::Name, "St6vector", "NSt3__16vectorE"}, 127 // std::__cxx11::char_traits == std::char_traits 128 // (This indirectly means that std::__1::char_traits == std::char_traits, 129 // due to the std::__cxx11 == std::__1 equivalence, which is what we rely 130 // on below.) 131 {FragmentKind::Name, "NSt7__cxx1111char_traitsE", "St11char_traits"}, 132 }, 133 { 134 // f(std::foo) 135 {"_Z1fNSt7__cxx113fooE", 136 "_Z1fNSt3__13fooE"}, 137 // f(std::string) 138 {"_Z1fNSt7__cxx1111char_traitsIcEE", 139 "_Z1fNSt3__111char_traitsIcEE", 140 "_Z1fSt11char_traitsIcE"}, 141 // f(std::string) 142 {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", 143 "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, 144 // f(std::vector<int>) 145 {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, 146 } 147 }, 148 149 // Check namespace equivalences for namespace 'std'. We support using 'St' 150 // for this, despite it not technically being a <name>. 151 { 152 { 153 // std::__1 == std 154 {FragmentKind::Name, "St3__1", "St"}, 155 // std::__1 == std::__cxx11 156 {FragmentKind::Name, "St3__1", "St7__cxx11"}, 157 // FIXME: Should a 'std' equivalence also cover the predefined 158 // substitutions? 159 // std::__1::allocator == std::allocator 160 {FragmentKind::Name, "NSt3__19allocatorE", "Sa"}, 161 }, 162 { 163 {"_Z1fSt3foo", "_Z1fNSt3__13fooE", "_Z1fNSt7__cxx113fooE"}, 164 {"_Z1fNSt3bar3bazE", "_Z1fNSt3__13bar3bazE"}, 165 // f(std::string) 166 {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE", 167 "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"}, 168 // f(std::vector<int>) 169 {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"}, 170 } 171 }, 172 173 // Check mutually-recursive equivalences. 174 { 175 { 176 {FragmentKind::Type, "1A", "1B"}, 177 {FragmentKind::Type, "1A", "1C"}, 178 {FragmentKind::Type, "1D", "1B"}, 179 {FragmentKind::Type, "1C", "1E"}, 180 }, 181 { 182 {"_Z1f1A", "_Z1f1B", "_Z1f1C", "_Z1f1D", "_Z1f1E"}, 183 {"_Z1f1F"}, 184 } 185 }, 186 187 // Check <encoding>s. 188 { 189 { 190 {FragmentKind::Encoding, "1fv", "1gv"}, 191 }, 192 { 193 // f(void) -> g(void) 194 {"_Z1fv", "_Z1gv"}, 195 // static local 'n' in f(void) -> static local 'n' in g(void) 196 {"_ZZ1fvE1n", "_ZZ1gvE1n"}, 197 } 198 }, 199 200 // Corner case: the substitution can appear within its own expansion. 201 { 202 { 203 // X <-> Y<X> 204 {FragmentKind::Type, "1X", "1YI1XE"}, 205 // A<B> <-> B 206 {FragmentKind::Type, "1AI1BE", "1B"}, 207 }, 208 { 209 // f(X) == f(Y<X>) == f(Y<Y<X>>) == f(Y<Y<Y<X>>>) 210 {"_Z1f1X", "_Z1f1YI1XE", "_Z1f1YIS_I1XEE", "_Z1f1YIS_IS_I1XEEE"}, 211 // f(B) == f(A<B>) == f(A<A<B>>) == f(A<A<A<B>>>) 212 {"_Z1f1B", "_Z1f1AI1BE", "_Z1f1AIS_I1BEE", "_Z1f1AIS_IS_I1BEEE"}, 213 } 214 }, 215 216 // Redundant equivalences are accepted (and have no effect). 217 { 218 { 219 {FragmentKind::Name, "3std", "St"}, 220 {FragmentKind::Name, "1X", "1Y"}, 221 {FragmentKind::Name, "N1X1ZE", "N1Y1ZE"}, 222 }, 223 {} 224 }, 225 226 // ForwardTemplateReference does not support canonicalization. 227 // FIXME: We should consider ways of fixing this, perhaps by eliminating 228 // the ForwardTemplateReference node with a tree transformation. 229 { 230 { 231 // X::operator T() <with T = A> == Y::operator T() <with T = A> 232 {FragmentKind::Encoding, "N1XcvT_I1AEEv", "N1YcvT_I1AEEv"}, 233 // A == B 234 {FragmentKind::Name, "1A", "1B"}, 235 }, 236 { 237 // All combinations result in unique equivalence classes. 238 {"_ZN1XcvT_I1AEEv"}, 239 {"_ZN1XcvT_I1BEEv"}, 240 {"_ZN1YcvT_I1AEEv"}, 241 {"_ZN1YcvT_I1BEEv"}, 242 // Even giving the same string twice gives a new class. 243 {"_ZN1XcvT_I1AEEv"}, 244 } 245 }, 246 }; 247 248 TEST(ItaniumManglingCanonicalizerTest, TestTestcases) { 249 for (const auto &Testcase : Testcases) { 250 llvm::ItaniumManglingCanonicalizer Canonicalizer; 251 for (const auto &Equiv : Testcase.Equivalences) { 252 auto Result = 253 Canonicalizer.addEquivalence(Equiv.Kind, Equiv.First, Equiv.Second); 254 EXPECT_EQ(Result, EquivalenceError::Success) 255 << "couldn't add equivalence between " << Equiv.First << " and " 256 << Equiv.Second; 257 } 258 259 using CanonKey = llvm::ItaniumManglingCanonicalizer::Key; 260 std::map<CanonKey, llvm::StringRef> Found; 261 for (const auto &Class : Testcase.Classes) { 262 CanonKey ClassKey = {}; 263 for (llvm::StringRef Str : Class) { 264 CanonKey ThisKey = Canonicalizer.canonicalize(Str); 265 EXPECT_NE(ThisKey, CanonKey()) << "couldn't canonicalize " << Str; 266 if (ClassKey) { 267 EXPECT_EQ(ThisKey, ClassKey) 268 << Str << " not in the same class as " << *Class.begin(); 269 } else { 270 ClassKey = ThisKey; 271 } 272 } 273 EXPECT_TRUE(Found.insert({ClassKey, *Class.begin()}).second) 274 << *Class.begin() << " is in the same class as " << Found[ClassKey]; 275 } 276 } 277 } 278 279 TEST(ItaniumManglingCanonicalizerTest, TestInvalidManglings) { 280 llvm::ItaniumManglingCanonicalizer Canonicalizer; 281 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "", "1X"), 282 EquivalenceError::InvalidFirstMangling); 283 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1X", "1ab"), 284 EquivalenceError::InvalidSecondMangling); 285 EXPECT_EQ(Canonicalizer.canonicalize("_Z3fooE"), 286 llvm::ItaniumManglingCanonicalizer::Key()); 287 EXPECT_EQ(Canonicalizer.canonicalize("foo"), 288 llvm::ItaniumManglingCanonicalizer::Key()); 289 290 // A reference to a template parameter ('T_' etc) cannot appear in a <name>, 291 // because we don't have template arguments to bind to it. (The arguments in 292 // an 'I ... E' construct in the <name> aren't registered as 293 // backreferenceable arguments in this sense, because they're not part of 294 // the template argument list of an <encoding>. 295 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Name, "N1XcvT_I1AEE", 296 "1f"), 297 EquivalenceError::InvalidFirstMangling); 298 } 299 300 TEST(ItaniumManglingCanonicalizerTest, TestBadEquivalenceOrder) { 301 llvm::ItaniumManglingCanonicalizer Canonicalizer; 302 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "N1P1XE", "N1Q1XE"), 303 EquivalenceError::Success); 304 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1P", "1Q"), 305 EquivalenceError::ManglingAlreadyUsed); 306 307 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "N1C1XE", "N1A1YE"), 308 EquivalenceError::Success); 309 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1A", "1B"), 310 EquivalenceError::Success); 311 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1C", "1D"), 312 EquivalenceError::Success); 313 EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1B", "1D"), 314 EquivalenceError::ManglingAlreadyUsed); 315 } 316