Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 1 | //===-------------- ItaniumManglingCanonicalizerTest.cpp ------------------===// |
| 2 | // |
Chandler Carruth | 57b08b0 | 2019-01-19 10:56:40 +0000 | [diff] [blame] | 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 |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 9 | #include "llvm/Support/ItaniumManglingCanonicalizer.h" |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 10 | #include "llvm/ADT/ArrayRef.h" |
| 11 | #include "llvm/ADT/StringRef.h" |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 12 | #include "gtest/gtest.h" |
| 13 | |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 14 | #include <cstdlib> |
| 15 | #include <map> |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 16 | #include <vector> |
| 17 | |
| 18 | using namespace llvm; |
| 19 | |
| 20 | namespace { |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 21 | |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 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. |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 32 | using EquivalenceClass = std::vector<llvm::StringRef>; |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 33 | |
| 34 | struct Testcase { |
| 35 | // A set of equivalences to register. |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 36 | std::vector<Equivalence> Equivalences; |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 37 | // A set of distinct equivalence classes created by registering the |
| 38 | // equivalences. |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 39 | std::vector<EquivalenceClass> Classes; |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 40 | }; |
| 41 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 42 | // A function that returns a set of test cases. |
| 43 | static std::vector<Testcase> getTestcases() { |
| 44 | return { |
| 45 | // Three different manglings for std::string (old libstdc++, new libstdc++, |
| 46 | // libc++). |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 47 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 63 | }, |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 64 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 65 | // Check that substitutions are properly handled. |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 66 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 79 | }, |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 80 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 81 | // Check that nested equivalences are properly handled. |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 82 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 126 | }, |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 127 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 128 | // Check namespace equivalences. |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 129 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 157 | }, |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 158 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 159 | // Check namespace equivalences for namespace 'std'. We support using 'St' |
| 160 | // for this, despite it not technically being a <name>. |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 161 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 181 | }, |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 182 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 183 | // Check mutually-recursive equivalences. |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 184 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 195 | }, |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 196 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 197 | // Check <encoding>s. |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 198 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 208 | }, |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 209 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 210 | // Corner case: the substitution can appear within its own expansion. |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 211 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 224 | }, |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 225 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 226 | // Redundant equivalences are accepted (and have no effect). |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 227 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 228 | { |
| 229 | {FragmentKind::Name, "3std", "St"}, |
| 230 | {FragmentKind::Name, "1X", "1Y"}, |
| 231 | {FragmentKind::Name, "N1X1ZE", "N1Y1ZE"}, |
| 232 | }, |
| 233 | {} |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 234 | }, |
Richard Smith | 8d8c057 | 2018-09-13 20:00:21 +0000 | [diff] [blame] | 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 | }, |
Richard Smith | b6e90a1 | 2019-12-18 10:44:29 -0800 | [diff] [blame] | 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 | }, |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 265 | }; |
| 266 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 267 | |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 268 | // A function to get a set of test cases for forward template references. |
| 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. |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 274 | { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 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 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 290 | }, |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 291 | }; |
| 292 | } |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 293 | |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 294 | template<bool CanonicalizeFirst> |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 295 | static void testTestcases(ArrayRef<Testcase> Testcases) { |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 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; |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 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 | |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 313 | std::map<CanonKey, llvm::StringRef> Found; |
| 314 | for (const auto &Class : Testcase.Classes) { |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 315 | CanonKey ClassKey = Keys[&Class]; |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 316 | for (llvm::StringRef Str : Class) { |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 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); |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 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 | |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 336 | TEST(ItaniumManglingCanonicalizerTest, TestCanonicalize) { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 337 | testTestcases<false>(getTestcases()); |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 338 | } |
| 339 | |
| 340 | TEST(ItaniumManglingCanonicalizerTest, TestLookup) { |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 341 | testTestcases<true>(getTestcases()); |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 342 | } |
| 343 | |
| 344 | TEST(ItaniumManglingCanonicalizerTest, TestForwardTemplateReference) { |
| 345 | // lookup(...) after canonicalization (intentionally) returns different |
| 346 | // values for this testcase. |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 347 | testTestcases<false>(getForwardTemplateReferenceTestcases()); |
Richard Smith | 9c2e4f3 | 2018-08-24 23:26:05 +0000 | [diff] [blame] | 348 | } |
| 349 | |
| 350 | |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 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()); |
Richard Smith | b6e90a1 | 2019-12-18 10:44:29 -0800 | [diff] [blame] | 359 | EXPECT_EQ(Canonicalizer.canonicalize("_Zfoo"), |
Richard Smith | 2ae8468 | 2018-08-24 22:31:51 +0000 | [diff] [blame] | 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 | |
| 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 | } |
Chandler Carruth | 6eb2b13 | 2018-08-26 10:03:08 +0000 | [diff] [blame] | 388 | |
| 389 | } // end anonymous namespace |