blob: 2fd6bd8c558026954993a5388111f38aa0dcb132 [file] [log] [blame]
Richard Smith2ae84682018-08-24 22:31:51 +00001//===-------------- 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
Richard Smith2ae84682018-08-24 22:31:51 +000010#include "llvm/Support/ItaniumManglingCanonicalizer.h"
Chandler Carruth6eb2b132018-08-26 10:03:08 +000011#include "llvm/ADT/ArrayRef.h"
12#include "llvm/ADT/StringRef.h"
Richard Smith2ae84682018-08-24 22:31:51 +000013#include "gtest/gtest.h"
14
Richard Smith9c2e4f32018-08-24 23:26:05 +000015#include <cstdlib>
16#include <map>
Chandler Carruth6eb2b132018-08-26 10:03:08 +000017#include <vector>
18
19using namespace llvm;
20
21namespace {
Richard Smith9c2e4f32018-08-24 23:26:05 +000022
Richard Smith2ae84682018-08-24 22:31:51 +000023using EquivalenceError = llvm::ItaniumManglingCanonicalizer::EquivalenceError;
24using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind;
25
26struct 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.
Chandler Carruth6eb2b132018-08-26 10:03:08 +000033using EquivalenceClass = std::vector<llvm::StringRef>;
Richard Smith2ae84682018-08-24 22:31:51 +000034
35struct Testcase {
36 // A set of equivalences to register.
Chandler Carruth6eb2b132018-08-26 10:03:08 +000037 std::vector<Equivalence> Equivalences;
Richard Smith2ae84682018-08-24 22:31:51 +000038 // A set of distinct equivalence classes created by registering the
39 // equivalences.
Chandler Carruth6eb2b132018-08-26 10:03:08 +000040 std::vector<EquivalenceClass> Classes;
Richard Smith2ae84682018-08-24 22:31:51 +000041};
42
Chandler Carruth6eb2b132018-08-26 10:03:08 +000043// A function that returns a set of test cases.
44static std::vector<Testcase> getTestcases() {
45 return {
46 // Three different manglings for std::string (old libstdc++, new libstdc++,
47 // libc++).
Richard Smith2ae84682018-08-24 22:31:51 +000048 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +000049 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +000064 },
Richard Smith2ae84682018-08-24 22:31:51 +000065
Chandler Carruth6eb2b132018-08-26 10:03:08 +000066 // Check that substitutions are properly handled.
Richard Smith2ae84682018-08-24 22:31:51 +000067 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +000068 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +000080 },
Richard Smith2ae84682018-08-24 22:31:51 +000081
Chandler Carruth6eb2b132018-08-26 10:03:08 +000082 // Check that nested equivalences are properly handled.
Richard Smith2ae84682018-08-24 22:31:51 +000083 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +000084 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +0000127 },
Richard Smith2ae84682018-08-24 22:31:51 +0000128
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000129 // Check namespace equivalences.
Richard Smith2ae84682018-08-24 22:31:51 +0000130 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000131 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +0000158 },
Richard Smith2ae84682018-08-24 22:31:51 +0000159
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000160 // Check namespace equivalences for namespace 'std'. We support using 'St'
161 // for this, despite it not technically being a <name>.
Richard Smith2ae84682018-08-24 22:31:51 +0000162 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000163 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +0000182 },
Richard Smith2ae84682018-08-24 22:31:51 +0000183
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000184 // Check mutually-recursive equivalences.
Richard Smith2ae84682018-08-24 22:31:51 +0000185 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000186 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +0000196 },
Richard Smith2ae84682018-08-24 22:31:51 +0000197
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000198 // Check <encoding>s.
Richard Smith2ae84682018-08-24 22:31:51 +0000199 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000200 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +0000209 },
Richard Smith2ae84682018-08-24 22:31:51 +0000210
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000211 // Corner case: the substitution can appear within its own expansion.
Richard Smith2ae84682018-08-24 22:31:51 +0000212 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000213 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +0000225 },
Richard Smith2ae84682018-08-24 22:31:51 +0000226
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000227 // Redundant equivalences are accepted (and have no effect).
Richard Smith2ae84682018-08-24 22:31:51 +0000228 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000229 {
230 {FragmentKind::Name, "3std", "St"},
231 {FragmentKind::Name, "1X", "1Y"},
232 {FragmentKind::Name, "N1X1ZE", "N1Y1ZE"},
233 },
234 {}
Richard Smith2ae84682018-08-24 22:31:51 +0000235 },
Richard Smith8d8c0572018-09-13 20:00:21 +0000236
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 },
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000253 };
254}
Richard Smith2ae84682018-08-24 22:31:51 +0000255
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000256// A function to get a set of test cases for forward template references.
257static 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.
Richard Smith2ae84682018-08-24 22:31:51 +0000262 {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000263 {
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 }
Richard Smith2ae84682018-08-24 22:31:51 +0000278 },
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000279 };
280}
Richard Smith2ae84682018-08-24 22:31:51 +0000281
Richard Smith9c2e4f32018-08-24 23:26:05 +0000282template<bool CanonicalizeFirst>
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000283static void testTestcases(ArrayRef<Testcase> Testcases) {
Richard Smith2ae84682018-08-24 22:31:51 +0000284 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;
Richard Smith9c2e4f32018-08-24 23:26:05 +0000295
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
Richard Smith2ae84682018-08-24 22:31:51 +0000301 std::map<CanonKey, llvm::StringRef> Found;
302 for (const auto &Class : Testcase.Classes) {
Richard Smith9c2e4f32018-08-24 23:26:05 +0000303 CanonKey ClassKey = Keys[&Class];
Richard Smith2ae84682018-08-24 22:31:51 +0000304 for (llvm::StringRef Str : Class) {
Richard Smith9c2e4f32018-08-24 23:26:05 +0000305 // 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);
Richard Smith2ae84682018-08-24 22:31:51 +0000310 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
Richard Smith9c2e4f32018-08-24 23:26:05 +0000324TEST(ItaniumManglingCanonicalizerTest, TestCanonicalize) {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000325 testTestcases<false>(getTestcases());
Richard Smith9c2e4f32018-08-24 23:26:05 +0000326}
327
328TEST(ItaniumManglingCanonicalizerTest, TestLookup) {
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000329 testTestcases<true>(getTestcases());
Richard Smith9c2e4f32018-08-24 23:26:05 +0000330}
331
332TEST(ItaniumManglingCanonicalizerTest, TestForwardTemplateReference) {
333 // lookup(...) after canonicalization (intentionally) returns different
334 // values for this testcase.
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000335 testTestcases<false>(getForwardTemplateReferenceTestcases());
Richard Smith9c2e4f32018-08-24 23:26:05 +0000336}
337
338
Richard Smith2ae84682018-08-24 22:31:51 +0000339TEST(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
360TEST(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}
Chandler Carruth6eb2b132018-08-26 10:03:08 +0000376
377} // end anonymous namespace