blob: 740cc0319f042094561162103aac7e6203d4987d [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
10#include <cstdlib>
11#include "llvm/Support/ItaniumManglingCanonicalizer.h"
12#include "gtest/gtest.h"
13
14using EquivalenceError = llvm::ItaniumManglingCanonicalizer::EquivalenceError;
15using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind;
16
17struct 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.
24using EquivalenceClass = std::initializer_list<llvm::StringRef>;
25
26struct 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
34static 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
248TEST(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
279TEST(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
300TEST(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}