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