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