ItaniumManglingCanonicalizerTest.cpp 13 KB

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