1 1.1 mrg /** 2 1.1 mrg * Do mangling for C++ linkage. 3 1.1 mrg * 4 1.1 mrg * This is the POSIX side of the implementation. 5 1.1 mrg * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`. 6 1.1 mrg * 7 1.1 mrg * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved 8 1.1 mrg * Authors: Walter Bright, https://www.digitalmars.com 9 1.1 mrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 10 1.1 mrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d) 11 1.1 mrg * Documentation: https://dlang.org/phobos/dmd_cppmangle.html 12 1.1 mrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cppmangle.d 13 1.1 mrg * 14 1.1 mrg * References: 15 1.1 mrg * Follows Itanium C++ ABI 1.86 section 5.1 16 1.1 mrg * http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling 17 1.1 mrg * which is where the grammar comments come from. 18 1.1 mrg * 19 1.1 mrg * Bugs: 20 1.1 mrg * https://issues.dlang.org/query.cgi 21 1.1 mrg * enter `C++, mangling` as the keywords. 22 1.1 mrg */ 23 1.1 mrg 24 1.1 mrg module dmd.cppmangle; 25 1.1 mrg 26 1.1 mrg import core.stdc.string; 27 1.1 mrg import core.stdc.stdio; 28 1.1 mrg 29 1.1 mrg import dmd.arraytypes; 30 1.1 mrg import dmd.astenums; 31 1.1 mrg import dmd.attrib; 32 1.1 mrg import dmd.declaration; 33 1.1 mrg import dmd.dsymbol; 34 1.1 mrg import dmd.dtemplate; 35 1.1 mrg import dmd.errors; 36 1.1 mrg import dmd.expression; 37 1.1 mrg import dmd.func; 38 1.1 mrg import dmd.globals; 39 1.1 mrg import dmd.id; 40 1.1 mrg import dmd.identifier; 41 1.1 mrg import dmd.mtype; 42 1.1 mrg import dmd.nspace; 43 1.1 mrg import dmd.root.array; 44 1.1 mrg import dmd.common.outbuffer; 45 1.1 mrg import dmd.root.rootobject; 46 1.1 mrg import dmd.root.string; 47 1.1 mrg import dmd.target; 48 1.1 mrg import dmd.tokens; 49 1.1 mrg import dmd.typesem; 50 1.1 mrg import dmd.visitor; 51 1.1 mrg 52 1.1 mrg 53 1.1 mrg // helper to check if an identifier is a C++ operator 54 1.1 mrg enum CppOperator { Cast, Assign, Eq, Index, Call, Unary, Binary, OpAssign, Unknown } 55 1.1 mrg package CppOperator isCppOperator(Identifier id) 56 1.1 mrg { 57 1.1 mrg __gshared const(Identifier)[] operators = null; 58 1.1 mrg if (!operators) 59 1.1 mrg operators = [Id._cast, Id.assign, Id.eq, Id.index, Id.call, Id.opUnary, Id.opBinary, Id.opOpAssign]; 60 1.1 mrg foreach (i, op; operators) 61 1.1 mrg { 62 1.1 mrg if (op == id) 63 1.1 mrg return cast(CppOperator)i; 64 1.1 mrg } 65 1.1 mrg return CppOperator.Unknown; 66 1.1 mrg } 67 1.1 mrg 68 1.1 mrg /// 69 1.1 mrg extern(C++) const(char)* toCppMangleItanium(Dsymbol s) 70 1.1 mrg { 71 1.1 mrg //printf("toCppMangleItanium(%s)\n", s.toChars()); 72 1.1 mrg OutBuffer buf; 73 1.1 mrg scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc); 74 1.1 mrg v.mangleOf(s); 75 1.1 mrg return buf.extractChars(); 76 1.1 mrg } 77 1.1 mrg 78 1.1 mrg /// 79 1.1 mrg extern(C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s) 80 1.1 mrg { 81 1.1 mrg //printf("cppTypeInfoMangle(%s)\n", s.toChars()); 82 1.1 mrg OutBuffer buf; 83 1.1 mrg buf.writestring("_ZTI"); // "TI" means typeinfo structure 84 1.1 mrg scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc); 85 1.1 mrg v.cpp_mangle_name(s, false); 86 1.1 mrg return buf.extractChars(); 87 1.1 mrg } 88 1.1 mrg 89 1.1 mrg /// 90 1.1 mrg extern(C++) const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset) 91 1.1 mrg { 92 1.1 mrg //printf("cppThunkMangleItanium(%s)\n", fd.toChars()); 93 1.1 mrg OutBuffer buf; 94 1.1 mrg buf.printf("_ZThn%u_", offset); // "Th" means thunk, "n%u" is the call offset 95 1.1 mrg scope CppMangleVisitor v = new CppMangleVisitor(&buf, fd.loc); 96 1.1 mrg v.mangle_function_encoding(fd); 97 1.1 mrg return buf.extractChars(); 98 1.1 mrg } 99 1.1 mrg 100 1.1 mrg /****************************** 101 1.1 mrg * Determine if sym is a full aggregate destructor. 102 1.1 mrg * Params: 103 1.1 mrg * sym = Dsymbol 104 1.1 mrg * Returns: 105 1.1 mrg * true if sym is an aggregate destructor 106 1.1 mrg */ 107 1.1 mrg bool isAggregateDtor(const Dsymbol sym) 108 1.1 mrg { 109 1.1 mrg const dtor = sym.isDtorDeclaration(); 110 1.1 mrg if (!dtor) 111 1.1 mrg return false; 112 1.1 mrg const ad = dtor.isMember(); 113 1.1 mrg assert(ad); 114 1.1 mrg return dtor == ad.aggrDtor; 115 1.1 mrg } 116 1.1 mrg 117 1.1 mrg /// Context used when processing pre-semantic AST 118 1.1 mrg private struct Context 119 1.1 mrg { 120 1.1 mrg /// Template instance of the function being mangled 121 1.1 mrg TemplateInstance ti; 122 1.1 mrg /// Function declaration we're mangling 123 1.1 mrg FuncDeclaration fd; 124 1.1 mrg /// Current type / expression being processed (semantically analyzed) 125 1.1 mrg RootObject res; 126 1.1 mrg 127 1.1 mrg @disable ref Context opAssign(ref Context other); 128 1.1 mrg @disable ref Context opAssign(Context other); 129 1.1 mrg 130 1.1 mrg /** 131 1.1 mrg * Helper function to track `res` 132 1.1 mrg * 133 1.1 mrg * Params: 134 1.1 mrg * next = Value to set `this.res` to. 135 1.1 mrg * If `this.res` is `null`, the expression is not evalutated. 136 1.1 mrg * This allow this code to be used even when no context is needed. 137 1.1 mrg * 138 1.1 mrg * Returns: 139 1.1 mrg * The previous state of this `Context` object 140 1.1 mrg */ 141 1.1 mrg private Context push(lazy RootObject next) 142 1.1 mrg { 143 1.1 mrg auto r = this.res; 144 1.1 mrg if (r !is null) 145 1.1 mrg this.res = next; 146 1.1 mrg return Context(this.ti, this.fd, r); 147 1.1 mrg } 148 1.1 mrg 149 1.1 mrg /** 150 1.1 mrg * Reset the context to a previous one, making any adjustment necessary 151 1.1 mrg */ 152 1.1 mrg private void pop(ref Context prev) 153 1.1 mrg { 154 1.1 mrg this.res = prev.res; 155 1.1 mrg } 156 1.1 mrg } 157 1.1 mrg 158 1.1 mrg private final class CppMangleVisitor : Visitor 159 1.1 mrg { 160 1.1 mrg /// Context used when processing pre-semantic AST 161 1.1 mrg private Context context; 162 1.1 mrg 163 1.1 mrg ABITagContainer abiTags; /// Container for already-written ABI tags 164 1.1 mrg Objects components; /// array of components available for substitution 165 1.1 mrg OutBuffer* buf; /// append the mangling to buf[] 166 1.1 mrg Loc loc; /// location for use in error messages 167 1.1 mrg 168 1.1 mrg /** 169 1.1 mrg * Constructor 170 1.1 mrg * 171 1.1 mrg * Params: 172 1.1 mrg * buf = `OutBuffer` to write the mangling to 173 1.1 mrg * loc = `Loc` of the symbol being mangled 174 1.1 mrg */ 175 1.1 mrg this(OutBuffer* buf, Loc loc) 176 1.1 mrg { 177 1.1 mrg this.buf = buf; 178 1.1 mrg this.loc = loc; 179 1.1 mrg } 180 1.1 mrg 181 1.1 mrg /***** 182 1.1 mrg * Entry point. Append mangling to buf[] 183 1.1 mrg * Params: 184 1.1 mrg * s = symbol to mangle 185 1.1 mrg */ 186 1.1 mrg void mangleOf(Dsymbol s) 187 1.1 mrg { 188 1.1 mrg if (VarDeclaration vd = s.isVarDeclaration()) 189 1.1 mrg { 190 1.1 mrg mangle_variable(vd, vd.cppnamespace !is null); 191 1.1 mrg } 192 1.1 mrg else if (FuncDeclaration fd = s.isFuncDeclaration()) 193 1.1 mrg { 194 1.1 mrg mangle_function(fd); 195 1.1 mrg } 196 1.1 mrg else 197 1.1 mrg { 198 1.1 mrg assert(0); 199 1.1 mrg } 200 1.1 mrg } 201 1.1 mrg 202 1.1 mrg /** 203 1.1 mrg * Mangle the return type of a function 204 1.1 mrg * 205 1.1 mrg * This is called on a templated function type. 206 1.1 mrg * Context is set to the `FuncDeclaration`. 207 1.1 mrg * 208 1.1 mrg * Params: 209 1.1 mrg * preSemantic = the `FuncDeclaration`'s `originalType` 210 1.1 mrg */ 211 1.1 mrg void mangleReturnType(TypeFunction preSemantic) 212 1.1 mrg { 213 1.1 mrg auto tf = cast(TypeFunction)this.context.res.asFuncDecl().type; 214 1.1 mrg Type rt = preSemantic.nextOf(); 215 1.1 mrg if (tf.isref) 216 1.1 mrg rt = rt.referenceTo(); 217 1.1 mrg auto prev = this.context.push(tf.nextOf()); 218 1.1 mrg scope (exit) this.context.pop(prev); 219 1.1 mrg this.headOfType(rt); 220 1.1 mrg } 221 1.1 mrg 222 1.1 mrg /** 223 1.1 mrg * Write a seq-id from an index number, excluding the terminating '_' 224 1.1 mrg * 225 1.1 mrg * Params: 226 1.1 mrg * idx = the index in a substitution list. 227 1.1 mrg * Note that index 0 has no value, and `S0_` would be the 228 1.1 mrg * substitution at index 1 in the list. 229 1.1 mrg * 230 1.1 mrg * See-Also: 231 1.1 mrg * https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id 232 1.1 mrg */ 233 1.1 mrg private void writeSequenceFromIndex(size_t idx) 234 1.1 mrg { 235 1.1 mrg if (idx) 236 1.1 mrg { 237 1.1 mrg void write_seq_id(size_t i) 238 1.1 mrg { 239 1.1 mrg if (i >= 36) 240 1.1 mrg { 241 1.1 mrg write_seq_id(i / 36); 242 1.1 mrg i %= 36; 243 1.1 mrg } 244 1.1 mrg i += (i < 10) ? '0' : 'A' - 10; 245 1.1 mrg buf.writeByte(cast(char)i); 246 1.1 mrg } 247 1.1 mrg 248 1.1 mrg write_seq_id(idx - 1); 249 1.1 mrg } 250 1.1 mrg } 251 1.1 mrg 252 1.1 mrg /** 253 1.1 mrg * Attempt to perform substitution on `p` 254 1.1 mrg * 255 1.1 mrg * If `p` already appeared in the mangling, it is stored as 256 1.1 mrg * a 'part', and short references in the form of `SX_` can be used. 257 1.1 mrg * Note that `p` can be anything: template declaration, struct declaration, 258 1.1 mrg * class declaration, namespace... 259 1.1 mrg * 260 1.1 mrg * Params: 261 1.1 mrg * p = The object to attempt to substitute 262 1.1 mrg * nested = Whether or not `p` is to be considered nested. 263 1.1 mrg * When `true`, `N` will be prepended before the substitution. 264 1.1 mrg * 265 1.1 mrg * Returns: 266 1.1 mrg * Whether `p` already appeared in the mangling, 267 1.1 mrg * and substitution has been written to `this.buf`. 268 1.1 mrg */ 269 1.1 mrg bool substitute(RootObject p, bool nested = false) 270 1.1 mrg { 271 1.1 mrg //printf("substitute %s\n", p ? p.toChars() : null); 272 1.1 mrg auto i = find(p); 273 1.1 mrg if (i < 0) 274 1.1 mrg return false; 275 1.1 mrg 276 1.1 mrg //printf("\tmatch\n"); 277 1.1 mrg /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... 278 1.1 mrg */ 279 1.1 mrg if (nested) 280 1.1 mrg buf.writeByte('N'); 281 1.1 mrg buf.writeByte('S'); 282 1.1 mrg writeSequenceFromIndex(i); 283 1.1 mrg buf.writeByte('_'); 284 1.1 mrg return true; 285 1.1 mrg } 286 1.1 mrg 287 1.1 mrg /****** 288 1.1 mrg * See if `p` exists in components[] 289 1.1 mrg * 290 1.1 mrg * Note that components can contain `null` entries, 291 1.1 mrg * as the index used in mangling is based on the index in the array. 292 1.1 mrg * 293 1.1 mrg * If called with an object whose dynamic type is `Nspace`, 294 1.1 mrg * calls the `find(Nspace)` overload. 295 1.1 mrg * 296 1.1 mrg * Returns: 297 1.1 mrg * index if found, -1 if not 298 1.1 mrg */ 299 1.1 mrg int find(RootObject p) 300 1.1 mrg { 301 1.1 mrg //printf("find %p %d %s\n", p, p.dyncast(), p ? p.toChars() : null); 302 1.1 mrg scope v = new ComponentVisitor(p); 303 1.1 mrg foreach (i, component; components) 304 1.1 mrg { 305 1.1 mrg if (component) 306 1.1 mrg component.visitObject(v); 307 1.1 mrg if (v.result) 308 1.1 mrg return cast(int)i; 309 1.1 mrg } 310 1.1 mrg return -1; 311 1.1 mrg } 312 1.1 mrg 313 1.1 mrg /********************* 314 1.1 mrg * Append p to components[] 315 1.1 mrg */ 316 1.1 mrg void append(RootObject p) 317 1.1 mrg { 318 1.1 mrg //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null"); 319 1.1 mrg components.push(p); 320 1.1 mrg } 321 1.1 mrg 322 1.1 mrg /** 323 1.1 mrg * Write an identifier preceded by its length 324 1.1 mrg * 325 1.1 mrg * Params: 326 1.1 mrg * ident = `Identifier` to write to `this.buf` 327 1.1 mrg */ 328 1.1 mrg void writeIdentifier(const ref Identifier ident) 329 1.1 mrg { 330 1.1 mrg const name = ident.toString(); 331 1.1 mrg this.buf.print(name.length); 332 1.1 mrg this.buf.writestring(name); 333 1.1 mrg } 334 1.1 mrg 335 1.1 mrg /** 336 1.1 mrg * Insert the leftover ABI tags to the buffer 337 1.1 mrg * 338 1.1 mrg * This inset ABI tags that hasn't already been written 339 1.1 mrg * after the mangled name of the function. 340 1.1 mrg * For more details, see the `abiTags` variable. 341 1.1 mrg * 342 1.1 mrg * Params: 343 1.1 mrg * off = Offset to insert at 344 1.1 mrg * fd = Type of the function to mangle the return type of 345 1.1 mrg */ 346 1.1 mrg void writeRemainingTags(size_t off, TypeFunction tf) 347 1.1 mrg { 348 1.1 mrg scope remainingVisitor = new LeftoverVisitor(&this.abiTags.written); 349 1.1 mrg tf.next.accept(remainingVisitor); 350 1.1 mrg OutBuffer b2; 351 1.1 mrg foreach (se; remainingVisitor.toWrite) 352 1.1 mrg { 353 1.1 mrg auto tag = se.peekString(); 354 1.1 mrg // We can only insert a slice, and each insert is a memmove, 355 1.1 mrg // so use a temporary buffer to keep it efficient. 356 1.1 mrg b2.reset(); 357 1.1 mrg b2.writestring("B"); 358 1.1 mrg b2.print(tag.length); 359 1.1 mrg b2.writestring(tag); 360 1.1 mrg this.buf.insert(off, b2[]); 361 1.1 mrg off += b2.length; 362 1.1 mrg } 363 1.1 mrg } 364 1.1 mrg 365 1.1 mrg /************************ 366 1.1 mrg * Determine if symbol is indeed the global ::std namespace. 367 1.1 mrg * Params: 368 1.1 mrg * s = symbol to check 369 1.1 mrg * Returns: 370 1.1 mrg * true if it is ::std 371 1.1 mrg */ 372 1.1 mrg static bool isStd(Dsymbol s) 373 1.1 mrg { 374 1.1 mrg if (!s) 375 1.1 mrg return false; 376 1.1 mrg 377 1.1 mrg if (auto cnd = s.isCPPNamespaceDeclaration()) 378 1.1 mrg return isStd(cnd); 379 1.1 mrg 380 1.1 mrg return (s.ident == Id.std && // the right name 381 1.1 mrg s.isNspace() && // g++ disallows global "std" for other than a namespace 382 1.1 mrg !getQualifier(s)); // at global level 383 1.1 mrg } 384 1.1 mrg 385 1.1 mrg /// Ditto 386 1.1 mrg static bool isStd(CPPNamespaceDeclaration s) 387 1.1 mrg { 388 1.1 mrg return s && s.cppnamespace is null && s.ident == Id.std; 389 1.1 mrg } 390 1.1 mrg 391 1.1 mrg /************************ 392 1.1 mrg * Determine if type is a C++ fundamental type. 393 1.1 mrg * Params: 394 1.1 mrg * t = type to check 395 1.1 mrg * Returns: 396 1.1 mrg * true if it is a fundamental type 397 1.1 mrg */ 398 1.1 mrg static bool isFundamentalType(Type t) 399 1.1 mrg { 400 1.1 mrg // First check the target whether some specific ABI is being followed. 401 1.1 mrg bool isFundamental = void; 402 1.1 mrg if (target.cpp.fundamentalType(t, isFundamental)) 403 1.1 mrg return isFundamental; 404 1.1 mrg 405 1.1 mrg if (auto te = t.isTypeEnum()) 406 1.1 mrg { 407 1.1 mrg // Peel off enum type from special types. 408 1.1 mrg if (te.sym.isSpecial()) 409 1.1 mrg t = te.memType(); 410 1.1 mrg } 411 1.1 mrg 412 1.1 mrg // Fundamental arithmetic types: 413 1.1 mrg // 1. integral types: bool, char, int, ... 414 1.1 mrg // 2. floating point types: float, double, real 415 1.1 mrg // 3. void 416 1.1 mrg // 4. null pointer: std::nullptr_t (since C++11) 417 1.1 mrg if (t.ty == Tvoid || t.ty == Tbool) 418 1.1 mrg return true; 419 1.1 mrg else if (t.ty == Tnull && global.params.cplusplus >= CppStdRevision.cpp11) 420 1.1 mrg return true; 421 1.1 mrg else 422 1.1 mrg return t.isTypeBasic() && (t.isintegral() || t.isreal()); 423 1.1 mrg } 424 1.1 mrg 425 1.1 mrg /****************************** 426 1.1 mrg * Write the mangled representation of a template argument. 427 1.1 mrg * Params: 428 1.1 mrg * ti = the template instance 429 1.1 mrg * arg = the template argument index 430 1.1 mrg */ 431 1.1 mrg void template_arg(TemplateInstance ti, size_t arg) 432 1.1 mrg { 433 1.1 mrg TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); 434 1.1 mrg assert(td); 435 1.1 mrg TemplateParameter tp = (*td.parameters)[arg]; 436 1.1 mrg RootObject o = (*ti.tiargs)[arg]; 437 1.1 mrg 438 1.1 mrg auto prev = this.context.push({ 439 1.1 mrg TemplateInstance parentti; 440 1.1 mrg if (this.context.res.dyncast() == DYNCAST.dsymbol) 441 1.1 mrg parentti = this.context.res.asFuncDecl().parent.isTemplateInstance(); 442 1.1 mrg else 443 1.1 mrg parentti = this.context.res.asType().toDsymbol(null).parent.isTemplateInstance(); 444 1.1 mrg return (*parentti.tiargs)[arg]; 445 1.1 mrg }()); 446 1.1 mrg scope (exit) this.context.pop(prev); 447 1.1 mrg 448 1.1 mrg if (tp.isTemplateTypeParameter()) 449 1.1 mrg { 450 1.1 mrg Type t = isType(o); 451 1.1 mrg assert(t); 452 1.1 mrg t.accept(this); 453 1.1 mrg } 454 1.1 mrg else if (TemplateValueParameter tv = tp.isTemplateValueParameter()) 455 1.1 mrg { 456 1.1 mrg // <expr-primary> ::= L <type> <value number> E # integer literal 457 1.1 mrg if (tv.valType.isintegral()) 458 1.1 mrg { 459 1.1 mrg Expression e = isExpression(o); 460 1.1 mrg assert(e); 461 1.1 mrg buf.writeByte('L'); 462 1.1 mrg tv.valType.accept(this); 463 1.1 mrg auto val = e.toUInteger(); 464 1.1 mrg if (!tv.valType.isunsigned() && cast(sinteger_t)val < 0) 465 1.1 mrg { 466 1.1 mrg val = -val; 467 1.1 mrg buf.writeByte('n'); 468 1.1 mrg } 469 1.1 mrg buf.print(val); 470 1.1 mrg buf.writeByte('E'); 471 1.1 mrg } 472 1.1 mrg else 473 1.1 mrg { 474 1.1 mrg ti.error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv.valType.toChars()); 475 1.1 mrg fatal(); 476 1.1 mrg } 477 1.1 mrg } 478 1.1 mrg else if (tp.isTemplateAliasParameter()) 479 1.1 mrg { 480 1.1 mrg // Passing a function as alias parameter is the same as passing 481 1.1 mrg // `&function` 482 1.1 mrg Dsymbol d = isDsymbol(o); 483 1.1 mrg Expression e = isExpression(o); 484 1.1 mrg if (d && d.isFuncDeclaration()) 485 1.1 mrg { 486 1.1 mrg // X .. E => template parameter is an expression 487 1.1 mrg // 'ad' => unary operator ('&') 488 1.1 mrg // L .. E => is a <expr-primary> 489 1.1 mrg buf.writestring("XadL"); 490 1.1 mrg mangle_function(d.isFuncDeclaration()); 491 1.1 mrg buf.writestring("EE"); 492 1.1 mrg } 493 1.1 mrg else if (e && e.op == EXP.variable && (cast(VarExp)e).var.isVarDeclaration()) 494 1.1 mrg { 495 1.1 mrg VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); 496 1.1 mrg buf.writeByte('L'); 497 1.1 mrg mangle_variable(vd, true); 498 1.1 mrg buf.writeByte('E'); 499 1.1 mrg } 500 1.1 mrg else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) 501 1.1 mrg { 502 1.1 mrg if (!substitute(d)) 503 1.1 mrg { 504 1.1 mrg cpp_mangle_name(d, false); 505 1.1 mrg } 506 1.1 mrg } 507 1.1 mrg else 508 1.1 mrg { 509 1.1 mrg ti.error("Internal Compiler Error: C++ `%s` template alias parameter is not supported", o.toChars()); 510 1.1 mrg fatal(); 511 1.1 mrg } 512 1.1 mrg } 513 1.1 mrg else if (tp.isTemplateThisParameter()) 514 1.1 mrg { 515 1.1 mrg ti.error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o.toChars()); 516 1.1 mrg fatal(); 517 1.1 mrg } 518 1.1 mrg else 519 1.1 mrg { 520 1.1 mrg assert(0); 521 1.1 mrg } 522 1.1 mrg } 523 1.1 mrg 524 1.1 mrg /****************************** 525 1.1 mrg * Write the mangled representation of the template arguments. 526 1.1 mrg * Params: 527 1.1 mrg * ti = the template instance 528 1.1 mrg * firstArg = index of the first template argument to mangle 529 1.1 mrg * (used for operator overloading) 530 1.1 mrg * Returns: 531 1.1 mrg * true if any arguments were written 532 1.1 mrg */ 533 1.1 mrg bool template_args(TemplateInstance ti, int firstArg = 0) 534 1.1 mrg { 535 1.1 mrg /* <template-args> ::= I <template-arg>+ E 536 1.1 mrg */ 537 1.1 mrg if (!ti || ti.tiargs.dim <= firstArg) // could happen if std::basic_string is not a template 538 1.1 mrg return false; 539 1.1 mrg buf.writeByte('I'); 540 1.1 mrg foreach (i; firstArg .. ti.tiargs.dim) 541 1.1 mrg { 542 1.1 mrg TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); 543 1.1 mrg assert(td); 544 1.1 mrg TemplateParameter tp = (*td.parameters)[i]; 545 1.1 mrg 546 1.1 mrg /* 547 1.1 mrg * <template-arg> ::= <type> # type or template 548 1.1 mrg * ::= X <expression> E # expression 549 1.1 mrg * ::= <expr-primary> # simple expressions 550 1.1 mrg * ::= J <template-arg>* E # argument pack 551 1.1 mrg * 552 1.1 mrg * Reference: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.template-arg 553 1.1 mrg */ 554 1.1 mrg if (TemplateTupleParameter tt = tp.isTemplateTupleParameter()) 555 1.1 mrg { 556 1.1 mrg buf.writeByte('J'); // argument pack 557 1.1 mrg 558 1.1 mrg // mangle the rest of the arguments as types 559 1.1 mrg foreach (j; i .. (*ti.tiargs).dim) 560 1.1 mrg { 561 1.1 mrg Type t = isType((*ti.tiargs)[j]); 562 1.1 mrg assert(t); 563 1.1 mrg t.accept(this); 564 1.1 mrg } 565 1.1 mrg 566 1.1 mrg buf.writeByte('E'); 567 1.1 mrg break; 568 1.1 mrg } 569 1.1 mrg 570 1.1 mrg template_arg(ti, i); 571 1.1 mrg } 572 1.1 mrg buf.writeByte('E'); 573 1.1 mrg return true; 574 1.1 mrg } 575 1.1 mrg 576 1.1 mrg /** 577 1.1 mrg * Write the symbol `p` if not null, then execute the delegate 578 1.1 mrg * 579 1.1 mrg * Params: 580 1.1 mrg * p = Symbol to write 581 1.1 mrg * dg = Delegate to execute 582 1.1 mrg */ 583 1.1 mrg void writeChained(Dsymbol p, scope void delegate() dg) 584 1.1 mrg { 585 1.1 mrg if (p && !p.isModule()) 586 1.1 mrg { 587 1.1 mrg buf.writestring("N"); 588 1.1 mrg source_name(p, true); 589 1.1 mrg dg(); 590 1.1 mrg buf.writestring("E"); 591 1.1 mrg } 592 1.1 mrg else 593 1.1 mrg dg(); 594 1.1 mrg } 595 1.1 mrg 596 1.1 mrg /** 597 1.1 mrg * Write the name of `s` to the buffer 598 1.1 mrg * 599 1.1 mrg * Params: 600 1.1 mrg * s = Symbol to write the name of 601 1.1 mrg * haveNE = Whether `N..E` is already part of the mangling 602 1.1 mrg * Because `Nspace` and `CPPNamespaceAttribute` can be 603 1.1 mrg * mixed, this is a mandatory hack. 604 1.1 mrg */ 605 1.1 mrg void source_name(Dsymbol s, bool haveNE = false) 606 1.1 mrg { 607 1.1 mrg version (none) 608 1.1 mrg { 609 1.1 mrg printf("source_name(%s)\n", s.toChars()); 610 1.1 mrg auto sl = this.buf.peekSlice(); 611 1.1 mrg assert(sl.length == 0 || haveNE || s.cppnamespace is null || sl != "_ZN"); 612 1.1 mrg } 613 1.1 mrg auto ti = s.isTemplateInstance(); 614 1.1 mrg 615 1.1 mrg if (!ti) 616 1.1 mrg { 617 1.1 mrg auto ag = s.isAggregateDeclaration(); 618 1.1 mrg const ident = (ag && ag.mangleOverride) ? ag.mangleOverride.id : s.ident; 619 1.1 mrg this.writeNamespace(s.cppnamespace, () { 620 1.1 mrg this.writeIdentifier(ident); 621 1.1 mrg this.abiTags.writeSymbol(s, this); 622 1.1 mrg }, 623 1.1 mrg haveNE); 624 1.1 mrg return; 625 1.1 mrg } 626 1.1 mrg 627 1.1 mrg bool needsTa = false; 628 1.1 mrg 629 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=20413 630 1.1 mrg // N..E is not needed when substituting members of the std namespace. 631 1.1 mrg // This is observed in the GCC and Clang implementations. 632 1.1 mrg // The Itanium specification is not clear enough on this specific case. 633 1.1 mrg // References: 634 1.1 mrg // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.name 635 1.1 mrg // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression 636 1.1 mrg Dsymbol q = getQualifier(ti.tempdecl); 637 1.1 mrg Dsymbol ns = ti.tempdecl.cppnamespace; 638 1.1 mrg const inStd = ns && isStd(ns) || q && isStd(q); 639 1.1 mrg const isNested = !inStd && (ns || q); 640 1.1 mrg 641 1.1 mrg if (substitute(ti.tempdecl, !haveNE && isNested)) 642 1.1 mrg { 643 1.1 mrg template_args(ti); 644 1.1 mrg if (!haveNE && isNested) 645 1.1 mrg buf.writeByte('E'); 646 1.1 mrg return; 647 1.1 mrg } 648 1.1 mrg else if (this.writeStdSubstitution(ti, needsTa)) 649 1.1 mrg { 650 1.1 mrg this.abiTags.writeSymbol(ti, this); 651 1.1 mrg if (needsTa) 652 1.1 mrg template_args(ti); 653 1.1 mrg return; 654 1.1 mrg } 655 1.1 mrg 656 1.1 mrg auto ag = ti.aliasdecl ? ti.aliasdecl.isAggregateDeclaration() : null; 657 1.1 mrg if (ag && ag.mangleOverride) 658 1.1 mrg { 659 1.1 mrg this.writeNamespace( 660 1.1 mrg ti.toAlias().cppnamespace, () { 661 1.1 mrg this.writeIdentifier(ag.mangleOverride.id); 662 1.1 mrg if (ag.mangleOverride.agg && ag.mangleOverride.agg.isInstantiated()) 663 1.1 mrg { 664 1.1 mrg auto to = ag.mangleOverride.agg.isInstantiated(); 665 1.1 mrg append(to); 666 1.1 mrg this.abiTags.writeSymbol(to.tempdecl, this); 667 1.1 mrg template_args(to); 668 1.1 mrg } 669 1.1 mrg }, haveNE); 670 1.1 mrg } 671 1.1 mrg else 672 1.1 mrg { 673 1.1 mrg this.writeNamespace( 674 1.1 mrg s.cppnamespace, () { 675 1.1 mrg this.writeIdentifier(ti.tempdecl.toAlias().ident); 676 1.1 mrg append(ti.tempdecl); 677 1.1 mrg this.abiTags.writeSymbol(ti.tempdecl, this); 678 1.1 mrg template_args(ti); 679 1.1 mrg }, haveNE); 680 1.1 mrg } 681 1.1 mrg } 682 1.1 mrg 683 1.1 mrg /******** 684 1.1 mrg * See if s is actually an instance of a template 685 1.1 mrg * Params: 686 1.1 mrg * s = symbol 687 1.1 mrg * Returns: 688 1.1 mrg * if s is instance of a template, return the instance, otherwise return s 689 1.1 mrg */ 690 1.1 mrg static Dsymbol getInstance(Dsymbol s) 691 1.1 mrg { 692 1.1 mrg Dsymbol p = s.toParent(); 693 1.1 mrg if (p) 694 1.1 mrg { 695 1.1 mrg if (TemplateInstance ti = p.isTemplateInstance()) 696 1.1 mrg return ti; 697 1.1 mrg } 698 1.1 mrg return s; 699 1.1 mrg } 700 1.1 mrg 701 1.1 mrg /// Get the namespace of a template instance 702 1.1 mrg CPPNamespaceDeclaration getTiNamespace(TemplateInstance ti) 703 1.1 mrg { 704 1.1 mrg // If we receive a pre-semantic `TemplateInstance`, 705 1.1 mrg // `cppnamespace` is always `null` 706 1.1 mrg return ti.tempdecl ? ti.cppnamespace 707 1.1 mrg : this.context.res.asType().toDsymbol(null).cppnamespace; 708 1.1 mrg } 709 1.1 mrg 710 1.1 mrg /******** 711 1.1 mrg * Get qualifier for `s`, meaning the symbol 712 1.1 mrg * that s is in the symbol table of. 713 1.1 mrg * The module does not count as a qualifier, because C++ 714 1.1 mrg * does not have modules. 715 1.1 mrg * Params: 716 1.1 mrg * s = symbol that may have a qualifier 717 1.1 mrg * s is rewritten to be TemplateInstance if s is one 718 1.1 mrg * Returns: 719 1.1 mrg * qualifier, null if none 720 1.1 mrg */ 721 1.1 mrg static Dsymbol getQualifier(Dsymbol s) 722 1.1 mrg { 723 1.1 mrg Dsymbol p = s.toParent(); 724 1.1 mrg return (p && !p.isModule()) ? p : null; 725 1.1 mrg } 726 1.1 mrg 727 1.1 mrg // Detect type char 728 1.1 mrg static bool isChar(RootObject o) 729 1.1 mrg { 730 1.1 mrg Type t = isType(o); 731 1.1 mrg return (t && t.equals(Type.tchar)); 732 1.1 mrg } 733 1.1 mrg 734 1.1 mrg // Detect type ::std::char_traits<char> 735 1.1 mrg bool isChar_traits_char(RootObject o) 736 1.1 mrg { 737 1.1 mrg return isIdent_char(Id.char_traits, o); 738 1.1 mrg } 739 1.1 mrg 740 1.1 mrg // Detect type ::std::allocator<char> 741 1.1 mrg bool isAllocator_char(RootObject o) 742 1.1 mrg { 743 1.1 mrg return isIdent_char(Id.allocator, o); 744 1.1 mrg } 745 1.1 mrg 746 1.1 mrg // Detect type ::std::ident<char> 747 1.1 mrg bool isIdent_char(Identifier ident, RootObject o) 748 1.1 mrg { 749 1.1 mrg Type t = isType(o); 750 1.1 mrg if (!t || t.ty != Tstruct) 751 1.1 mrg return false; 752 1.1 mrg Dsymbol s = (cast(TypeStruct)t).toDsymbol(null); 753 1.1 mrg if (s.ident != ident) 754 1.1 mrg return false; 755 1.1 mrg Dsymbol p = s.toParent(); 756 1.1 mrg if (!p) 757 1.1 mrg return false; 758 1.1 mrg TemplateInstance ti = p.isTemplateInstance(); 759 1.1 mrg if (!ti) 760 1.1 mrg return false; 761 1.1 mrg Dsymbol q = getQualifier(ti); 762 1.1 mrg const bool inStd = isStd(q) || isStd(this.getTiNamespace(ti)); 763 1.1 mrg return inStd && ti.tiargs.dim == 1 && isChar((*ti.tiargs)[0]); 764 1.1 mrg } 765 1.1 mrg 766 1.1 mrg /*** 767 1.1 mrg * Detect template args <char, ::std::char_traits<char>> 768 1.1 mrg * and write st if found. 769 1.1 mrg * Returns: 770 1.1 mrg * true if found 771 1.1 mrg */ 772 1.1 mrg bool char_std_char_traits_char(TemplateInstance ti, string st) 773 1.1 mrg { 774 1.1 mrg if (ti.tiargs.dim == 2 && 775 1.1 mrg isChar((*ti.tiargs)[0]) && 776 1.1 mrg isChar_traits_char((*ti.tiargs)[1])) 777 1.1 mrg { 778 1.1 mrg buf.writestring(st.ptr); 779 1.1 mrg return true; 780 1.1 mrg } 781 1.1 mrg return false; 782 1.1 mrg } 783 1.1 mrg 784 1.1 mrg 785 1.1 mrg void prefix_name(Dsymbol s) 786 1.1 mrg { 787 1.1 mrg //printf("prefix_name(%s)\n", s.toChars()); 788 1.1 mrg if (substitute(s)) 789 1.1 mrg return; 790 1.1 mrg if (isStd(s)) 791 1.1 mrg return buf.writestring("St"); 792 1.1 mrg 793 1.1 mrg auto si = getInstance(s); 794 1.1 mrg Dsymbol p = getQualifier(si); 795 1.1 mrg if (p) 796 1.1 mrg { 797 1.1 mrg if (isStd(p)) 798 1.1 mrg { 799 1.1 mrg bool needsTa; 800 1.1 mrg auto ti = si.isTemplateInstance(); 801 1.1 mrg if (this.writeStdSubstitution(ti, needsTa)) 802 1.1 mrg { 803 1.1 mrg this.abiTags.writeSymbol(ti, this); 804 1.1 mrg if (needsTa) 805 1.1 mrg { 806 1.1 mrg template_args(ti); 807 1.1 mrg append(ti); 808 1.1 mrg } 809 1.1 mrg return; 810 1.1 mrg } 811 1.1 mrg buf.writestring("St"); 812 1.1 mrg } 813 1.1 mrg else 814 1.1 mrg prefix_name(p); 815 1.1 mrg } 816 1.1 mrg source_name(si, true); 817 1.1 mrg if (!isStd(si)) 818 1.1 mrg /* Do this after the source_name() call to keep components[] 819 1.1 mrg * in the right order. 820 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=17947 821 1.1 mrg */ 822 1.1 mrg append(si); 823 1.1 mrg } 824 1.1 mrg 825 1.1 mrg /** 826 1.1 mrg * Write common substitution for standard types, such as std::allocator 827 1.1 mrg * 828 1.1 mrg * This function assumes that the symbol `ti` is in the namespace `std`. 829 1.1 mrg * 830 1.1 mrg * Params: 831 1.1 mrg * ti = Template instance to consider 832 1.1 mrg * needsTa = If this function returns `true`, this value indicates 833 1.1 mrg * if additional template argument mangling is needed 834 1.1 mrg * 835 1.1 mrg * Returns: 836 1.1 mrg * `true` if a special std symbol was found 837 1.1 mrg */ 838 1.1 mrg bool writeStdSubstitution(TemplateInstance ti, out bool needsTa) 839 1.1 mrg { 840 1.1 mrg if (!ti) 841 1.1 mrg return false; 842 1.1 mrg if (!isStd(this.getTiNamespace(ti)) && !isStd(getQualifier(ti))) 843 1.1 mrg return false; 844 1.1 mrg 845 1.1 mrg if (ti.name == Id.allocator) 846 1.1 mrg { 847 1.1 mrg buf.writestring("Sa"); 848 1.1 mrg needsTa = true; 849 1.1 mrg return true; 850 1.1 mrg } 851 1.1 mrg if (ti.name == Id.basic_string) 852 1.1 mrg { 853 1.1 mrg // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>> 854 1.1 mrg if (ti.tiargs.dim == 3 && 855 1.1 mrg isChar((*ti.tiargs)[0]) && 856 1.1 mrg isChar_traits_char((*ti.tiargs)[1]) && 857 1.1 mrg isAllocator_char((*ti.tiargs)[2])) 858 1.1 mrg 859 1.1 mrg { 860 1.1 mrg buf.writestring("Ss"); 861 1.1 mrg return true; 862 1.1 mrg } 863 1.1 mrg buf.writestring("Sb"); // ::std::basic_string 864 1.1 mrg needsTa = true; 865 1.1 mrg return true; 866 1.1 mrg } 867 1.1 mrg 868 1.1 mrg // ::std::basic_istream<char, ::std::char_traits<char>> 869 1.1 mrg if (ti.name == Id.basic_istream && 870 1.1 mrg char_std_char_traits_char(ti, "Si")) 871 1.1 mrg return true; 872 1.1 mrg 873 1.1 mrg // ::std::basic_ostream<char, ::std::char_traits<char>> 874 1.1 mrg if (ti.name == Id.basic_ostream && 875 1.1 mrg char_std_char_traits_char(ti, "So")) 876 1.1 mrg return true; 877 1.1 mrg 878 1.1 mrg // ::std::basic_iostream<char, ::std::char_traits<char>> 879 1.1 mrg if (ti.name == Id.basic_iostream && 880 1.1 mrg char_std_char_traits_char(ti, "Sd")) 881 1.1 mrg return true; 882 1.1 mrg 883 1.1 mrg return false; 884 1.1 mrg } 885 1.1 mrg 886 1.1 mrg void cpp_mangle_name(Dsymbol s, bool qualified) 887 1.1 mrg { 888 1.1 mrg //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); 889 1.1 mrg Dsymbol p = s.toParent(); 890 1.1 mrg Dsymbol se = s; 891 1.1 mrg bool write_prefix = true; 892 1.1 mrg if (p && p.isTemplateInstance()) 893 1.1 mrg { 894 1.1 mrg se = p; 895 1.1 mrg if (find(p.isTemplateInstance().tempdecl) >= 0) 896 1.1 mrg write_prefix = false; 897 1.1 mrg p = p.toParent(); 898 1.1 mrg } 899 1.1 mrg if (!p || p.isModule()) 900 1.1 mrg { 901 1.1 mrg source_name(se, false); 902 1.1 mrg append(s); 903 1.1 mrg return; 904 1.1 mrg } 905 1.1 mrg 906 1.1 mrg if (!isStd(p) || qualified) 907 1.1 mrg { 908 1.1 mrg buf.writeByte('N'); 909 1.1 mrg if (write_prefix) 910 1.1 mrg { 911 1.1 mrg if (isStd(p)) 912 1.1 mrg buf.writestring("St"); 913 1.1 mrg else 914 1.1 mrg prefix_name(p); 915 1.1 mrg } 916 1.1 mrg source_name(se, true); 917 1.1 mrg buf.writeByte('E'); 918 1.1 mrg append(s); 919 1.1 mrg return; 920 1.1 mrg } 921 1.1 mrg /* The N..E is not required if: 922 1.1 mrg * 1. the parent is 'std' 923 1.1 mrg * 2. 'std' is the initial qualifier 924 1.1 mrg * 3. there is no CV-qualifier or a ref-qualifier for a member function 925 1.1 mrg * ABI 5.1.8 926 1.1 mrg */ 927 1.1 mrg TemplateInstance ti = se.isTemplateInstance(); 928 1.1 mrg if (s.ident == Id.allocator) 929 1.1 mrg { 930 1.1 mrg buf.writestring("Sa"); // "Sa" is short for ::std::allocator 931 1.1 mrg template_args(ti); 932 1.1 mrg } 933 1.1 mrg else if (s.ident == Id.basic_string) 934 1.1 mrg { 935 1.1 mrg // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>> 936 1.1 mrg if (ti.tiargs.dim == 3 && 937 1.1 mrg isChar((*ti.tiargs)[0]) && 938 1.1 mrg isChar_traits_char((*ti.tiargs)[1]) && 939 1.1 mrg isAllocator_char((*ti.tiargs)[2])) 940 1.1 mrg { 941 1.1 mrg buf.writestring("Ss"); 942 1.1 mrg return; 943 1.1 mrg } 944 1.1 mrg buf.writestring("Sb"); // ::std::basic_string 945 1.1 mrg template_args(ti); 946 1.1 mrg } 947 1.1 mrg else 948 1.1 mrg { 949 1.1 mrg // ::std::basic_istream<char, ::std::char_traits<char>> 950 1.1 mrg if (s.ident == Id.basic_istream) 951 1.1 mrg { 952 1.1 mrg if (char_std_char_traits_char(ti, "Si")) 953 1.1 mrg return; 954 1.1 mrg } 955 1.1 mrg else if (s.ident == Id.basic_ostream) 956 1.1 mrg { 957 1.1 mrg if (char_std_char_traits_char(ti, "So")) 958 1.1 mrg return; 959 1.1 mrg } 960 1.1 mrg else if (s.ident == Id.basic_iostream) 961 1.1 mrg { 962 1.1 mrg if (char_std_char_traits_char(ti, "Sd")) 963 1.1 mrg return; 964 1.1 mrg } 965 1.1 mrg buf.writestring("St"); 966 1.1 mrg source_name(se, true); 967 1.1 mrg } 968 1.1 mrg append(s); 969 1.1 mrg } 970 1.1 mrg 971 1.1 mrg /** 972 1.1 mrg * Write CV-qualifiers to the buffer 973 1.1 mrg * 974 1.1 mrg * CV-qualifiers are 'r': restrict (unused in D), 'V': volatile, 'K': const 975 1.1 mrg * 976 1.1 mrg * See_Also: 977 1.1 mrg * https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.CV-qualifiers 978 1.1 mrg */ 979 1.1 mrg void CV_qualifiers(const Type t) 980 1.1 mrg { 981 1.1 mrg if (t.isConst()) 982 1.1 mrg buf.writeByte('K'); 983 1.1 mrg } 984 1.1 mrg 985 1.1 mrg /** 986 1.1 mrg * Mangles a variable 987 1.1 mrg * 988 1.1 mrg * Params: 989 1.1 mrg * d = Variable declaration to mangle 990 1.1 mrg * isNested = Whether this variable is nested, e.g. a template parameter 991 1.1 mrg * or within a namespace 992 1.1 mrg */ 993 1.1 mrg void mangle_variable(VarDeclaration d, bool isNested) 994 1.1 mrg { 995 1.1 mrg // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 996 1.1 mrg if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared))) 997 1.1 mrg { 998 1.1 mrg d.error("Internal Compiler Error: C++ static non-`__gshared` non-`extern` variables not supported"); 999 1.1 mrg fatal(); 1000 1.1 mrg } 1001 1.1 mrg Dsymbol p = d.toParent(); 1002 1.1 mrg if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" 1003 1.1 mrg { 1004 1.1 mrg buf.writestring("_ZN"); 1005 1.1 mrg prefix_name(p); 1006 1.1 mrg source_name(d, true); 1007 1.1 mrg buf.writeByte('E'); 1008 1.1 mrg } 1009 1.1 mrg else if (isNested) 1010 1.1 mrg { 1011 1.1 mrg buf.writestring("_Z"); 1012 1.1 mrg source_name(d, false); 1013 1.1 mrg } 1014 1.1 mrg else 1015 1.1 mrg { 1016 1.1 mrg if (auto varTags = ABITagContainer.forSymbol(d)) 1017 1.1 mrg { 1018 1.1 mrg buf.writestring("_Z"); 1019 1.1 mrg source_name(d, false); 1020 1.1 mrg return; 1021 1.1 mrg } 1022 1.1 mrg if (auto typeTags = ABITagContainer.forSymbol(d.type.toDsymbol(null))) 1023 1.1 mrg { 1024 1.1 mrg buf.writestring("_Z"); 1025 1.1 mrg source_name(d, false); 1026 1.1 mrg this.abiTags.write(*this.buf, typeTags); 1027 1.1 mrg return; 1028 1.1 mrg } 1029 1.1 mrg //char beta[6] should mangle as "beta" 1030 1.1 mrg buf.writestring(d.ident.toString()); 1031 1.1 mrg } 1032 1.1 mrg } 1033 1.1 mrg 1034 1.1 mrg void mangle_function(FuncDeclaration d) 1035 1.1 mrg { 1036 1.1 mrg //printf("mangle_function(%s)\n", d.toChars()); 1037 1.1 mrg /* 1038 1.1 mrg * <mangled-name> ::= _Z <encoding> 1039 1.1 mrg */ 1040 1.1 mrg buf.writestring("_Z"); 1041 1.1 mrg this.mangle_function_encoding(d); 1042 1.1 mrg } 1043 1.1 mrg 1044 1.1 mrg void mangle_function_encoding(FuncDeclaration d) 1045 1.1 mrg { 1046 1.1 mrg //printf("mangle_function_encoding(%s)\n", d.toChars()); 1047 1.1 mrg /* 1048 1.1 mrg * <encoding> ::= <function name> <bare-function-type> 1049 1.1 mrg * ::= <data name> 1050 1.1 mrg * ::= <special-name> 1051 1.1 mrg */ 1052 1.1 mrg TypeFunction tf = cast(TypeFunction)d.type; 1053 1.1 mrg 1054 1.1 mrg if (TemplateDeclaration ftd = getFuncTemplateDecl(d)) 1055 1.1 mrg { 1056 1.1 mrg /* It's an instance of a function template 1057 1.1 mrg */ 1058 1.1 mrg TemplateInstance ti = d.parent.isTemplateInstance(); 1059 1.1 mrg assert(ti); 1060 1.1 mrg this.mangleTemplatedFunction(d, tf, ftd, ti); 1061 1.1 mrg return; 1062 1.1 mrg } 1063 1.1 mrg 1064 1.1 mrg Dsymbol p = d.toParent(); 1065 1.1 mrg if (p && !p.isModule() && tf.linkage == LINK.cpp) 1066 1.1 mrg { 1067 1.1 mrg this.mangleNestedFuncPrefix(tf, p); 1068 1.1 mrg 1069 1.1 mrg if (auto ctor = d.isCtorDeclaration()) 1070 1.1 mrg buf.writestring(ctor.isCpCtor ? "C2" : "C1"); 1071 1.1 mrg else if (d.isAggregateDtor()) 1072 1.1 mrg buf.writestring("D1"); 1073 1.1 mrg else if (d.ident && d.ident == Id.assign) 1074 1.1 mrg buf.writestring("aS"); 1075 1.1 mrg else if (d.ident && d.ident == Id.eq) 1076 1.1 mrg buf.writestring("eq"); 1077 1.1 mrg else if (d.ident && d.ident == Id.index) 1078 1.1 mrg buf.writestring("ix"); 1079 1.1 mrg else if (d.ident && d.ident == Id.call) 1080 1.1 mrg buf.writestring("cl"); 1081 1.1 mrg else 1082 1.1 mrg source_name(d, true); 1083 1.1 mrg buf.writeByte('E'); 1084 1.1 mrg } 1085 1.1 mrg else 1086 1.1 mrg { 1087 1.1 mrg source_name(d, false); 1088 1.1 mrg } 1089 1.1 mrg 1090 1.1 mrg // Save offset for potentially writing tags 1091 1.1 mrg const size_t off = this.buf.length(); 1092 1.1 mrg 1093 1.1 mrg // Template args accept extern "C" symbols with special mangling 1094 1.1 mrg if (tf.linkage == LINK.cpp) 1095 1.1 mrg mangleFunctionParameters(tf.parameterList); 1096 1.1 mrg 1097 1.1 mrg if (!tf.next.isTypeBasic()) 1098 1.1 mrg this.writeRemainingTags(off, tf); 1099 1.1 mrg } 1100 1.1 mrg 1101 1.1 mrg /** 1102 1.1 mrg * Recursively mangles a non-scoped namespace 1103 1.1 mrg * 1104 1.1 mrg * Parameters: 1105 1.1 mrg * ns = Namespace to mangle 1106 1.1 mrg * dg = A delegate to write the identifier in this namespace 1107 1.1 mrg * haveNE = When `false` (the default), surround the namespace / dg 1108 1.1 mrg * call with nested name qualifier (`N..E`). 1109 1.1 mrg * Otherwise, they are already present (e.g. `Nspace` was used). 1110 1.1 mrg */ 1111 1.1 mrg void writeNamespace(CPPNamespaceDeclaration ns, scope void delegate() dg, 1112 1.1 mrg bool haveNE = false) 1113 1.1 mrg { 1114 1.1 mrg void runDg () { if (dg !is null) dg(); } 1115 1.1 mrg 1116 1.1 mrg if (ns is null || ns.ident is null) 1117 1.1 mrg return runDg(); 1118 1.1 mrg 1119 1.1 mrg if (isStd(ns)) 1120 1.1 mrg { 1121 1.1 mrg if (!substitute(ns)) 1122 1.1 mrg buf.writestring("St"); 1123 1.1 mrg runDg(); 1124 1.1 mrg } 1125 1.1 mrg else if (dg !is null) 1126 1.1 mrg { 1127 1.1 mrg if (!haveNE) 1128 1.1 mrg buf.writestring("N"); 1129 1.1 mrg if (!substitute(ns)) 1130 1.1 mrg { 1131 1.1 mrg this.writeNamespace(ns.cppnamespace, null); 1132 1.1 mrg this.writeIdentifier(ns.ident); 1133 1.1 mrg append(ns); 1134 1.1 mrg } 1135 1.1 mrg dg(); 1136 1.1 mrg if (!haveNE) 1137 1.1 mrg buf.writestring("E"); 1138 1.1 mrg } 1139 1.1 mrg else if (!substitute(ns)) 1140 1.1 mrg { 1141 1.1 mrg this.writeNamespace(ns.cppnamespace, null); 1142 1.1 mrg this.writeIdentifier(ns.ident); 1143 1.1 mrg append(ns); 1144 1.1 mrg } 1145 1.1 mrg } 1146 1.1 mrg 1147 1.1 mrg /** 1148 1.1 mrg * Mangles a function template to C++ 1149 1.1 mrg * 1150 1.1 mrg * Params: 1151 1.1 mrg * d = Function declaration 1152 1.1 mrg * tf = Function type (casted d.type) 1153 1.1 mrg * ftd = Template declaration (ti.templdecl) 1154 1.1 mrg * ti = Template instance (d.parent) 1155 1.1 mrg */ 1156 1.1 mrg void mangleTemplatedFunction(FuncDeclaration d, TypeFunction tf, 1157 1.1 mrg TemplateDeclaration ftd, TemplateInstance ti) 1158 1.1 mrg { 1159 1.1 mrg Dsymbol p = ti.toParent(); 1160 1.1 mrg // Check if this function is *not* nested 1161 1.1 mrg if (!p || p.isModule() || tf.linkage != LINK.cpp) 1162 1.1 mrg { 1163 1.1 mrg this.context.ti = ti; 1164 1.1 mrg this.context.fd = d; 1165 1.1 mrg this.context.res = d; 1166 1.1 mrg TypeFunction preSemantic = cast(TypeFunction)d.originalType; 1167 1.1 mrg auto nspace = ti.toParent(); 1168 1.1 mrg if (nspace && nspace.isNspace()) 1169 1.1 mrg this.writeChained(ti.toParent(), () => source_name(ti, true)); 1170 1.1 mrg else 1171 1.1 mrg source_name(ti, false); 1172 1.1 mrg this.mangleReturnType(preSemantic); 1173 1.1 mrg this.mangleFunctionParameters(ParameterList(preSemantic.parameterList.parameters, tf.parameterList.varargs)); 1174 1.1 mrg return; 1175 1.1 mrg } 1176 1.1 mrg 1177 1.1 mrg // It's a nested function (e.g. a member of an aggregate) 1178 1.1 mrg this.mangleNestedFuncPrefix(tf, p); 1179 1.1 mrg 1180 1.1 mrg if (d.isCtorDeclaration()) 1181 1.1 mrg { 1182 1.1 mrg buf.writestring("C1"); 1183 1.1 mrg mangleFunctionParameters(tf.parameterList); 1184 1.1 mrg return; 1185 1.1 mrg } 1186 1.1 mrg else if (d.isAggregateDtor()) 1187 1.1 mrg { 1188 1.1 mrg buf.writestring("D1"); 1189 1.1 mrg mangleFunctionParameters(tf.parameterList); 1190 1.1 mrg return; 1191 1.1 mrg } 1192 1.1 mrg 1193 1.1 mrg int firstTemplateArg = 0; 1194 1.1 mrg bool appendReturnType = true; 1195 1.1 mrg bool isConvertFunc = false; 1196 1.1 mrg string symName; 1197 1.1 mrg 1198 1.1 mrg // test for special symbols 1199 1.1 mrg CppOperator whichOp = isCppOperator(ti.name); 1200 1.1 mrg final switch (whichOp) 1201 1.1 mrg { 1202 1.1 mrg case CppOperator.Unknown: 1203 1.1 mrg break; 1204 1.1 mrg case CppOperator.Cast: 1205 1.1 mrg symName = "cv"; 1206 1.1 mrg firstTemplateArg = 1; 1207 1.1 mrg isConvertFunc = true; 1208 1.1 mrg appendReturnType = false; 1209 1.1 mrg break; 1210 1.1 mrg case CppOperator.Assign: 1211 1.1 mrg symName = "aS"; 1212 1.1 mrg break; 1213 1.1 mrg case CppOperator.Eq: 1214 1.1 mrg symName = "eq"; 1215 1.1 mrg break; 1216 1.1 mrg case CppOperator.Index: 1217 1.1 mrg symName = "ix"; 1218 1.1 mrg break; 1219 1.1 mrg case CppOperator.Call: 1220 1.1 mrg symName = "cl"; 1221 1.1 mrg break; 1222 1.1 mrg case CppOperator.Unary: 1223 1.1 mrg case CppOperator.Binary: 1224 1.1 mrg case CppOperator.OpAssign: 1225 1.1 mrg TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); 1226 1.1 mrg assert(td); 1227 1.1 mrg assert(ti.tiargs.dim >= 1); 1228 1.1 mrg TemplateParameter tp = (*td.parameters)[0]; 1229 1.1 mrg TemplateValueParameter tv = tp.isTemplateValueParameter(); 1230 1.1 mrg if (!tv || !tv.valType.isString()) 1231 1.1 mrg break; // expecting a string argument to operators! 1232 1.1 mrg Expression exp = (*ti.tiargs)[0].isExpression(); 1233 1.1 mrg StringExp str = exp.toStringExp(); 1234 1.1 mrg switch (whichOp) 1235 1.1 mrg { 1236 1.1 mrg case CppOperator.Unary: 1237 1.1 mrg switch (str.peekString()) 1238 1.1 mrg { 1239 1.1 mrg case "*": symName = "de"; goto continue_template; 1240 1.1 mrg case "++": symName = "pp"; goto continue_template; 1241 1.1 mrg case "--": symName = "mm"; goto continue_template; 1242 1.1 mrg case "-": symName = "ng"; goto continue_template; 1243 1.1 mrg case "+": symName = "ps"; goto continue_template; 1244 1.1 mrg case "~": symName = "co"; goto continue_template; 1245 1.1 mrg default: break; 1246 1.1 mrg } 1247 1.1 mrg break; 1248 1.1 mrg case CppOperator.Binary: 1249 1.1 mrg switch (str.peekString()) 1250 1.1 mrg { 1251 1.1 mrg case ">>": symName = "rs"; goto continue_template; 1252 1.1 mrg case "<<": symName = "ls"; goto continue_template; 1253 1.1 mrg case "*": symName = "ml"; goto continue_template; 1254 1.1 mrg case "-": symName = "mi"; goto continue_template; 1255 1.1 mrg case "+": symName = "pl"; goto continue_template; 1256 1.1 mrg case "&": symName = "an"; goto continue_template; 1257 1.1 mrg case "/": symName = "dv"; goto continue_template; 1258 1.1 mrg case "%": symName = "rm"; goto continue_template; 1259 1.1 mrg case "^": symName = "eo"; goto continue_template; 1260 1.1 mrg case "|": symName = "or"; goto continue_template; 1261 1.1 mrg default: break; 1262 1.1 mrg } 1263 1.1 mrg break; 1264 1.1 mrg case CppOperator.OpAssign: 1265 1.1 mrg switch (str.peekString()) 1266 1.1 mrg { 1267 1.1 mrg case "*": symName = "mL"; goto continue_template; 1268 1.1 mrg case "+": symName = "pL"; goto continue_template; 1269 1.1 mrg case "-": symName = "mI"; goto continue_template; 1270 1.1 mrg case "/": symName = "dV"; goto continue_template; 1271 1.1 mrg case "%": symName = "rM"; goto continue_template; 1272 1.1 mrg case ">>": symName = "rS"; goto continue_template; 1273 1.1 mrg case "<<": symName = "lS"; goto continue_template; 1274 1.1 mrg case "&": symName = "aN"; goto continue_template; 1275 1.1 mrg case "|": symName = "oR"; goto continue_template; 1276 1.1 mrg case "^": symName = "eO"; goto continue_template; 1277 1.1 mrg default: break; 1278 1.1 mrg } 1279 1.1 mrg break; 1280 1.1 mrg default: 1281 1.1 mrg assert(0); 1282 1.1 mrg continue_template: 1283 1.1 mrg firstTemplateArg = 1; 1284 1.1 mrg break; 1285 1.1 mrg } 1286 1.1 mrg break; 1287 1.1 mrg } 1288 1.1 mrg if (symName.length == 0) 1289 1.1 mrg source_name(ti, true); 1290 1.1 mrg else 1291 1.1 mrg { 1292 1.1 mrg buf.writestring(symName); 1293 1.1 mrg if (isConvertFunc) 1294 1.1 mrg template_arg(ti, 0); 1295 1.1 mrg appendReturnType = template_args(ti, firstTemplateArg) && appendReturnType; 1296 1.1 mrg } 1297 1.1 mrg buf.writeByte('E'); 1298 1.1 mrg if (appendReturnType) 1299 1.1 mrg headOfType(tf.nextOf()); // mangle return type 1300 1.1 mrg mangleFunctionParameters(tf.parameterList); 1301 1.1 mrg } 1302 1.1 mrg 1303 1.1 mrg /** 1304 1.1 mrg * Mangle the parameters of a function 1305 1.1 mrg * 1306 1.1 mrg * For templated functions, `context.res` is set to the `FuncDeclaration` 1307 1.1 mrg * 1308 1.1 mrg * Params: 1309 1.1 mrg * parameters = Array of `Parameter` to mangle 1310 1.1 mrg * varargs = if != 0, this function has varargs parameters 1311 1.1 mrg */ 1312 1.1 mrg void mangleFunctionParameters(ParameterList parameterList) 1313 1.1 mrg { 1314 1.1 mrg int numparams = 0; 1315 1.1 mrg 1316 1.1 mrg foreach (n, fparam; parameterList) 1317 1.1 mrg { 1318 1.1 mrg Type t = fparam.type.merge2(); 1319 1.1 mrg if (fparam.isReference()) 1320 1.1 mrg t = t.referenceTo(); 1321 1.1 mrg else if (fparam.storageClass & STC.lazy_) 1322 1.1 mrg { 1323 1.1 mrg // Mangle as delegate 1324 1.1 mrg auto tf = new TypeFunction(ParameterList(), t, LINK.d); 1325 1.1 mrg auto td = new TypeDelegate(tf); 1326 1.1 mrg t = td.merge(); 1327 1.1 mrg } 1328 1.1 mrg else if (Type cpptype = target.cpp.parameterType(t)) 1329 1.1 mrg t = cpptype; 1330 1.1 mrg if (t.ty == Tsarray) 1331 1.1 mrg { 1332 1.1 mrg // Static arrays in D are passed by value; no counterpart in C++ 1333 1.1 mrg .error(loc, "Internal Compiler Error: unable to pass static array `%s` to extern(C++) function, use pointer instead", 1334 1.1 mrg t.toChars()); 1335 1.1 mrg fatal(); 1336 1.1 mrg } 1337 1.1 mrg auto prev = this.context.push({ 1338 1.1 mrg TypeFunction tf; 1339 1.1 mrg if (isDsymbol(this.context.res)) 1340 1.1 mrg tf = cast(TypeFunction)this.context.res.asFuncDecl().type; 1341 1.1 mrg else 1342 1.1 mrg tf = this.context.res.asType().isTypeFunction(); 1343 1.1 mrg assert(tf); 1344 1.1 mrg return (*tf.parameterList.parameters)[n].type; 1345 1.1 mrg }()); 1346 1.1 mrg scope (exit) this.context.pop(prev); 1347 1.1 mrg 1348 1.1 mrg if (this.context.ti && global.params.cplusplus >= CppStdRevision.cpp11) 1349 1.1 mrg handleParamPack(t, this.context.ti.tempdecl.isTemplateDeclaration().parameters); 1350 1.1 mrg 1351 1.1 mrg headOfType(t); 1352 1.1 mrg ++numparams; 1353 1.1 mrg } 1354 1.1 mrg 1355 1.1 mrg if (parameterList.varargs == VarArg.variadic) 1356 1.1 mrg buf.writeByte('z'); 1357 1.1 mrg else if (!numparams) 1358 1.1 mrg buf.writeByte('v'); // encode (void) parameters 1359 1.1 mrg } 1360 1.1 mrg 1361 1.1 mrg /****** The rest is type mangling ************/ 1362 1.1 mrg 1363 1.1 mrg void error(Type t) 1364 1.1 mrg { 1365 1.1 mrg const(char)* p; 1366 1.1 mrg if (t.isImmutable()) 1367 1.1 mrg p = "`immutable` "; 1368 1.1 mrg else if (t.isShared()) 1369 1.1 mrg p = "`shared` "; 1370 1.1 mrg else 1371 1.1 mrg p = ""; 1372 1.1 mrg .error(loc, "Internal Compiler Error: %stype `%s` cannot be mapped to C++\n", p, t.toChars()); 1373 1.1 mrg fatal(); //Fatal, because this error should be handled in frontend 1374 1.1 mrg } 1375 1.1 mrg 1376 1.1 mrg /**************************** 1377 1.1 mrg * Mangle a type, 1378 1.1 mrg * treating it as a Head followed by a Tail. 1379 1.1 mrg * Params: 1380 1.1 mrg * t = Head of a type 1381 1.1 mrg */ 1382 1.1 mrg void headOfType(Type t) 1383 1.1 mrg { 1384 1.1 mrg if (t.ty == Tclass) 1385 1.1 mrg { 1386 1.1 mrg mangleTypeClass(cast(TypeClass)t, true); 1387 1.1 mrg } 1388 1.1 mrg else 1389 1.1 mrg { 1390 1.1 mrg // For value types, strip const/immutable/shared from the head of the type 1391 1.1 mrg auto prev = this.context.push(this.context.res.asType().mutableOf().unSharedOf()); 1392 1.1 mrg scope (exit) this.context.pop(prev); 1393 1.1 mrg t.mutableOf().unSharedOf().accept(this); 1394 1.1 mrg } 1395 1.1 mrg } 1396 1.1 mrg 1397 1.1 mrg /****** 1398 1.1 mrg * Write out 1 or 2 character basic type mangling. 1399 1.1 mrg * Handle const and substitutions. 1400 1.1 mrg * Params: 1401 1.1 mrg * t = type to mangle 1402 1.1 mrg * p = if not 0, then character prefix 1403 1.1 mrg * c = mangling character 1404 1.1 mrg */ 1405 1.1 mrg void writeBasicType(Type t, char p, char c) 1406 1.1 mrg { 1407 1.1 mrg // Only do substitutions for non-fundamental types. 1408 1.1 mrg if (!isFundamentalType(t) || t.isConst()) 1409 1.1 mrg { 1410 1.1 mrg if (substitute(t)) 1411 1.1 mrg return; 1412 1.1 mrg else 1413 1.1 mrg append(t); 1414 1.1 mrg } 1415 1.1 mrg CV_qualifiers(t); 1416 1.1 mrg if (p) 1417 1.1 mrg buf.writeByte(p); 1418 1.1 mrg buf.writeByte(c); 1419 1.1 mrg } 1420 1.1 mrg 1421 1.1 mrg 1422 1.1 mrg /**************** 1423 1.1 mrg * Write structs and enums. 1424 1.1 mrg * Params: 1425 1.1 mrg * t = TypeStruct or TypeEnum 1426 1.1 mrg */ 1427 1.1 mrg void doSymbol(Type t) 1428 1.1 mrg { 1429 1.1 mrg if (substitute(t)) 1430 1.1 mrg return; 1431 1.1 mrg CV_qualifiers(t); 1432 1.1 mrg 1433 1.1 mrg // Handle any target-specific struct types. 1434 1.1 mrg if (auto tm = target.cpp.typeMangle(t)) 1435 1.1 mrg { 1436 1.1 mrg buf.writestring(tm); 1437 1.1 mrg } 1438 1.1 mrg else 1439 1.1 mrg { 1440 1.1 mrg Dsymbol s = t.toDsymbol(null); 1441 1.1 mrg Dsymbol p = s.toParent(); 1442 1.1 mrg if (p && p.isTemplateInstance()) 1443 1.1 mrg { 1444 1.1 mrg /* https://issues.dlang.org/show_bug.cgi?id=17947 1445 1.1 mrg * Substitute the template instance symbol, not the struct/enum symbol 1446 1.1 mrg */ 1447 1.1 mrg if (substitute(p)) 1448 1.1 mrg return; 1449 1.1 mrg } 1450 1.1 mrg if (!substitute(s)) 1451 1.1 mrg cpp_mangle_name(s, false); 1452 1.1 mrg } 1453 1.1 mrg if (t.isConst()) 1454 1.1 mrg append(t); 1455 1.1 mrg } 1456 1.1 mrg 1457 1.1 mrg 1458 1.1 mrg 1459 1.1 mrg /************************ 1460 1.1 mrg * Mangle a class type. 1461 1.1 mrg * If it's the head, treat the initial pointer as a value type. 1462 1.1 mrg * Params: 1463 1.1 mrg * t = class type 1464 1.1 mrg * head = true for head of a type 1465 1.1 mrg */ 1466 1.1 mrg void mangleTypeClass(TypeClass t, bool head) 1467 1.1 mrg { 1468 1.1 mrg if (t.isImmutable() || t.isShared()) 1469 1.1 mrg return error(t); 1470 1.1 mrg 1471 1.1 mrg /* Mangle as a <pointer to><struct> 1472 1.1 mrg */ 1473 1.1 mrg if (substitute(t)) 1474 1.1 mrg return; 1475 1.1 mrg if (!head) 1476 1.1 mrg CV_qualifiers(t); 1477 1.1 mrg buf.writeByte('P'); 1478 1.1 mrg 1479 1.1 mrg CV_qualifiers(t); 1480 1.1 mrg 1481 1.1 mrg { 1482 1.1 mrg Dsymbol s = t.toDsymbol(null); 1483 1.1 mrg Dsymbol p = s.toParent(); 1484 1.1 mrg if (p && p.isTemplateInstance()) 1485 1.1 mrg { 1486 1.1 mrg /* https://issues.dlang.org/show_bug.cgi?id=17947 1487 1.1 mrg * Substitute the template instance symbol, not the class symbol 1488 1.1 mrg */ 1489 1.1 mrg if (substitute(p)) 1490 1.1 mrg return; 1491 1.1 mrg } 1492 1.1 mrg } 1493 1.1 mrg 1494 1.1 mrg if (!substitute(t.sym)) 1495 1.1 mrg { 1496 1.1 mrg cpp_mangle_name(t.sym, false); 1497 1.1 mrg } 1498 1.1 mrg if (t.isConst()) 1499 1.1 mrg append(null); // C++ would have an extra type here 1500 1.1 mrg append(t); 1501 1.1 mrg } 1502 1.1 mrg 1503 1.1 mrg /** 1504 1.1 mrg * Mangle the prefix of a nested (e.g. member) function 1505 1.1 mrg * 1506 1.1 mrg * Params: 1507 1.1 mrg * tf = Type of the nested function 1508 1.1 mrg * parent = Parent in which the function is nested 1509 1.1 mrg */ 1510 1.1 mrg void mangleNestedFuncPrefix(TypeFunction tf, Dsymbol parent) 1511 1.1 mrg { 1512 1.1 mrg /* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E 1513 1.1 mrg * ::= N [<CV-qualifiers>] <template-prefix> <template-args> E 1514 1.1 mrg */ 1515 1.1 mrg buf.writeByte('N'); 1516 1.1 mrg CV_qualifiers(tf); 1517 1.1 mrg 1518 1.1 mrg /* <prefix> ::= <prefix> <unqualified-name> 1519 1.1 mrg * ::= <template-prefix> <template-args> 1520 1.1 mrg * ::= <template-param> 1521 1.1 mrg * ::= # empty 1522 1.1 mrg * ::= <substitution> 1523 1.1 mrg * ::= <prefix> <data-member-prefix> 1524 1.1 mrg */ 1525 1.1 mrg prefix_name(parent); 1526 1.1 mrg } 1527 1.1 mrg 1528 1.1 mrg /** 1529 1.1 mrg * Write `Dp` (C++11 function parameter pack prefix) if 't' is a TemplateSequenceParameter (T...). 1530 1.1 mrg * 1531 1.1 mrg * Params: 1532 1.1 mrg * t = Parameter type 1533 1.1 mrg * params = Template parameters of the function 1534 1.1 mrg */ 1535 1.1 mrg private void handleParamPack(Type t, TemplateParameters* params) 1536 1.1 mrg { 1537 1.1 mrg if (t.isTypeReference()) 1538 1.1 mrg t = t.nextOf(); 1539 1.1 mrg auto ti = t.isTypeIdentifier(); 1540 1.1 mrg if (!ti) 1541 1.1 mrg return; 1542 1.1 mrg 1543 1.1 mrg auto idx = templateParamIndex(ti.ident, params); 1544 1.1 mrg if (idx < params.length && (*params)[idx].isTemplateTupleParameter()) 1545 1.1 mrg buf.writestring("Dp"); 1546 1.1 mrg } 1547 1.1 mrg 1548 1.1 mrg /** 1549 1.1 mrg * Helper function to write a `T..._` template index. 1550 1.1 mrg * 1551 1.1 mrg * Params: 1552 1.1 mrg * idx = Index of `param` in the template argument list 1553 1.1 mrg * param = Template parameter to mangle 1554 1.1 mrg */ 1555 1.1 mrg private void writeTemplateArgIndex(size_t idx, TemplateParameter param) 1556 1.1 mrg { 1557 1.1 mrg // expressions are mangled in <X..E> 1558 1.1 mrg if (param.isTemplateValueParameter()) 1559 1.1 mrg buf.writeByte('X'); 1560 1.1 mrg buf.writeByte('T'); 1561 1.1 mrg writeSequenceFromIndex(idx); 1562 1.1 mrg buf.writeByte('_'); 1563 1.1 mrg if (param.isTemplateValueParameter()) 1564 1.1 mrg buf.writeByte('E'); 1565 1.1 mrg } 1566 1.1 mrg 1567 1.1 mrg /** 1568 1.1 mrg * Given an array of template parameters and an identifier, 1569 1.1 mrg * returns the index of the identifier in that array. 1570 1.1 mrg * 1571 1.1 mrg * Params: 1572 1.1 mrg * ident = Identifier for which substitution is attempted 1573 1.1 mrg * (e.g. `void func(T)(T param)` => `T` from `T param`) 1574 1.1 mrg * params = `TemplateParameters` of the enclosing symbol 1575 1.1 mrg * (in the previous example, `func`'s template parameters) 1576 1.1 mrg * 1577 1.1 mrg * Returns: 1578 1.1 mrg * The index of the identifier match in `params`, 1579 1.1 mrg * or `params.length` if there wasn't any match. 1580 1.1 mrg */ 1581 1.1 mrg private static size_t templateParamIndex( 1582 1.1 mrg const ref Identifier ident, TemplateParameters* params) 1583 1.1 mrg { 1584 1.1 mrg foreach (idx, param; *params) 1585 1.1 mrg if (param.ident == ident) 1586 1.1 mrg return idx; 1587 1.1 mrg return params.length; 1588 1.1 mrg } 1589 1.1 mrg 1590 1.1 mrg /** 1591 1.1 mrg * Given a template instance `t`, write its qualified name 1592 1.1 mrg * without the template parameter list 1593 1.1 mrg * 1594 1.1 mrg * Params: 1595 1.1 mrg * t = Post-parsing `TemplateInstance` pointing to the symbol 1596 1.1 mrg * to mangle (one level deep) 1597 1.1 mrg * dg = Delegate to execute after writing the qualified symbol 1598 1.1 mrg * 1599 1.1 mrg */ 1600 1.1 mrg private void writeQualified(TemplateInstance t, scope void delegate() dg) 1601 1.1 mrg { 1602 1.1 mrg auto type = isType(this.context.res); 1603 1.1 mrg if (!type) 1604 1.1 mrg { 1605 1.1 mrg this.writeIdentifier(t.name); 1606 1.1 mrg return dg(); 1607 1.1 mrg } 1608 1.1 mrg auto sym1 = type.toDsymbol(null); 1609 1.1 mrg if (!sym1) 1610 1.1 mrg { 1611 1.1 mrg this.writeIdentifier(t.name); 1612 1.1 mrg return dg(); 1613 1.1 mrg } 1614 1.1 mrg // Get the template instance 1615 1.1 mrg auto sym = getQualifier(sym1); 1616 1.1 mrg auto sym2 = getQualifier(sym); 1617 1.1 mrg if (sym2 && isStd(sym2)) // Nspace path 1618 1.1 mrg { 1619 1.1 mrg bool unused; 1620 1.1 mrg assert(sym.isTemplateInstance()); 1621 1.1 mrg if (this.writeStdSubstitution(sym.isTemplateInstance(), unused)) 1622 1.1 mrg return dg(); 1623 1.1 mrg // std names don't require `N..E` 1624 1.1 mrg buf.writestring("St"); 1625 1.1 mrg this.writeIdentifier(t.name); 1626 1.1 mrg this.append(t); 1627 1.1 mrg return dg(); 1628 1.1 mrg } 1629 1.1 mrg else if (sym2) 1630 1.1 mrg { 1631 1.1 mrg buf.writestring("N"); 1632 1.1 mrg if (!this.substitute(sym2)) 1633 1.1 mrg sym2.accept(this); 1634 1.1 mrg } 1635 1.1 mrg this.writeNamespace( 1636 1.1 mrg sym1.cppnamespace, () { 1637 1.1 mrg this.writeIdentifier(t.name); 1638 1.1 mrg this.append(t); 1639 1.1 mrg dg(); 1640 1.1 mrg }); 1641 1.1 mrg if (sym2) 1642 1.1 mrg buf.writestring("E"); 1643 1.1 mrg } 1644 1.1 mrg 1645 1.1 mrg extern(C++): 1646 1.1 mrg 1647 1.1 mrg alias visit = Visitor.visit; 1648 1.1 mrg 1649 1.1 mrg override void visit(TypeNull t) 1650 1.1 mrg { 1651 1.1 mrg if (t.isImmutable() || t.isShared()) 1652 1.1 mrg return error(t); 1653 1.1 mrg 1654 1.1 mrg writeBasicType(t, 'D', 'n'); 1655 1.1 mrg } 1656 1.1 mrg 1657 1.1 mrg override void visit(TypeNoreturn t) 1658 1.1 mrg { 1659 1.1 mrg if (t.isImmutable() || t.isShared()) 1660 1.1 mrg return error(t); 1661 1.1 mrg 1662 1.1 mrg writeBasicType(t, 0, 'v'); // mangle like `void` 1663 1.1 mrg } 1664 1.1 mrg 1665 1.1 mrg override void visit(TypeBasic t) 1666 1.1 mrg { 1667 1.1 mrg if (t.isImmutable() || t.isShared()) 1668 1.1 mrg return error(t); 1669 1.1 mrg 1670 1.1 mrg // Handle any target-specific basic types. 1671 1.1 mrg if (auto tm = target.cpp.typeMangle(t)) 1672 1.1 mrg { 1673 1.1 mrg // Only do substitutions for non-fundamental types. 1674 1.1 mrg if (!isFundamentalType(t) || t.isConst()) 1675 1.1 mrg { 1676 1.1 mrg if (substitute(t)) 1677 1.1 mrg return; 1678 1.1 mrg else 1679 1.1 mrg append(t); 1680 1.1 mrg } 1681 1.1 mrg CV_qualifiers(t); 1682 1.1 mrg buf.writestring(tm); 1683 1.1 mrg return; 1684 1.1 mrg } 1685 1.1 mrg 1686 1.1 mrg /* <builtin-type>: 1687 1.1 mrg * v void 1688 1.1 mrg * w wchar_t 1689 1.1 mrg * b bool 1690 1.1 mrg * c char 1691 1.1 mrg * a signed char 1692 1.1 mrg * h unsigned char 1693 1.1 mrg * s short 1694 1.1 mrg * t unsigned short 1695 1.1 mrg * i int 1696 1.1 mrg * j unsigned int 1697 1.1 mrg * l long 1698 1.1 mrg * m unsigned long 1699 1.1 mrg * x long long, __int64 1700 1.1 mrg * y unsigned long long, __int64 1701 1.1 mrg * n __int128 1702 1.1 mrg * o unsigned __int128 1703 1.1 mrg * f float 1704 1.1 mrg * d double 1705 1.1 mrg * e long double, __float80 1706 1.1 mrg * g __float128 1707 1.1 mrg * z ellipsis 1708 1.1 mrg * Dd 64 bit IEEE 754r decimal floating point 1709 1.1 mrg * De 128 bit IEEE 754r decimal floating point 1710 1.1 mrg * Df 32 bit IEEE 754r decimal floating point 1711 1.1 mrg * Dh 16 bit IEEE 754r half-precision floating point 1712 1.1 mrg * Di char32_t 1713 1.1 mrg * Ds char16_t 1714 1.1 mrg * u <source-name> # vendor extended type 1715 1.1 mrg */ 1716 1.1 mrg if (t.isimaginary() || t.iscomplex()) 1717 1.1 mrg { 1718 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=22806 1719 1.1 mrg // Complex and imaginary types are represented in the same way as 1720 1.1 mrg // arrays or vectors in C++. First substitute the outer type, then 1721 1.1 mrg // write out the mangle string of the underlying type. 1722 1.1 mrg if (substitute(t)) 1723 1.1 mrg return; 1724 1.1 mrg append(t); 1725 1.1 mrg CV_qualifiers(t); 1726 1.1 mrg 1727 1.1 mrg if (t.isimaginary()) 1728 1.1 mrg buf.writeByte('G'); // 'G' means imaginary 1729 1.1 mrg else 1730 1.1 mrg buf.writeByte('C'); // 'C' means complex 1731 1.1 mrg 1732 1.1 mrg switch (t.ty) 1733 1.1 mrg { 1734 1.1 mrg case Timaginary32: 1735 1.1 mrg case Tcomplex32: 1736 1.1 mrg return Type.tfloat32.accept(this); 1737 1.1 mrg case Timaginary64: 1738 1.1 mrg case Tcomplex64: 1739 1.1 mrg return Type.tfloat64.accept(this); 1740 1.1 mrg case Timaginary80: 1741 1.1 mrg case Tcomplex80: 1742 1.1 mrg return Type.tfloat80.accept(this); 1743 1.1 mrg default: 1744 1.1 mrg assert(0); 1745 1.1 mrg } 1746 1.1 mrg } 1747 1.1 mrg 1748 1.1 mrg char c; 1749 1.1 mrg char p = 0; 1750 1.1 mrg switch (t.ty) 1751 1.1 mrg { 1752 1.1 mrg case Tvoid: c = 'v'; break; 1753 1.1 mrg case Tint8: c = 'a'; break; 1754 1.1 mrg case Tuns8: c = 'h'; break; 1755 1.1 mrg case Tint16: c = 's'; break; 1756 1.1 mrg case Tuns16: c = 't'; break; 1757 1.1 mrg case Tint32: c = 'i'; break; 1758 1.1 mrg case Tuns32: c = 'j'; break; 1759 1.1 mrg case Tfloat32: c = 'f'; break; 1760 1.1 mrg case Tint64: 1761 1.1 mrg c = target.c.longsize == 8 ? 'l' : 'x'; 1762 1.1 mrg break; 1763 1.1 mrg case Tuns64: 1764 1.1 mrg c = target.c.longsize == 8 ? 'm' : 'y'; 1765 1.1 mrg break; 1766 1.1 mrg case Tint128: c = 'n'; break; 1767 1.1 mrg case Tuns128: c = 'o'; break; 1768 1.1 mrg case Tfloat64: c = 'd'; break; 1769 1.1 mrg case Tfloat80: c = 'e'; break; 1770 1.1 mrg case Tbool: c = 'b'; break; 1771 1.1 mrg case Tchar: c = 'c'; break; 1772 1.1 mrg case Twchar: p = 'D'; c = 's'; break; // since C++11 1773 1.1 mrg case Tdchar: p = 'D'; c = 'i'; break; // since C++11 1774 1.1 mrg 1775 1.1 mrg default: 1776 1.1 mrg return error(t); 1777 1.1 mrg } 1778 1.1 mrg writeBasicType(t, p, c); 1779 1.1 mrg } 1780 1.1 mrg 1781 1.1 mrg override void visit(TypeVector t) 1782 1.1 mrg { 1783 1.1 mrg if (t.isImmutable() || t.isShared()) 1784 1.1 mrg return error(t); 1785 1.1 mrg 1786 1.1 mrg if (substitute(t)) 1787 1.1 mrg return; 1788 1.1 mrg append(t); 1789 1.1 mrg CV_qualifiers(t); 1790 1.1 mrg 1791 1.1 mrg // Handle any target-specific vector types. 1792 1.1 mrg if (auto tm = target.cpp.typeMangle(t)) 1793 1.1 mrg { 1794 1.1 mrg buf.writestring(tm); 1795 1.1 mrg } 1796 1.1 mrg else 1797 1.1 mrg { 1798 1.1 mrg assert(t.basetype && t.basetype.ty == Tsarray); 1799 1.1 mrg auto tsa = t.basetype.isTypeSArray(); 1800 1.1 mrg assert(tsa.dim); 1801 1.1 mrg buf.writestring("Dv"); // -- Gnu ABI v.4 1802 1.1 mrg buf.print(tsa.dim.toInteger()); 1803 1.1 mrg buf.writeByte('_'); 1804 1.1 mrg t.basetype.nextOf().accept(this); 1805 1.1 mrg } 1806 1.1 mrg } 1807 1.1 mrg 1808 1.1 mrg override void visit(TypeSArray t) 1809 1.1 mrg { 1810 1.1 mrg if (t.isImmutable() || t.isShared()) 1811 1.1 mrg return error(t); 1812 1.1 mrg 1813 1.1 mrg if (!substitute(t)) 1814 1.1 mrg append(t); 1815 1.1 mrg CV_qualifiers(t); 1816 1.1 mrg buf.writeByte('A'); 1817 1.1 mrg buf.print(t.dim ? t.dim.toInteger() : 0); 1818 1.1 mrg buf.writeByte('_'); 1819 1.1 mrg t.next.accept(this); 1820 1.1 mrg } 1821 1.1 mrg 1822 1.1 mrg override void visit(TypePointer t) 1823 1.1 mrg { 1824 1.1 mrg if (t.isImmutable() || t.isShared()) 1825 1.1 mrg return error(t); 1826 1.1 mrg 1827 1.1 mrg // Check for const - Since we cannot represent C++'s `char* const`, 1828 1.1 mrg // and `const char* const` (a.k.a `const(char*)` in D) is mangled 1829 1.1 mrg // the same as `const char*` (`const(char)*` in D), we need to add 1830 1.1 mrg // an extra `K` if `nextOf()` is `const`, before substitution 1831 1.1 mrg CV_qualifiers(t); 1832 1.1 mrg if (substitute(t)) 1833 1.1 mrg return; 1834 1.1 mrg buf.writeByte('P'); 1835 1.1 mrg auto prev = this.context.push(this.context.res.asType().nextOf()); 1836 1.1 mrg scope (exit) this.context.pop(prev); 1837 1.1 mrg t.next.accept(this); 1838 1.1 mrg append(t); 1839 1.1 mrg } 1840 1.1 mrg 1841 1.1 mrg override void visit(TypeReference t) 1842 1.1 mrg { 1843 1.1 mrg if (substitute(t)) 1844 1.1 mrg return; 1845 1.1 mrg buf.writeByte('R'); 1846 1.1 mrg CV_qualifiers(t.nextOf()); 1847 1.1 mrg headOfType(t.nextOf()); 1848 1.1 mrg if (t.nextOf().isConst()) 1849 1.1 mrg append(t.nextOf()); 1850 1.1 mrg append(t); 1851 1.1 mrg } 1852 1.1 mrg 1853 1.1 mrg override void visit(TypeFunction t) 1854 1.1 mrg { 1855 1.1 mrg /* 1856 1.1 mrg * <function-type> ::= F [Y] <bare-function-type> E 1857 1.1 mrg * <bare-function-type> ::= <signature type>+ 1858 1.1 mrg * # types are possible return type, then parameter types 1859 1.1 mrg */ 1860 1.1 mrg /* ABI says: 1861 1.1 mrg "The type of a non-static member function is considered to be different, 1862 1.1 mrg for the purposes of substitution, from the type of a namespace-scope or 1863 1.1 mrg static member function whose type appears similar. The types of two 1864 1.1 mrg non-static member functions are considered to be different, for the 1865 1.1 mrg purposes of substitution, if the functions are members of different 1866 1.1 mrg classes. In other words, for the purposes of substitution, the class of 1867 1.1 mrg which the function is a member is considered part of the type of 1868 1.1 mrg function." 1869 1.1 mrg 1870 1.1 mrg BUG: Right now, types of functions are never merged, so our simplistic 1871 1.1 mrg component matcher always finds them to be different. 1872 1.1 mrg We should use Type.equals on these, and use different 1873 1.1 mrg TypeFunctions for non-static member functions, and non-static 1874 1.1 mrg member functions of different classes. 1875 1.1 mrg */ 1876 1.1 mrg if (substitute(t)) 1877 1.1 mrg return; 1878 1.1 mrg buf.writeByte('F'); 1879 1.1 mrg if (t.linkage == LINK.c) 1880 1.1 mrg buf.writeByte('Y'); 1881 1.1 mrg Type tn = t.next; 1882 1.1 mrg if (t.isref) 1883 1.1 mrg tn = tn.referenceTo(); 1884 1.1 mrg tn.accept(this); 1885 1.1 mrg mangleFunctionParameters(t.parameterList); 1886 1.1 mrg buf.writeByte('E'); 1887 1.1 mrg append(t); 1888 1.1 mrg } 1889 1.1 mrg 1890 1.1 mrg override void visit(TypeStruct t) 1891 1.1 mrg { 1892 1.1 mrg if (t.isImmutable() || t.isShared()) 1893 1.1 mrg return error(t); 1894 1.1 mrg //printf("TypeStruct %s\n", t.toChars()); 1895 1.1 mrg doSymbol(t); 1896 1.1 mrg } 1897 1.1 mrg 1898 1.1 mrg override void visit(TypeEnum t) 1899 1.1 mrg { 1900 1.1 mrg if (t.isImmutable() || t.isShared()) 1901 1.1 mrg return error(t); 1902 1.1 mrg 1903 1.1 mrg /* __c_(u)long(long) and others get special mangling 1904 1.1 mrg */ 1905 1.1 mrg const id = t.sym.ident; 1906 1.1 mrg //printf("enum id = '%s'\n", id.toChars()); 1907 1.1 mrg if (id == Id.__c_long) 1908 1.1 mrg return writeBasicType(t, 0, 'l'); 1909 1.1 mrg else if (id == Id.__c_ulong) 1910 1.1 mrg return writeBasicType(t, 0, 'm'); 1911 1.1 mrg else if (id == Id.__c_char) 1912 1.1 mrg return writeBasicType(t, 0, 'c'); 1913 1.1 mrg else if (id == Id.__c_wchar_t) 1914 1.1 mrg return writeBasicType(t, 0, 'w'); 1915 1.1 mrg else if (id == Id.__c_longlong) 1916 1.1 mrg return writeBasicType(t, 0, 'x'); 1917 1.1 mrg else if (id == Id.__c_ulonglong) 1918 1.1 mrg return writeBasicType(t, 0, 'y'); 1919 1.1 mrg else if (id == Id.__c_complex_float) 1920 1.1 mrg return Type.tcomplex32.accept(this); 1921 1.1 mrg else if (id == Id.__c_complex_double) 1922 1.1 mrg return Type.tcomplex64.accept(this); 1923 1.1 mrg else if (id == Id.__c_complex_real) 1924 1.1 mrg return Type.tcomplex80.accept(this); 1925 1.1 mrg 1926 1.1 mrg doSymbol(t); 1927 1.1 mrg } 1928 1.1 mrg 1929 1.1 mrg override void visit(TypeClass t) 1930 1.1 mrg { 1931 1.1 mrg mangleTypeClass(t, false); 1932 1.1 mrg } 1933 1.1 mrg 1934 1.1 mrg /** 1935 1.1 mrg * Performs template parameter substitution 1936 1.1 mrg * 1937 1.1 mrg * Mangling is performed on a copy of the post-parsing AST before 1938 1.1 mrg * any semantic pass is run. 1939 1.1 mrg * There is no easy way to link a type to the template parameters 1940 1.1 mrg * once semantic has run, because: 1941 1.1 mrg * - the `TemplateInstance` installs aliases in its scope to its params 1942 1.1 mrg * - `AliasDeclaration`s are resolved in many places 1943 1.1 mrg * - semantic passes are destructive, so the `TypeIdentifier` gets lost 1944 1.1 mrg * 1945 1.1 mrg * As a result, the best approach with the current architecture is to: 1946 1.1 mrg * - Run the visitor on the `originalType` of the function, 1947 1.1 mrg * looking up any `TypeIdentifier` at the template scope when found. 1948 1.1 mrg * - Fallback to the post-semantic `TypeFunction` when the identifier is 1949 1.1 mrg * not a template parameter. 1950 1.1 mrg */ 1951 1.1 mrg override void visit(TypeIdentifier t) 1952 1.1 mrg { 1953 1.1 mrg auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl; 1954 1.1 mrg assert(decl.parameters !is null); 1955 1.1 mrg auto idx = templateParamIndex(t.ident, decl.parameters); 1956 1.1 mrg // If not found, default to the post-semantic type 1957 1.1 mrg if (idx >= decl.parameters.length) 1958 1.1 mrg return this.context.res.visitObject(this); 1959 1.1 mrg 1960 1.1 mrg auto param = (*decl.parameters)[idx]; 1961 1.1 mrg if (auto type = this.context.res.isType()) 1962 1.1 mrg CV_qualifiers(type); 1963 1.1 mrg // Otherwise, attempt substitution (`S_` takes precedence on `T_`) 1964 1.1 mrg if (this.substitute(param)) 1965 1.1 mrg return; 1966 1.1 mrg 1967 1.1 mrg // If substitution failed, write `TX_` where `X` is the index 1968 1.1 mrg this.writeTemplateArgIndex(idx, param); 1969 1.1 mrg this.append(param); 1970 1.1 mrg // Write the ABI tags, if any 1971 1.1 mrg if (auto sym = this.context.res.isDsymbol()) 1972 1.1 mrg this.abiTags.writeSymbol(sym, this); 1973 1.1 mrg } 1974 1.1 mrg 1975 1.1 mrg /// Ditto 1976 1.1 mrg override void visit(TypeInstance t) 1977 1.1 mrg { 1978 1.1 mrg assert(t.tempinst !is null); 1979 1.1 mrg t.tempinst.accept(this); 1980 1.1 mrg } 1981 1.1 mrg 1982 1.1 mrg /** 1983 1.1 mrg * Mangles a `TemplateInstance` 1984 1.1 mrg * 1985 1.1 mrg * A `TemplateInstance` can be found either in the parameter, 1986 1.1 mrg * or the return value. 1987 1.1 mrg * Arguments to the template instance needs to be mangled but the template 1988 1.1 mrg * can be partially substituted, so for example the following: 1989 1.1 mrg * `Container!(T, Val) func16479_12 (alias Container, T, int Val) ()` 1990 1.1 mrg * will mangle the return value part to "T_IT0_XT1_EE" 1991 1.1 mrg */ 1992 1.1 mrg override void visit(TemplateInstance t) 1993 1.1 mrg { 1994 1.1 mrg // Template names are substituted, but args still need to be written 1995 1.1 mrg void writeArgs () 1996 1.1 mrg { 1997 1.1 mrg buf.writeByte('I'); 1998 1.1 mrg // When visiting the arguments, the context will be set to the 1999 1.1 mrg // resolved type 2000 1.1 mrg auto analyzed_ti = this.context.res.asType().toDsymbol(null).isInstantiated(); 2001 1.1 mrg auto prev = this.context; 2002 1.1 mrg scope (exit) this.context.pop(prev); 2003 1.1 mrg foreach (idx, RootObject o; *t.tiargs) 2004 1.1 mrg { 2005 1.1 mrg this.context.res = (*analyzed_ti.tiargs)[idx]; 2006 1.1 mrg o.visitObject(this); 2007 1.1 mrg } 2008 1.1 mrg if (analyzed_ti.tiargs.dim > t.tiargs.dim) 2009 1.1 mrg { 2010 1.1 mrg // If the resolved AST has more args than the parse one, 2011 1.1 mrg // we have default arguments 2012 1.1 mrg auto oparams = (cast(TemplateDeclaration)analyzed_ti.tempdecl).origParameters; 2013 1.1 mrg foreach (idx, arg; (*oparams)[t.tiargs.dim .. $]) 2014 1.1 mrg { 2015 1.1 mrg this.context.res = (*analyzed_ti.tiargs)[idx + t.tiargs.dim]; 2016 1.1 mrg 2017 1.1 mrg if (auto ttp = arg.isTemplateTypeParameter()) 2018 1.1 mrg ttp.defaultType.accept(this); 2019 1.1 mrg else if (auto tvp = arg.isTemplateValueParameter()) 2020 1.1 mrg tvp.defaultValue.accept(this); 2021 1.1 mrg else if (auto tvp = arg.isTemplateThisParameter()) 2022 1.1 mrg tvp.defaultType.accept(this); 2023 1.1 mrg else if (auto tvp = arg.isTemplateAliasParameter()) 2024 1.1 mrg tvp.defaultAlias.visitObject(this); 2025 1.1 mrg else 2026 1.1 mrg assert(0, arg.toString()); 2027 1.1 mrg } 2028 1.1 mrg } 2029 1.1 mrg buf.writeByte('E'); 2030 1.1 mrg } 2031 1.1 mrg 2032 1.1 mrg // `name` is used, not `ident` 2033 1.1 mrg assert(t.name !is null); 2034 1.1 mrg assert(t.tiargs !is null); 2035 1.1 mrg 2036 1.1 mrg bool needsTa; 2037 1.1 mrg auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl; 2038 1.1 mrg // Attempt to substitute the template itself 2039 1.1 mrg auto idx = templateParamIndex(t.name, decl.parameters); 2040 1.1 mrg if (idx < decl.parameters.length) 2041 1.1 mrg { 2042 1.1 mrg auto param = (*decl.parameters)[idx]; 2043 1.1 mrg if (auto type = t.getType()) 2044 1.1 mrg CV_qualifiers(type); 2045 1.1 mrg if (this.substitute(param)) 2046 1.1 mrg return; 2047 1.1 mrg this.writeTemplateArgIndex(idx, param); 2048 1.1 mrg this.append(param); 2049 1.1 mrg writeArgs(); 2050 1.1 mrg } 2051 1.1 mrg else if (this.writeStdSubstitution(t, needsTa)) 2052 1.1 mrg { 2053 1.1 mrg if (needsTa) 2054 1.1 mrg writeArgs(); 2055 1.1 mrg } 2056 1.1 mrg else if (!this.substitute(t)) 2057 1.1 mrg this.writeQualified(t, &writeArgs); 2058 1.1 mrg } 2059 1.1 mrg 2060 1.1 mrg /// Ditto 2061 1.1 mrg override void visit(IntegerExp t) 2062 1.1 mrg { 2063 1.1 mrg this.buf.writeByte('L'); 2064 1.1 mrg t.type.accept(this); 2065 1.1 mrg this.buf.print(t.getInteger()); 2066 1.1 mrg this.buf.writeByte('E'); 2067 1.1 mrg } 2068 1.1 mrg 2069 1.1 mrg override void visit(Nspace t) 2070 1.1 mrg { 2071 1.1 mrg if (auto p = getQualifier(t)) 2072 1.1 mrg p.accept(this); 2073 1.1 mrg 2074 1.1 mrg if (isStd(t)) 2075 1.1 mrg buf.writestring("St"); 2076 1.1 mrg else 2077 1.1 mrg { 2078 1.1 mrg this.writeIdentifier(t.ident); 2079 1.1 mrg this.append(t); 2080 1.1 mrg } 2081 1.1 mrg } 2082 1.1 mrg 2083 1.1 mrg override void visit(Type t) 2084 1.1 mrg { 2085 1.1 mrg error(t); 2086 1.1 mrg } 2087 1.1 mrg 2088 1.1 mrg void visit(Tuple t) 2089 1.1 mrg { 2090 1.1 mrg assert(0); 2091 1.1 mrg } 2092 1.1 mrg } 2093 1.1 mrg 2094 1.1 mrg /// Helper code to visit `RootObject`, as it doesn't define `accept`, 2095 1.1 mrg /// only its direct subtypes do. 2096 1.1 mrg private void visitObject(V : Visitor)(RootObject o, V this_) 2097 1.1 mrg { 2098 1.1 mrg assert(o !is null); 2099 1.1 mrg if (Type ta = isType(o)) 2100 1.1 mrg ta.accept(this_); 2101 1.1 mrg else if (Expression ea = isExpression(o)) 2102 1.1 mrg ea.accept(this_); 2103 1.1 mrg else if (Dsymbol sa = isDsymbol(o)) 2104 1.1 mrg sa.accept(this_); 2105 1.1 mrg else if (TemplateParameter t = isTemplateParameter(o)) 2106 1.1 mrg t.accept(this_); 2107 1.1 mrg else if (Tuple t = isTuple(o)) 2108 1.1 mrg // `Tuple` inherits `RootObject` and does not define accept 2109 1.1 mrg // For this reason, this uses static dispatch on the visitor 2110 1.1 mrg this_.visit(t); 2111 1.1 mrg else 2112 1.1 mrg assert(0, o.toString()); 2113 1.1 mrg } 2114 1.1 mrg 2115 1.1 mrg /// Helper function to safely get a type out of a `RootObject` 2116 1.1 mrg private Type asType(RootObject o) 2117 1.1 mrg { 2118 1.1 mrg Type ta = isType(o); 2119 1.1 mrg // When called with context.res as argument, it can be `FuncDeclaration` 2120 1.1 mrg if (!ta && o.asFuncDecl()) 2121 1.1 mrg ta = (cast(FuncDeclaration)o).type; 2122 1.1 mrg assert(ta !is null, o.toString()); 2123 1.1 mrg return ta; 2124 1.1 mrg } 2125 1.1 mrg 2126 1.1 mrg /// Helper function to safely get a `FuncDeclaration` out of a `RootObject` 2127 1.1 mrg private FuncDeclaration asFuncDecl(RootObject o) 2128 1.1 mrg { 2129 1.1 mrg Dsymbol d = isDsymbol(o); 2130 1.1 mrg assert(d !is null); 2131 1.1 mrg auto fd = d.isFuncDeclaration(); 2132 1.1 mrg assert(fd !is null); 2133 1.1 mrg return fd; 2134 1.1 mrg } 2135 1.1 mrg 2136 1.1 mrg /// Helper class to compare entries in components 2137 1.1 mrg private extern(C++) final class ComponentVisitor : Visitor 2138 1.1 mrg { 2139 1.1 mrg /// Only one of the following is not `null`, it's always 2140 1.1 mrg /// the most specialized type, set from the ctor 2141 1.1 mrg private Nspace namespace; 2142 1.1 mrg 2143 1.1 mrg /// Ditto 2144 1.1 mrg private CPPNamespaceDeclaration namespace2; 2145 1.1 mrg 2146 1.1 mrg /// Ditto 2147 1.1 mrg private TypePointer tpointer; 2148 1.1 mrg 2149 1.1 mrg /// Ditto 2150 1.1 mrg private TypeReference tref; 2151 1.1 mrg 2152 1.1 mrg /// Ditto 2153 1.1 mrg private TypeIdentifier tident; 2154 1.1 mrg 2155 1.1 mrg /// Least specialized type 2156 1.1 mrg private RootObject object; 2157 1.1 mrg 2158 1.1 mrg /// Set to the result of the comparison 2159 1.1 mrg private bool result; 2160 1.1 mrg 2161 1.1 mrg public this(RootObject base) 2162 1.1 mrg { 2163 1.1 mrg switch (base.dyncast()) 2164 1.1 mrg { 2165 1.1 mrg case DYNCAST.dsymbol: 2166 1.1 mrg if (auto ns = (cast(Dsymbol)base).isNspace()) 2167 1.1 mrg this.namespace = ns; 2168 1.1 mrg else if (auto ns = (cast(Dsymbol)base).isCPPNamespaceDeclaration()) 2169 1.1 mrg this.namespace2 = ns; 2170 1.1 mrg else 2171 1.1 mrg goto default; 2172 1.1 mrg break; 2173 1.1 mrg 2174 1.1 mrg case DYNCAST.type: 2175 1.1 mrg auto t = cast(Type)base; 2176 1.1 mrg if (t.ty == Tpointer) 2177 1.1 mrg this.tpointer = cast(TypePointer)t; 2178 1.1 mrg else if (t.ty == Treference) 2179 1.1 mrg this.tref = cast(TypeReference)t; 2180 1.1 mrg else if (t.ty == Tident) 2181 1.1 mrg this.tident = cast(TypeIdentifier)t; 2182 1.1 mrg else 2183 1.1 mrg goto default; 2184 1.1 mrg break; 2185 1.1 mrg 2186 1.1 mrg // Note: ABI tags are also handled here (they are TupleExp of StringExp) 2187 1.1 mrg default: 2188 1.1 mrg this.object = base; 2189 1.1 mrg } 2190 1.1 mrg } 2191 1.1 mrg 2192 1.1 mrg /// Introduce base class overloads 2193 1.1 mrg alias visit = Visitor.visit; 2194 1.1 mrg 2195 1.1 mrg /// Least specialized overload of each direct child of `RootObject` 2196 1.1 mrg public override void visit(Dsymbol o) 2197 1.1 mrg { 2198 1.1 mrg this.result = this.object && this.object == o; 2199 1.1 mrg } 2200 1.1 mrg 2201 1.1 mrg /// Ditto 2202 1.1 mrg public override void visit(Expression o) 2203 1.1 mrg { 2204 1.1 mrg this.result = this.object && this.object == o; 2205 1.1 mrg } 2206 1.1 mrg 2207 1.1 mrg /// Ditto 2208 1.1 mrg public void visit(Tuple o) 2209 1.1 mrg { 2210 1.1 mrg this.result = this.object && this.object == o; 2211 1.1 mrg } 2212 1.1 mrg 2213 1.1 mrg /// Ditto 2214 1.1 mrg public override void visit(Type o) 2215 1.1 mrg { 2216 1.1 mrg this.result = this.object && this.object == o; 2217 1.1 mrg } 2218 1.1 mrg 2219 1.1 mrg /// Ditto 2220 1.1 mrg public override void visit(TemplateParameter o) 2221 1.1 mrg { 2222 1.1 mrg this.result = this.object && this.object == o; 2223 1.1 mrg } 2224 1.1 mrg 2225 1.1 mrg /** 2226 1.1 mrg * This overload handles composed types including template parameters 2227 1.1 mrg * 2228 1.1 mrg * Components for substitutions include "next" type. 2229 1.1 mrg * For example, if `ref T` is present, `ref T` and `T` will be present 2230 1.1 mrg * in the substitution array. 2231 1.1 mrg * But since we don't have the final/merged type, we cannot rely on 2232 1.1 mrg * object comparison, and need to recurse instead. 2233 1.1 mrg */ 2234 1.1 mrg public override void visit(TypeReference o) 2235 1.1 mrg { 2236 1.1 mrg if (!this.tref) 2237 1.1 mrg return; 2238 1.1 mrg if (this.tref == o) 2239 1.1 mrg this.result = true; 2240 1.1 mrg else 2241 1.1 mrg { 2242 1.1 mrg // It might be a reference to a template parameter that we already 2243 1.1 mrg // saw, so we need to recurse 2244 1.1 mrg scope v = new ComponentVisitor(this.tref.next); 2245 1.1 mrg o.next.visitObject(v); 2246 1.1 mrg this.result = v.result; 2247 1.1 mrg } 2248 1.1 mrg } 2249 1.1 mrg 2250 1.1 mrg /// Ditto 2251 1.1 mrg public override void visit(TypePointer o) 2252 1.1 mrg { 2253 1.1 mrg if (!this.tpointer) 2254 1.1 mrg return; 2255 1.1 mrg if (this.tpointer == o) 2256 1.1 mrg this.result = true; 2257 1.1 mrg else 2258 1.1 mrg { 2259 1.1 mrg // It might be a pointer to a template parameter that we already 2260 1.1 mrg // saw, so we need to recurse 2261 1.1 mrg scope v = new ComponentVisitor(this.tpointer.next); 2262 1.1 mrg o.next.visitObject(v); 2263 1.1 mrg this.result = v.result; 2264 1.1 mrg } 2265 1.1 mrg } 2266 1.1 mrg 2267 1.1 mrg /// Ditto 2268 1.1 mrg public override void visit(TypeIdentifier o) 2269 1.1 mrg { 2270 1.1 mrg /// Since we know they are at the same level, scope resolution will 2271 1.1 mrg /// give us the same symbol, thus we can just compare ident. 2272 1.1 mrg this.result = (this.tident && (this.tident.ident == o.ident)); 2273 1.1 mrg } 2274 1.1 mrg 2275 1.1 mrg /** 2276 1.1 mrg * Overload which accepts a Namespace 2277 1.1 mrg * 2278 1.1 mrg * It is very common for large C++ projects to have multiple files sharing 2279 1.1 mrg * the same `namespace`. If any D project adopts the same approach 2280 1.1 mrg * (e.g. separating data structures from functions), it will lead to two 2281 1.1 mrg * `Nspace` objects being instantiated, with different addresses. 2282 1.1 mrg * At the same time, we cannot compare just any Dsymbol via identifier, 2283 1.1 mrg * because it messes with templates. 2284 1.1 mrg * 2285 1.1 mrg * See_Also: 2286 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=18922 2287 1.1 mrg * 2288 1.1 mrg * Params: 2289 1.1 mrg * ns = C++ namespace to do substitution for 2290 1.1 mrg */ 2291 1.1 mrg public override void visit(Nspace ns) 2292 1.1 mrg { 2293 1.1 mrg this.result = isNamespaceEqual(this.namespace, ns) 2294 1.1 mrg || isNamespaceEqual(this.namespace2, ns); 2295 1.1 mrg } 2296 1.1 mrg 2297 1.1 mrg /// Ditto 2298 1.1 mrg public override void visit(CPPNamespaceDeclaration ns) 2299 1.1 mrg { 2300 1.1 mrg this.result = isNamespaceEqual(this.namespace, ns) 2301 1.1 mrg || isNamespaceEqual(this.namespace2, ns); 2302 1.1 mrg } 2303 1.1 mrg } 2304 1.1 mrg 2305 1.1 mrg /// Transitional functions for `CPPNamespaceDeclaration` / `Nspace` 2306 1.1 mrg /// Remove when `Nspace` is removed. 2307 1.1 mrg private bool isNamespaceEqual (Nspace a, Nspace b) 2308 1.1 mrg { 2309 1.1 mrg if (a is null || b is null) 2310 1.1 mrg return false; 2311 1.1 mrg return a.equals(b); 2312 1.1 mrg } 2313 1.1 mrg 2314 1.1 mrg /// Ditto 2315 1.1 mrg private bool isNamespaceEqual (Nspace a, CPPNamespaceDeclaration b) 2316 1.1 mrg { 2317 1.1 mrg return isNamespaceEqual(b, a); 2318 1.1 mrg } 2319 1.1 mrg 2320 1.1 mrg /// Ditto 2321 1.1 mrg private bool isNamespaceEqual (CPPNamespaceDeclaration a, Nspace b, size_t idx = 0) 2322 1.1 mrg { 2323 1.1 mrg if ((a is null) != (b is null)) 2324 1.1 mrg return false; 2325 1.1 mrg if (!a.ident.equals(b.ident)) 2326 1.1 mrg return false; 2327 1.1 mrg 2328 1.1 mrg // We need to see if there's more ident enclosing 2329 1.1 mrg if (auto pb = b.toParent().isNspace()) 2330 1.1 mrg return isNamespaceEqual(a.cppnamespace, pb); 2331 1.1 mrg else 2332 1.1 mrg return a.cppnamespace is null; 2333 1.1 mrg } 2334 1.1 mrg 2335 1.1 mrg /// Returns: 2336 1.1 mrg /// Whether two `CPPNamespaceDeclaration` are equals 2337 1.1 mrg private bool isNamespaceEqual (CPPNamespaceDeclaration a, CPPNamespaceDeclaration b) 2338 1.1 mrg { 2339 1.1 mrg if (a is null || b is null) 2340 1.1 mrg return false; 2341 1.1 mrg 2342 1.1 mrg if ((a.cppnamespace is null) != (b.cppnamespace is null)) 2343 1.1 mrg return false; 2344 1.1 mrg if (a.ident != b.ident) 2345 1.1 mrg return false; 2346 1.1 mrg return a.cppnamespace is null ? true : isNamespaceEqual(a.cppnamespace, b.cppnamespace); 2347 1.1 mrg } 2348 1.1 mrg 2349 1.1 mrg /** 2350 1.1 mrg * A container for ABI tags 2351 1.1 mrg * 2352 1.1 mrg * At its hearth, there is a sorted array of ABI tags having been written 2353 1.1 mrg * already. ABI tags can be present on parameters, template parameters, 2354 1.1 mrg * return value, and varaible. ABI tags for a given type needs to be written 2355 1.1 mrg * sorted. When a function returns a type that has ABI tags, only the tags that 2356 1.1 mrg * haven't been printed as part of the mangling (e.g. arguments) are written 2357 1.1 mrg * directly after the function name. 2358 1.1 mrg * 2359 1.1 mrg * This means that: 2360 1.1 mrg * --- 2361 1.1 mrg * /++ C++ type definitions: 2362 1.1 mrg * struct [[gnu::abi_tag("tag1")]] Struct1 {}; 2363 1.1 mrg * struct [[gnu::abi_tag("tag2")]] Struct2 {}; 2364 1.1 mrg * // Can also be: "tag2", "tag1", since tags are sorted. 2365 1.1 mrg * struct [[gnu::abi_tag("tag1", "tag2")]] Struct3 {}; 2366 1.1 mrg * +/ 2367 1.1 mrg * // Functions definitions: 2368 1.1 mrg * Struct3 func1 (Struct1); 2369 1.1 mrg * Struct3 func2 (Struct2); 2370 1.1 mrg * Struct3 func3 (Struct2, Struct1); 2371 1.1 mrg * --- 2372 1.1 mrg * Will be respectively pseudo-mangled (part of interest between stars) as: 2373 1.1 mrg * "_Z4 func1 *B4tag2* ParamsMangling" (ParamsMangling includes tag1), 2374 1.1 mrg * "_Z4 func2 *B4tag1* ParamsMangling" (ParamsMangling includes tag2), 2375 1.1 mrg * "_Z4 func2 *B4tag1* ParamsMangling" (ParamsMangling includes both). 2376 1.1 mrg * 2377 1.1 mrg * This is why why need to keep a list of tags that were written, 2378 1.1 mrg * and insert the missing one after parameter mangling has been written. 2379 1.1 mrg * Since there's a lot of operations that are not easily doable in DMD 2380 1.1 mrg * (since we can't use Phobos), this special container is implemented. 2381 1.1 mrg */ 2382 1.1 mrg private struct ABITagContainer 2383 1.1 mrg { 2384 1.1 mrg private Array!StringExp written; 2385 1.1 mrg 2386 1.1 mrg static ArrayLiteralExp forSymbol (Dsymbol s) 2387 1.1 mrg { 2388 1.1 mrg if (!s) 2389 1.1 mrg return null; 2390 1.1 mrg // If this is a template instance, we want the declaration, 2391 1.1 mrg // as that's where the UDAs are 2392 1.1 mrg if (auto ti = s.isTemplateInstance()) 2393 1.1 mrg s = ti.tempdecl; 2394 1.1 mrg if (!s.userAttribDecl || !s.userAttribDecl.atts) 2395 1.1 mrg return null; 2396 1.1 mrg 2397 1.1 mrg foreach (exp; *s.userAttribDecl.atts) 2398 1.1 mrg { 2399 1.1 mrg if (UserAttributeDeclaration.isGNUABITag(exp)) 2400 1.1 mrg return (*exp.isStructLiteralExp().elements)[0] 2401 1.1 mrg .isArrayLiteralExp(); 2402 1.1 mrg } 2403 1.1 mrg return null; 2404 1.1 mrg } 2405 1.1 mrg 2406 1.1 mrg void writeSymbol(Dsymbol s, CppMangleVisitor self) 2407 1.1 mrg { 2408 1.1 mrg auto tale = forSymbol(s); 2409 1.1 mrg if (!tale) return; 2410 1.1 mrg if (self.substitute(tale)) 2411 1.1 mrg return; 2412 1.1 mrg this.write(*self.buf, tale); 2413 1.1 mrg } 2414 1.1 mrg 2415 1.1 mrg /** 2416 1.1 mrg * Write an ArrayLiteralExp (expected to be an ABI tag) to the buffer 2417 1.1 mrg * 2418 1.1 mrg * Params: 2419 1.1 mrg * buf = Buffer to write mangling to 2420 1.1 mrg * ale = GNU ABI tag array literal expression, semantically analyzed 2421 1.1 mrg */ 2422 1.1 mrg void write (ref OutBuffer buf, ArrayLiteralExp ale, bool skipKnown = false) 2423 1.1 mrg { 2424 1.1 mrg void writeElem (StringExp exp) 2425 1.1 mrg { 2426 1.1 mrg const tag = exp.peekString(); 2427 1.1 mrg buf.writestring("B"); 2428 1.1 mrg buf.print(tag.length); 2429 1.1 mrg buf.writestring(tag); 2430 1.1 mrg } 2431 1.1 mrg 2432 1.1 mrg bool match; 2433 1.1 mrg foreach (exp; *ale.elements) 2434 1.1 mrg { 2435 1.1 mrg auto elem = exp.toStringExp(); 2436 1.1 mrg auto idx = closestIndex(this.written[], elem, match); 2437 1.1 mrg if (!match) 2438 1.1 mrg { 2439 1.1 mrg writeElem(elem); 2440 1.1 mrg this.written.insert(idx, elem); 2441 1.1 mrg } 2442 1.1 mrg else if (!skipKnown) 2443 1.1 mrg writeElem(elem); 2444 1.1 mrg } 2445 1.1 mrg } 2446 1.1 mrg } 2447 1.1 mrg 2448 1.1 mrg /** 2449 1.1 mrg * Returns the closest index to to `exp` in `slice` 2450 1.1 mrg * 2451 1.1 mrg * Performs a binary search on `slice` (assumes `slice` is sorted), 2452 1.1 mrg * and returns either `exp`'s index in `slice` if `exact` is `true`, 2453 1.1 mrg * or the index at which `exp` can be inserted in `slice` if `exact is `false`. 2454 1.1 mrg * Inserting `exp` at the return value will keep the array sorted. 2455 1.1 mrg * 2456 1.1 mrg * Params: 2457 1.1 mrg * slice = The sorted slice to search into 2458 1.1 mrg * exp = The string expression to search for 2459 1.1 mrg * exact = If `true` on return, `exp` was found in `slice` 2460 1.1 mrg * 2461 1.1 mrg * Returns: 2462 1.1 mrg * Either the index to insert `exp` at (if `exact == false`), 2463 1.1 mrg * or the index of `exp` in `slice`. 2464 1.1 mrg */ 2465 1.1 mrg private size_t closestIndex (const(StringExp)[] slice, StringExp exp, out bool exact) 2466 1.1 mrg { 2467 1.1 mrg if (!slice.length) return 0; 2468 1.1 mrg 2469 1.1 mrg const StringExp* first = slice.ptr; 2470 1.1 mrg while (true) 2471 1.1 mrg { 2472 1.1 mrg int res = dstrcmp(exp.peekString(), slice[$ / 2].peekString()); 2473 1.1 mrg if (res == 0) 2474 1.1 mrg { 2475 1.1 mrg exact = true; 2476 1.1 mrg return (&slice[$/2] - first); 2477 1.1 mrg } 2478 1.1 mrg 2479 1.1 mrg if (slice.length == 1) 2480 1.1 mrg return (slice.ptr - first) + (res > 0); 2481 1.1 mrg slice = slice[(res > 0 ? $ / 2 : 0) .. (res > 0 ? $ : $ / 2)]; 2482 1.1 mrg } 2483 1.1 mrg } 2484 1.1 mrg 2485 1.1 mrg // 2486 1.1 mrg unittest 2487 1.1 mrg { 2488 1.1 mrg bool match; 2489 1.1 mrg auto s1 = new StringExp(Loc.initial, "Amande"); 2490 1.1 mrg auto s2 = new StringExp(Loc.initial, "Baguette"); 2491 1.1 mrg auto s3 = new StringExp(Loc.initial, "Croissant"); 2492 1.1 mrg auto s4 = new StringExp(Loc.initial, "Framboises"); 2493 1.1 mrg auto s5 = new StringExp(Loc.initial, "Proscuitto"); 2494 1.1 mrg 2495 1.1 mrg // Found, odd size 2496 1.1 mrg assert(closestIndex([s1, s2, s3, s4, s5], s1, match) == 0 && match); 2497 1.1 mrg assert(closestIndex([s1, s2, s3, s4, s5], s2, match) == 1 && match); 2498 1.1 mrg assert(closestIndex([s1, s2, s3, s4, s5], s3, match) == 2 && match); 2499 1.1 mrg assert(closestIndex([s1, s2, s3, s4, s5], s4, match) == 3 && match); 2500 1.1 mrg assert(closestIndex([s1, s2, s3, s4, s5], s5, match) == 4 && match); 2501 1.1 mrg 2502 1.1 mrg // Not found, even size 2503 1.1 mrg assert(closestIndex([s2, s3, s4, s5], s1, match) == 0 && !match); 2504 1.1 mrg assert(closestIndex([s1, s3, s4, s5], s2, match) == 1 && !match); 2505 1.1 mrg assert(closestIndex([s1, s2, s4, s5], s3, match) == 2 && !match); 2506 1.1 mrg assert(closestIndex([s1, s2, s3, s5], s4, match) == 3 && !match); 2507 1.1 mrg assert(closestIndex([s1, s2, s3, s4], s5, match) == 4 && !match); 2508 1.1 mrg 2509 1.1 mrg // Found, even size 2510 1.1 mrg assert(closestIndex([s1, s2, s3, s4], s1, match) == 0 && match); 2511 1.1 mrg assert(closestIndex([s1, s2, s3, s4], s2, match) == 1 && match); 2512 1.1 mrg assert(closestIndex([s1, s2, s3, s4], s3, match) == 2 && match); 2513 1.1 mrg assert(closestIndex([s1, s2, s3, s4], s4, match) == 3 && match); 2514 1.1 mrg assert(closestIndex([s1, s3, s4, s5], s5, match) == 3 && match); 2515 1.1 mrg 2516 1.1 mrg // Not found, odd size 2517 1.1 mrg assert(closestIndex([s2, s4, s5], s1, match) == 0 && !match); 2518 1.1 mrg assert(closestIndex([s1, s4, s5], s2, match) == 1 && !match); 2519 1.1 mrg assert(closestIndex([s1, s2, s4], s3, match) == 2 && !match); 2520 1.1 mrg assert(closestIndex([s1, s3, s5], s4, match) == 2 && !match); 2521 1.1 mrg assert(closestIndex([s1, s2, s4], s5, match) == 3 && !match); 2522 1.1 mrg } 2523 1.1 mrg 2524 1.1 mrg /** 2525 1.1 mrg * Visits the return type of a function and writes leftover ABI tags 2526 1.1 mrg */ 2527 1.1 mrg extern(C++) private final class LeftoverVisitor : Visitor 2528 1.1 mrg { 2529 1.1 mrg /// List of tags to write 2530 1.1 mrg private Array!StringExp toWrite; 2531 1.1 mrg /// List of tags to ignore 2532 1.1 mrg private const(Array!StringExp)* ignore; 2533 1.1 mrg 2534 1.1 mrg /// 2535 1.1 mrg public this(const(Array!StringExp)* previous) 2536 1.1 mrg { 2537 1.1 mrg this.ignore = previous; 2538 1.1 mrg } 2539 1.1 mrg 2540 1.1 mrg /// Reintroduce base class overloads 2541 1.1 mrg public alias visit = Visitor.visit; 2542 1.1 mrg 2543 1.1 mrg /// Least specialized overload of each direct child of `RootObject` 2544 1.1 mrg public override void visit(Dsymbol o) 2545 1.1 mrg { 2546 1.1 mrg auto ale = ABITagContainer.forSymbol(o); 2547 1.1 mrg if (!ale) return; 2548 1.1 mrg 2549 1.1 mrg bool match; 2550 1.1 mrg foreach (elem; *ale.elements) 2551 1.1 mrg { 2552 1.1 mrg auto se = elem.toStringExp(); 2553 1.1 mrg closestIndex((*this.ignore)[], se, match); 2554 1.1 mrg if (match) continue; 2555 1.1 mrg auto idx = closestIndex(this.toWrite[], se, match); 2556 1.1 mrg if (!match) 2557 1.1 mrg this.toWrite.insert(idx, se); 2558 1.1 mrg } 2559 1.1 mrg } 2560 1.1 mrg 2561 1.1 mrg /// Ditto 2562 1.1 mrg public override void visit(Type o) 2563 1.1 mrg { 2564 1.1 mrg if (auto sym = o.toDsymbol(null)) 2565 1.1 mrg sym.accept(this); 2566 1.1 mrg } 2567 1.1 mrg 2568 1.1 mrg /// Composite type 2569 1.1 mrg public override void visit(TypePointer o) 2570 1.1 mrg { 2571 1.1 mrg o.next.accept(this); 2572 1.1 mrg } 2573 1.1 mrg 2574 1.1 mrg public override void visit(TypeReference o) 2575 1.1 mrg { 2576 1.1 mrg o.next.accept(this); 2577 1.1 mrg } 2578 1.1 mrg } 2579