cppmangle.d revision 1.1 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