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