]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | |
2 | /* Compiler implementation of the D programming language | |
3 | * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved | |
4 | * written by Walter Bright | |
5 | * http://www.digitalmars.com | |
6 | * Distributed under the Boost Software License, Version 1.0. | |
7 | * http://www.boost.org/LICENSE_1_0.txt | |
8 | * https://github.com/D-Programming-Language/dmd/blob/master/src/cppmangle.c | |
9 | */ | |
10 | ||
11 | /** | |
12 | * Do mangling for C++ linkage. | |
13 | * | |
14 | * References: | |
15 | * Follows Itanium C++ ABI 1.86 section 5.1 | |
16 | * http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling | |
17 | * which is where the grammar comments come from. | |
18 | * | |
19 | * Bugs: | |
20 | * https://issues.dlang.org/query.cgi | |
21 | * enter `C++, mangling` as the keywords. | |
22 | */ | |
23 | ||
f9ab59ff | 24 | #include "root/dsystem.h" |
b4c522fa IB |
25 | |
26 | #include "mars.h" | |
27 | #include "dsymbol.h" | |
28 | #include "mtype.h" | |
29 | #include "scope.h" | |
30 | #include "init.h" | |
31 | #include "expression.h" | |
32 | #include "attrib.h" | |
33 | #include "declaration.h" | |
34 | #include "template.h" | |
35 | #include "id.h" | |
36 | #include "enum.h" | |
37 | #include "import.h" | |
38 | #include "aggregate.h" | |
39 | #include "target.h" | |
40 | ||
41 | typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param); | |
42 | int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL); | |
43 | ||
44 | class CppMangleVisitor : public Visitor | |
45 | { | |
46 | Objects components; // array of components available for substitution | |
47 | OutBuffer *buf; // append the mangling to buf[] | |
f9ab59ff | 48 | public: |
b4c522fa IB |
49 | Loc loc; // location for use in error messages |
50 | ||
b4c522fa IB |
51 | // Write <seq-id> to buf |
52 | void write_seq_id(size_t i) | |
53 | { | |
54 | if (i >= 36) | |
55 | { | |
56 | write_seq_id(i / 36); | |
57 | i %= 36; | |
58 | } | |
59 | i += (i < 10) ? '0' : 'A' - 10; | |
60 | buf->writeByte((char)i); | |
61 | } | |
62 | ||
63 | bool substitute(RootObject *p) | |
64 | { | |
65 | //printf("substitute %s\n", p ? p->toChars() : NULL); | |
66 | int i = find(p); | |
67 | if (i >= 0) | |
68 | { | |
69 | //printf("\tmatch\n"); | |
70 | /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... | |
71 | */ | |
72 | buf->writeByte('S'); | |
73 | if (i) | |
74 | { | |
75 | write_seq_id(i - 1); | |
76 | } | |
77 | buf->writeByte('_'); | |
78 | return true; | |
79 | } | |
80 | return false; | |
81 | } | |
82 | ||
83 | /****** | |
84 | * See if `p` exists in components[] | |
85 | * Returns: | |
86 | * index if found, -1 if not | |
87 | */ | |
88 | int find(RootObject *p) | |
89 | { | |
90 | //printf("find %p %d %s\n", p, p.dyncast(), p ? p.toChars() : NULL); | |
91 | for (size_t i = 0; i < components.dim; i++) | |
92 | { | |
93 | if (p == components[i]) | |
94 | return (int)i; | |
95 | } | |
96 | return -1; | |
97 | } | |
98 | ||
99 | /********************* | |
100 | * Append p to components[] | |
101 | */ | |
102 | void append(RootObject *p) | |
103 | { | |
104 | //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null"); | |
105 | components.push(p); | |
106 | } | |
107 | ||
108 | /************************ | |
109 | * Determine if symbol is indeed the global ::std namespace. | |
110 | * Params: | |
111 | * s = symbol to check | |
112 | * Returns: | |
113 | * true if it is ::std | |
114 | */ | |
115 | static bool isStd(Dsymbol *s) | |
116 | { | |
117 | return (s && | |
118 | s->ident == Id::std && // the right name | |
119 | s->isNspace() && // g++ disallows global "std" for other than a namespace | |
120 | !getQualifier(s)); // at global level | |
121 | } | |
122 | ||
123 | /****************************** | |
124 | * Write the mangled representation of the template arguments. | |
125 | * Params: | |
126 | * ti = the template instance | |
127 | */ | |
128 | void template_args(TemplateInstance *ti) | |
129 | { | |
130 | /* <template-args> ::= I <template-arg>+ E | |
131 | */ | |
132 | if (!ti) // could happen if std::basic_string is not a template | |
133 | return; | |
134 | buf->writeByte('I'); | |
135 | for (size_t i = 0; i < ti->tiargs->dim; i++) | |
136 | { | |
137 | RootObject *o = (*ti->tiargs)[i]; | |
138 | TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); | |
139 | assert(td); | |
140 | TemplateParameter *tp = (*td->parameters)[i]; | |
141 | ||
142 | /* | |
143 | * <template-arg> ::= <type> # type or template | |
144 | * ::= X <expression> E # expression | |
145 | * ::= <expr-primary> # simple expressions | |
146 | * ::= I <template-arg>* E # argument pack | |
147 | */ | |
148 | if (tp->isTemplateTupleParameter()) | |
149 | { | |
150 | buf->writeByte('I'); // argument pack | |
151 | ||
152 | // mangle the rest of the arguments as types | |
153 | for (size_t j = i; j < ti->tiargs->dim; j++) | |
154 | { | |
155 | Type *t = isType((*ti->tiargs)[j]); | |
156 | assert(t); | |
157 | t->accept(this); | |
158 | } | |
159 | ||
160 | buf->writeByte('E'); | |
161 | break; | |
162 | } | |
163 | if (tp->isTemplateTypeParameter()) | |
164 | { | |
165 | Type *t = isType(o); | |
166 | assert(t); | |
167 | t->accept(this); | |
168 | } | |
169 | else if (TemplateValueParameter *tv = tp->isTemplateValueParameter()) | |
170 | { | |
171 | // <expr-primary> ::= L <type> <value number> E # integer literal | |
172 | if (tv->valType->isintegral()) | |
173 | { | |
174 | Expression *e = isExpression(o); | |
175 | assert(e); | |
176 | buf->writeByte('L'); | |
177 | tv->valType->accept(this); | |
178 | uinteger_t val = e->toUInteger(); | |
179 | if (!tv->valType->isunsigned() && (sinteger_t)val < 0) | |
180 | { | |
181 | val = -val; | |
182 | buf->writeByte('n'); | |
183 | } | |
184 | buf->printf("%llu", val); | |
185 | buf->writeByte('E'); | |
186 | } | |
187 | else | |
188 | { | |
189 | ti->error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv->valType->toChars()); | |
190 | fatal(); | |
191 | } | |
192 | } | |
193 | else if (tp->isTemplateAliasParameter()) | |
194 | { | |
195 | Dsymbol *d = isDsymbol(o); | |
196 | Expression *e = isExpression(o); | |
197 | if (d && d->isFuncDeclaration()) | |
198 | { | |
199 | bool is_nested = d->toParent() && | |
200 | !d->toParent()->isModule() && | |
201 | ((TypeFunction*)d->isFuncDeclaration()->type)->linkage == LINKcpp; | |
202 | if (is_nested) | |
203 | buf->writeByte('X'); | |
204 | buf->writeByte('L'); | |
205 | mangle_function(d->isFuncDeclaration()); | |
206 | buf->writeByte('E'); | |
207 | if (is_nested) | |
208 | buf->writeByte('E'); | |
209 | } | |
210 | else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration()) | |
211 | { | |
212 | VarDeclaration *vd = ((VarExp*)e)->var->isVarDeclaration(); | |
213 | buf->writeByte('L'); | |
214 | mangle_variable(vd, true); | |
215 | buf->writeByte('E'); | |
216 | } | |
217 | else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember) | |
218 | { | |
219 | if (!substitute(d)) | |
220 | { | |
221 | cpp_mangle_name(d, false); | |
222 | } | |
223 | } | |
224 | else | |
225 | { | |
226 | ti->error("Internal Compiler Error: `%s` is unsupported parameter for C++ template", o->toChars()); | |
227 | fatal(); | |
228 | } | |
229 | } | |
230 | else if(tp->isTemplateThisParameter()) | |
231 | { | |
232 | ti->error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o->toChars()); | |
233 | fatal(); | |
234 | } | |
235 | else | |
236 | { | |
237 | assert(0); | |
238 | } | |
239 | } | |
240 | buf->writeByte('E'); | |
241 | } | |
242 | ||
243 | void source_name(Dsymbol *s) | |
244 | { | |
245 | //printf("source_name(%s)\n", s->toChars()); | |
246 | if (TemplateInstance *ti = s->isTemplateInstance()) | |
247 | { | |
248 | if (!substitute(ti->tempdecl)) | |
249 | { | |
250 | append(ti->tempdecl); | |
251 | const char *name = ti->tempdecl->toAlias()->ident->toChars(); | |
252 | buf->printf("%d", strlen(name)); | |
253 | buf->writestring(name); | |
254 | } | |
255 | template_args(ti); | |
256 | } | |
257 | else | |
258 | { | |
259 | const char *name = s->ident->toChars(); | |
260 | buf->printf("%d", strlen(name)); | |
261 | buf->writestring(name); | |
262 | } | |
263 | } | |
264 | ||
265 | /******** | |
266 | * See if s is actually an instance of a template | |
267 | * Params: | |
268 | * s = symbol | |
269 | * Returns: | |
270 | * if s is instance of a template, return the instance, otherwise return s | |
271 | */ | |
272 | Dsymbol *getInstance(Dsymbol *s) | |
273 | { | |
274 | Dsymbol *p = s->toParent(); | |
275 | if (p) | |
276 | { | |
277 | if (TemplateInstance *ti = p->isTemplateInstance()) | |
278 | return ti; | |
279 | } | |
280 | return s; | |
281 | } | |
282 | ||
283 | /******** | |
284 | * Get qualifier for `s`, meaning the symbol | |
285 | * that s is in the symbol table of. | |
286 | * The module does not count as a qualifier, because C++ | |
287 | * does not have modules. | |
288 | * Params: | |
289 | * s = symbol that may have a qualifier | |
290 | * Returns: | |
291 | * qualifier, NULL if none | |
292 | */ | |
293 | static Dsymbol *getQualifier(Dsymbol *s) | |
294 | { | |
295 | Dsymbol *p = s->toParent(); | |
296 | return (p && !p->isModule()) ? p : NULL; | |
297 | } | |
298 | ||
299 | // Detect type char | |
300 | static bool isChar(RootObject *o) | |
301 | { | |
302 | Type *t = isType(o); | |
303 | return (t && t->equals(Type::tchar)); | |
304 | } | |
305 | ||
306 | // Detect type ::std::char_traits<char> | |
307 | static bool isChar_traits_char(RootObject *o) | |
308 | { | |
309 | return isIdent_char(Id::char_traits, o); | |
310 | } | |
311 | ||
312 | // Detect type ::std::allocator<char> | |
313 | static bool isAllocator_char(RootObject *o) | |
314 | { | |
315 | return isIdent_char(Id::allocator, o); | |
316 | } | |
317 | ||
318 | // Detect type ::std::ident<char> | |
319 | static bool isIdent_char(Identifier *ident, RootObject *o) | |
320 | { | |
321 | Type *t = isType(o); | |
322 | if (!t || t->ty != Tstruct) | |
323 | return false; | |
324 | Dsymbol *s = ((TypeStruct*)t)->toDsymbol(NULL); | |
325 | if (s->ident != ident) | |
326 | return false; | |
327 | Dsymbol *p = s->toParent(); | |
328 | if (!p) | |
329 | return false; | |
330 | TemplateInstance *ti = p->isTemplateInstance(); | |
331 | if (!ti) | |
332 | return false; | |
333 | Dsymbol *q = getQualifier(ti); | |
334 | return isStd(q) && ti->tiargs->dim == 1 && isChar((*ti->tiargs)[0]); | |
335 | } | |
336 | ||
337 | /*** | |
338 | * Detect template args <char, ::std::char_traits<char>> | |
339 | * and write st if found. | |
340 | * Returns: | |
341 | * true if found | |
342 | */ | |
343 | bool char_std_char_traits_char(TemplateInstance *ti, const char *st) | |
344 | { | |
345 | if (ti->tiargs->dim == 2 && | |
346 | isChar((*ti->tiargs)[0]) && | |
347 | isChar_traits_char((*ti->tiargs)[1])) | |
348 | { | |
349 | buf->writestring(st); | |
350 | return true; | |
351 | } | |
352 | return false; | |
353 | } | |
354 | ||
355 | ||
356 | void prefix_name(Dsymbol *s) | |
357 | { | |
358 | //printf("prefix_name(%s)\n", s->toChars()); | |
359 | if (!substitute(s)) | |
360 | { | |
361 | Dsymbol *si = getInstance(s); | |
362 | Dsymbol *p = getQualifier(si); | |
363 | if (p) | |
364 | { | |
365 | if (isStd(p)) | |
366 | { | |
367 | TemplateInstance *ti = si->isTemplateInstance(); | |
368 | if (ti) | |
369 | { | |
370 | if (s->ident == Id::allocator) | |
371 | { | |
372 | buf->writestring("Sa"); | |
373 | template_args(ti); | |
374 | append(ti); | |
375 | return; | |
376 | } | |
377 | if (s->ident == Id::basic_string) | |
378 | { | |
379 | // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>> | |
380 | if (ti->tiargs->dim == 3 && | |
381 | isChar((*ti->tiargs)[0]) && | |
382 | isChar_traits_char((*ti->tiargs)[1]) && | |
383 | isAllocator_char((*ti->tiargs)[2])) | |
384 | ||
385 | { | |
386 | buf->writestring("Ss"); | |
387 | return; | |
388 | } | |
389 | buf->writestring("Sb"); // ::std::basic_string | |
390 | template_args(ti); | |
391 | append(ti); | |
392 | return; | |
393 | } | |
394 | ||
395 | // ::std::basic_istream<char, ::std::char_traits<char>> | |
396 | if (s->ident == Id::basic_istream && | |
397 | char_std_char_traits_char(ti, "Si")) | |
398 | return; | |
399 | ||
400 | // ::std::basic_ostream<char, ::std::char_traits<char>> | |
401 | if (s->ident == Id::basic_ostream && | |
402 | char_std_char_traits_char(ti, "So")) | |
403 | return; | |
404 | ||
405 | // ::std::basic_iostream<char, ::std::char_traits<char>> | |
406 | if (s->ident == Id::basic_iostream && | |
407 | char_std_char_traits_char(ti, "Sd")) | |
408 | return; | |
409 | } | |
410 | buf->writestring("St"); | |
411 | } | |
412 | else | |
413 | prefix_name(p); | |
414 | } | |
415 | source_name(si); | |
416 | if (!isStd(si)) | |
417 | { | |
418 | /* Do this after the source_name() call to keep components[] | |
419 | * in the right order. | |
420 | * https://issues.dlang.org/show_bug.cgi?id=17947 | |
421 | */ | |
422 | append(si); | |
423 | } | |
424 | } | |
425 | } | |
426 | ||
427 | void cpp_mangle_name(Dsymbol *s, bool qualified) | |
428 | { | |
429 | //printf("cpp_mangle_name(%s, %d)\n", s->toChars(), qualified); | |
430 | Dsymbol *p = s->toParent(); | |
431 | Dsymbol *se = s; | |
432 | bool write_prefix = true; | |
433 | if (p && p->isTemplateInstance()) | |
434 | { | |
435 | se = p; | |
436 | if (find(p->isTemplateInstance()->tempdecl) >= 0) | |
437 | write_prefix = false; | |
438 | p = p->toParent(); | |
439 | } | |
440 | ||
441 | if (p && !p->isModule()) | |
442 | { | |
443 | /* The N..E is not required if: | |
444 | * 1. the parent is 'std' | |
445 | * 2. 'std' is the initial qualifier | |
446 | * 3. there is no CV-qualifier or a ref-qualifier for a member function | |
447 | * ABI 5.1.8 | |
448 | */ | |
449 | if (isStd(p) && !qualified) | |
450 | { | |
451 | TemplateInstance *ti = se->isTemplateInstance(); | |
452 | if (s->ident == Id::allocator) | |
453 | { | |
454 | buf->writestring("Sa"); // "Sa" is short for ::std::allocator | |
455 | template_args(ti); | |
456 | } | |
457 | else if (s->ident == Id::basic_string) | |
458 | { | |
459 | // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>> | |
460 | if (ti->tiargs->dim == 3 && | |
461 | isChar((*ti->tiargs)[0]) && | |
462 | isChar_traits_char((*ti->tiargs)[1]) && | |
463 | isAllocator_char((*ti->tiargs)[2])) | |
464 | ||
465 | { | |
466 | buf->writestring("Ss"); | |
467 | return; | |
468 | } | |
469 | buf->writestring("Sb"); // ::std::basic_string | |
470 | template_args(ti); | |
471 | } | |
472 | else | |
473 | { | |
474 | // ::std::basic_istream<char, ::std::char_traits<char>> | |
475 | if (s->ident == Id::basic_istream) | |
476 | { | |
477 | if (char_std_char_traits_char(ti, "Si")) | |
478 | return; | |
479 | } | |
480 | else if (s->ident == Id::basic_ostream) | |
481 | { | |
482 | if (char_std_char_traits_char(ti, "So")) | |
483 | return; | |
484 | } | |
485 | else if (s->ident == Id::basic_iostream) | |
486 | { | |
487 | if (char_std_char_traits_char(ti, "Sd")) | |
488 | return; | |
489 | } | |
490 | buf->writestring("St"); | |
491 | source_name(se); | |
492 | } | |
493 | } | |
494 | else | |
495 | { | |
496 | buf->writeByte('N'); | |
497 | if (write_prefix) | |
498 | prefix_name(p); | |
499 | source_name(se); | |
500 | buf->writeByte('E'); | |
501 | } | |
502 | } | |
503 | else | |
504 | source_name(se); | |
505 | append(s); | |
506 | } | |
507 | ||
508 | void CV_qualifiers(Type *t) | |
509 | { | |
510 | // CV-qualifiers are 'r': restrict, 'V': volatile, 'K': const | |
511 | if (t->isConst()) | |
512 | buf->writeByte('K'); | |
513 | } | |
514 | ||
515 | void mangle_variable(VarDeclaration *d, bool is_temp_arg_ref) | |
516 | { | |
517 | // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 | |
518 | if (!(d->storage_class & (STCextern | STCfield | STCgshared))) | |
519 | { | |
520 | d->error("Internal Compiler Error: C++ static non-`__gshared` non-`extern` variables not supported"); | |
521 | fatal(); | |
522 | } | |
523 | ||
524 | Dsymbol *p = d->toParent(); | |
525 | if (p && !p->isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" | |
526 | { | |
527 | buf->writestring("_ZN"); | |
528 | prefix_name(p); | |
529 | source_name(d); | |
530 | buf->writeByte('E'); | |
531 | } | |
532 | else //char beta[6] should mangle as "beta" | |
533 | { | |
534 | if (!is_temp_arg_ref) | |
535 | { | |
536 | buf->writestring(d->ident->toChars()); | |
537 | } | |
538 | else | |
539 | { | |
540 | buf->writestring("_Z"); | |
541 | source_name(d); | |
542 | } | |
543 | } | |
544 | } | |
545 | ||
546 | void mangle_function(FuncDeclaration *d) | |
547 | { | |
548 | //printf("mangle_function(%s)\n", d->toChars()); | |
549 | /* | |
550 | * <mangled-name> ::= _Z <encoding> | |
551 | * <encoding> ::= <function name> <bare-function-type> | |
552 | * ::= <data name> | |
553 | * ::= <special-name> | |
554 | */ | |
555 | TypeFunction *tf = (TypeFunction *)d->type; | |
556 | ||
557 | buf->writestring("_Z"); | |
558 | if (getFuncTemplateDecl(d)) | |
559 | { | |
560 | /* It's an instance of a function template | |
561 | */ | |
562 | TemplateInstance *ti = d->parent->isTemplateInstance(); | |
563 | assert(ti); | |
564 | Dsymbol *p = ti->toParent(); | |
565 | if (p && !p->isModule() && tf->linkage == LINKcpp) | |
566 | { | |
567 | buf->writeByte('N'); | |
568 | CV_qualifiers(d->type); | |
569 | prefix_name(p); | |
570 | if (d->isCtorDeclaration()) | |
571 | buf->writestring("C1"); | |
572 | else if (d->isDtorDeclaration()) | |
573 | buf->writestring("D1"); | |
574 | else | |
575 | source_name(ti); | |
576 | buf->writeByte('E'); | |
577 | } | |
578 | else | |
579 | source_name(ti); | |
580 | headOfType(tf->nextOf()); // mangle return type | |
581 | } | |
582 | else | |
583 | { | |
584 | Dsymbol *p = d->toParent(); | |
585 | if (p && !p->isModule() && tf->linkage == LINKcpp) | |
586 | { | |
587 | /* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E | |
588 | * ::= N [<CV-qualifiers>] <template-prefix> <template-args> E | |
589 | */ | |
590 | buf->writeByte('N'); | |
591 | CV_qualifiers(d->type); | |
592 | ||
593 | /* <prefix> ::= <prefix> <unqualified-name> | |
594 | * ::= <template-prefix> <template-args> | |
595 | * ::= <template-param> | |
596 | * ::= # empty | |
597 | * ::= <substitution> | |
598 | * ::= <prefix> <data-member-prefix> | |
599 | */ | |
600 | prefix_name(p); | |
601 | //printf("p: %s\n", buf.peekString()); | |
602 | ||
603 | if (d->isCtorDeclaration()) | |
604 | { | |
605 | buf->writestring("C1"); | |
606 | } | |
607 | else if (d->isDtorDeclaration()) | |
608 | { | |
609 | buf->writestring("D1"); | |
610 | } | |
611 | else | |
612 | { | |
613 | source_name(d); | |
614 | } | |
615 | buf->writeByte('E'); | |
616 | } | |
617 | else | |
618 | { | |
619 | source_name(d); | |
620 | } | |
621 | } | |
622 | ||
623 | if (tf->linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling | |
624 | { | |
625 | assert(tf->ty == Tfunction); | |
626 | mangleFunctionParameters(tf->parameters, tf->varargs); | |
627 | } | |
628 | } | |
629 | ||
630 | void mangleFunctionParameters(Parameters *parameters, int varargs) | |
631 | { | |
632 | struct ParamsCppMangle | |
633 | { | |
634 | int numparams; | |
635 | CppMangleVisitor *mangler; | |
636 | ||
637 | static int dg(void *ctx, size_t, Parameter *fparam) | |
638 | { | |
639 | ParamsCppMangle *p = (ParamsCppMangle *)ctx; | |
640 | CppMangleVisitor *mangler = p->mangler; | |
641 | Type *t = Target::cppParameterType(fparam); | |
642 | if (t->ty == Tsarray) | |
643 | { | |
644 | // Static arrays in D are passed by value; no counterpart in C++ | |
645 | t->error(mangler->loc, "Internal Compiler Error: unable to pass static array `%s` to extern(C++) function, use pointer instead", | |
646 | t->toChars()); | |
647 | fatal(); | |
648 | } | |
649 | mangler->headOfType(t); | |
650 | p->numparams++; | |
651 | return 0; | |
652 | } | |
653 | }; | |
654 | ||
655 | ParamsCppMangle p; | |
656 | p.numparams = 0; | |
657 | p.mangler = this; | |
658 | ||
659 | if (parameters) | |
660 | Parameter_foreach(parameters, &ParamsCppMangle::dg, (void*)&p); | |
661 | ||
662 | if (varargs) | |
663 | buf->writeByte('z'); | |
664 | else if (!p.numparams) | |
665 | buf->writeByte('v'); // encode (void) parameters | |
666 | } | |
667 | ||
668 | public: | |
669 | CppMangleVisitor(OutBuffer *buf, Loc loc) | |
670 | : components(), buf(buf), loc(loc) | |
671 | { | |
672 | } | |
673 | ||
674 | /***** | |
675 | * Entry point. Append mangling to buf[] | |
676 | * Params: | |
677 | * s = symbol to mangle | |
678 | */ | |
679 | void mangleOf(Dsymbol *s) | |
680 | { | |
681 | if (VarDeclaration *vd = s->isVarDeclaration()) | |
682 | { | |
683 | mangle_variable(vd, false); | |
684 | } | |
685 | else if (FuncDeclaration *fd = s->isFuncDeclaration()) | |
686 | { | |
687 | mangle_function(fd); | |
688 | } | |
689 | else | |
690 | { | |
691 | assert(0); | |
692 | } | |
693 | } | |
694 | ||
695 | /****** The rest is type mangling ************/ | |
696 | ||
697 | void error(Type *t) | |
698 | { | |
699 | const char *p; | |
700 | if (t->isImmutable()) | |
701 | p = "`immutable` "; | |
702 | else if (t->isShared()) | |
703 | p = "`shared` "; | |
704 | else | |
705 | p = ""; | |
706 | t->error(loc, "Internal Compiler Error: %stype `%s` can not be mapped to C++", p, t->toChars()); | |
707 | fatal(); //Fatal, because this error should be handled in frontend | |
708 | } | |
709 | ||
710 | /**************************** | |
711 | * Mangle a type, | |
712 | * treating it as a Head followed by a Tail. | |
713 | * Params: | |
714 | * t = Head of a type | |
715 | */ | |
716 | void headOfType(Type *t) | |
717 | { | |
718 | if (t->ty == Tclass) | |
719 | { | |
720 | mangleTypeClass((TypeClass*)t, true); | |
721 | } | |
722 | else | |
723 | { | |
724 | // For value types, strip const/immutable/shared from the head of the type | |
725 | t->mutableOf()->unSharedOf()->accept(this); | |
726 | } | |
727 | } | |
728 | ||
729 | void visit(Type *t) | |
730 | { | |
731 | error(t); | |
732 | } | |
733 | ||
734 | /****** | |
735 | * Write out 1 or 2 character basic type mangling. | |
736 | * Handle const and substitutions. | |
737 | * Params: | |
738 | * t = type to mangle | |
739 | * p = if not 0, then character prefix | |
740 | * c = mangling character | |
741 | */ | |
742 | void writeBasicType(Type *t, char p, char c) | |
743 | { | |
744 | if (p || t->isConst()) | |
745 | { | |
746 | if (substitute(t)) | |
747 | return; | |
748 | else | |
749 | append(t); | |
750 | } | |
751 | CV_qualifiers(t); | |
752 | if (p) | |
753 | buf->writeByte(p); | |
754 | buf->writeByte(c); | |
755 | } | |
756 | ||
757 | void visit(TypeNull *t) | |
758 | { | |
759 | if (t->isImmutable() || t->isShared()) | |
760 | return error(t); | |
761 | ||
762 | writeBasicType(t, 'D', 'n'); | |
763 | } | |
764 | ||
765 | void visit(TypeBasic *t) | |
766 | { | |
767 | if (t->isImmutable() || t->isShared()) | |
768 | return error(t); | |
769 | ||
770 | /* <builtin-type>: | |
771 | * v void | |
772 | * w wchar_t | |
773 | * b bool | |
774 | * c char | |
775 | * a signed char | |
776 | * h unsigned char | |
777 | * s short | |
778 | * t unsigned short | |
779 | * i int | |
780 | * j unsigned int | |
781 | * l long | |
782 | * m unsigned long | |
783 | * x long long, __int64 | |
784 | * y unsigned long long, __int64 | |
785 | * n __int128 | |
786 | * o unsigned __int128 | |
787 | * f float | |
788 | * d double | |
789 | * e long double, __float80 | |
790 | * g __float128 | |
791 | * z ellipsis | |
792 | * Dd 64 bit IEEE 754r decimal floating point | |
793 | * De 128 bit IEEE 754r decimal floating point | |
794 | * Df 32 bit IEEE 754r decimal floating point | |
795 | * Dh 16 bit IEEE 754r half-precision floating point | |
796 | * Di char32_t | |
797 | * Ds char16_t | |
798 | * u <source-name> # vendor extended type | |
799 | */ | |
800 | ||
801 | char c; | |
802 | char p = 0; | |
803 | switch (t->ty) | |
804 | { | |
805 | case Tvoid: c = 'v'; break; | |
806 | case Tint8: c = 'a'; break; | |
807 | case Tuns8: c = 'h'; break; | |
808 | case Tint16: c = 's'; break; | |
809 | case Tuns16: c = 't'; break; | |
810 | case Tint32: c = 'i'; break; | |
811 | case Tuns32: c = 'j'; break; | |
812 | case Tfloat32: c = 'f'; break; | |
813 | case Tint64: | |
814 | c = (Target::c_longsize == 8 ? 'l' : 'x'); | |
815 | break; | |
816 | case Tuns64: | |
817 | c = (Target::c_longsize == 8 ? 'm' : 'y'); | |
818 | break; | |
819 | case Tint128: c = 'n'; break; | |
820 | case Tuns128: c = 'o'; break; | |
821 | case Tfloat64: c = 'd'; break; | |
822 | case Tfloat80: c = 'e'; break; | |
823 | case Tbool: c = 'b'; break; | |
824 | case Tchar: c = 'c'; break; | |
825 | case Twchar: c = 't'; break; // unsigned short (perhaps use 'Ds' ? | |
826 | case Tdchar: c = 'w'; break; // wchar_t (UTF-32) (perhaps use 'Di' ? | |
827 | case Timaginary32: p = 'G'; c = 'f'; break; // 'G' means imaginary | |
828 | case Timaginary64: p = 'G'; c = 'd'; break; | |
829 | case Timaginary80: p = 'G'; c = 'e'; break; | |
830 | case Tcomplex32: p = 'C'; c = 'f'; break; // 'C' means complex | |
831 | case Tcomplex64: p = 'C'; c = 'd'; break; | |
832 | case Tcomplex80: p = 'C'; c = 'e'; break; | |
833 | ||
834 | default: | |
835 | // Handle any target-specific basic types. | |
836 | if (const char *tm = Target::cppTypeMangle(t)) | |
837 | { | |
838 | if (substitute(t)) | |
839 | return; | |
840 | else | |
841 | append(t); | |
842 | CV_qualifiers(t); | |
843 | buf->writestring(tm); | |
844 | return; | |
845 | } | |
846 | return error(t); | |
847 | } | |
848 | writeBasicType(t, p, c); | |
849 | } | |
850 | ||
851 | void visit(TypeVector *t) | |
852 | { | |
853 | if (t->isImmutable() || t->isShared()) | |
854 | return error(t); | |
855 | ||
856 | if (substitute(t)) | |
857 | return; | |
858 | append(t); | |
859 | CV_qualifiers(t); | |
860 | ||
861 | // Handle any target-specific vector types. | |
862 | if (const char *tm = Target::cppTypeMangle(t)) | |
863 | { | |
864 | buf->writestring(tm); | |
865 | } | |
866 | else | |
867 | { | |
868 | assert(t->basetype && t->basetype->ty == Tsarray); | |
869 | assert(((TypeSArray *)t->basetype)->dim); | |
870 | buf->writestring("U8__vector"); //-- Gnu ABI v.3 | |
871 | t->basetype->nextOf()->accept(this); | |
872 | } | |
873 | } | |
874 | ||
875 | void visit(TypeSArray *t) | |
876 | { | |
877 | if (t->isImmutable() || t->isShared()) | |
878 | return error(t); | |
879 | ||
880 | if (!substitute(t)) | |
881 | append(t); | |
882 | CV_qualifiers(t); | |
883 | buf->writeByte('A'); | |
884 | buf->printf("%llu", t->dim ? t->dim->toInteger() : 0); | |
885 | buf->writeByte('_'); | |
886 | t->next->accept(this); | |
887 | } | |
888 | ||
889 | void visit(TypePointer *t) | |
890 | { | |
891 | if (t->isImmutable() || t->isShared()) | |
892 | return error(t); | |
893 | ||
894 | if (substitute(t)) | |
895 | return; | |
896 | CV_qualifiers(t); | |
897 | buf->writeByte('P'); | |
898 | t->next->accept(this); | |
899 | append(t); | |
900 | } | |
901 | ||
902 | void visit(TypeReference *t) | |
903 | { | |
904 | //printf("TypeReference %s\n", t->toChars()); | |
905 | if (substitute(t)) | |
906 | return; | |
907 | buf->writeByte('R'); | |
908 | t->next->accept(this); | |
909 | append(t); | |
910 | } | |
911 | ||
912 | void visit(TypeFunction *t) | |
913 | { | |
914 | /* | |
915 | * <function-type> ::= F [Y] <bare-function-type> E | |
916 | * <bare-function-type> ::= <signature type>+ | |
917 | * # types are possible return type, then parameter types | |
918 | */ | |
919 | ||
920 | /* ABI says: | |
921 | "The type of a non-static member function is considered to be different, | |
922 | for the purposes of substitution, from the type of a namespace-scope or | |
923 | static member function whose type appears similar. The types of two | |
924 | non-static member functions are considered to be different, for the | |
925 | purposes of substitution, if the functions are members of different | |
926 | classes. In other words, for the purposes of substitution, the class of | |
927 | which the function is a member is considered part of the type of | |
928 | function." | |
929 | ||
930 | BUG: Right now, types of functions are never merged, so our simplistic | |
931 | component matcher always finds them to be different. | |
932 | We should use Type::equals on these, and use different | |
933 | TypeFunctions for non-static member functions, and non-static | |
934 | member functions of different classes. | |
935 | */ | |
936 | if (substitute(t)) | |
937 | return; | |
938 | buf->writeByte('F'); | |
939 | if (t->linkage == LINKc) | |
940 | buf->writeByte('Y'); | |
941 | Type *tn = t->next; | |
942 | if (t->isref) | |
943 | tn = tn->referenceTo(); | |
944 | tn->accept(this); | |
945 | mangleFunctionParameters(t->parameters, t->varargs); | |
946 | buf->writeByte('E'); | |
947 | append(t); | |
948 | } | |
949 | ||
950 | void visit(TypeStruct *t) | |
951 | { | |
952 | if (t->isImmutable() || t->isShared()) | |
953 | return error(t); | |
954 | ||
955 | /* __c_long and __c_ulong get special mangling | |
956 | */ | |
957 | Identifier *id = t->sym->ident; | |
958 | //printf("struct id = '%s'\n", id->toChars()); | |
959 | if (id == Id::__c_long) | |
960 | return writeBasicType(t, 0, 'l'); | |
961 | else if (id == Id::__c_ulong) | |
962 | return writeBasicType(t, 0, 'm'); | |
963 | ||
964 | //printf("TypeStruct %s\n", t->toChars()); | |
965 | doSymbol(t); | |
966 | } | |
967 | ||
968 | ||
969 | void visit(TypeEnum *t) | |
970 | { | |
971 | if (t->isImmutable() || t->isShared()) | |
972 | return error(t); | |
973 | ||
974 | /* __c_(u)long(long) get special mangling | |
975 | */ | |
976 | Identifier *id = t->sym->ident; | |
977 | //printf("enum id = '%s'\n", id->toChars()); | |
978 | if (id == Id::__c_long) | |
979 | return writeBasicType(t, 0, 'l'); | |
980 | else if (id == Id::__c_ulong) | |
981 | return writeBasicType(t, 0, 'm'); | |
982 | else if (id == Id::__c_longlong) | |
983 | return writeBasicType(t, 0, 'x'); | |
984 | else if (id == Id::__c_ulonglong) | |
985 | return writeBasicType(t, 0, 'y'); | |
986 | ||
987 | doSymbol(t); | |
988 | } | |
989 | ||
990 | /**************** | |
991 | * Write structs and enums. | |
992 | * Params: | |
993 | * t = TypeStruct or TypeEnum | |
994 | */ | |
995 | void doSymbol(Type *t) | |
996 | { | |
997 | if (substitute(t)) | |
998 | return; | |
999 | CV_qualifiers(t); | |
1000 | ||
1001 | // Handle any target-specific struct types. | |
1002 | if (const char *tm = Target::cppTypeMangle(t)) | |
1003 | { | |
1004 | buf->writestring(tm); | |
1005 | } | |
1006 | else | |
1007 | { | |
1008 | Dsymbol *s = t->toDsymbol(NULL); | |
1009 | Dsymbol *p = s->toParent(); | |
1010 | if (p && p->isTemplateInstance()) | |
1011 | { | |
1012 | /* https://issues.dlang.org/show_bug.cgi?id=17947 | |
1013 | * Substitute the template instance symbol, not the struct/enum symbol | |
1014 | */ | |
1015 | if (substitute(p)) | |
1016 | return; | |
1017 | } | |
1018 | if (!substitute(s)) | |
1019 | { | |
1020 | cpp_mangle_name(s, t->isConst()); | |
1021 | } | |
1022 | } | |
1023 | if (t->isConst()) | |
1024 | append(t); | |
1025 | } | |
1026 | ||
1027 | void visit(TypeClass *t) | |
1028 | { | |
1029 | mangleTypeClass(t, false); | |
1030 | } | |
1031 | ||
1032 | /************************ | |
1033 | * Mangle a class type. | |
1034 | * If it's the head, treat the initial pointer as a value type. | |
1035 | * Params: | |
1036 | * t = class type | |
1037 | * head = true for head of a type | |
1038 | */ | |
1039 | void mangleTypeClass(TypeClass *t, bool head) | |
1040 | { | |
1041 | if (t->isImmutable() || t->isShared()) | |
1042 | return error(t); | |
1043 | ||
1044 | /* Mangle as a <pointer to><struct> | |
1045 | */ | |
1046 | if (substitute(t)) | |
1047 | return; | |
1048 | if (!head) | |
1049 | CV_qualifiers(t); | |
1050 | buf->writeByte('P'); | |
1051 | ||
1052 | CV_qualifiers(t); | |
1053 | ||
1054 | { | |
1055 | Dsymbol *s = t->toDsymbol(NULL); | |
1056 | Dsymbol *p = s->toParent(); | |
1057 | if (p && p->isTemplateInstance()) | |
1058 | { | |
1059 | /* https://issues.dlang.org/show_bug.cgi?id=17947 | |
1060 | * Substitute the template instance symbol, not the class symbol | |
1061 | */ | |
1062 | if (substitute(p)) | |
1063 | return; | |
1064 | } | |
1065 | } | |
1066 | ||
1067 | if (!substitute(t->sym)) | |
1068 | { | |
1069 | cpp_mangle_name(t->sym, t->isConst()); | |
1070 | } | |
1071 | if (t->isConst()) | |
1072 | append(NULL); // C++ would have an extra type here | |
1073 | append(t); | |
1074 | } | |
1075 | ||
1076 | const char *mangle_typeinfo(Dsymbol *s) | |
1077 | { | |
1078 | buf->writestring("_ZTI"); | |
1079 | cpp_mangle_name(s, false); | |
1080 | return buf->extractString(); | |
1081 | } | |
1082 | }; | |
1083 | ||
1084 | const char *toCppMangleItanium(Dsymbol *s) | |
1085 | { | |
1086 | //printf("toCppMangleItanium(%s)\n", s->toChars()); | |
1087 | OutBuffer buf; | |
1088 | CppMangleVisitor v(&buf, s->loc); | |
1089 | v.mangleOf(s); | |
1090 | return buf.extractString(); | |
1091 | } | |
1092 | ||
1093 | const char *cppTypeInfoMangleItanium(Dsymbol *s) | |
1094 | { | |
1095 | //printf("cppTypeInfoMangleItanium(%s)\n", s->toChars()); | |
1096 | OutBuffer buf; | |
1097 | buf.writestring("_ZTI"); // "TI" means typeinfo structure | |
1098 | CppMangleVisitor v(&buf, s->loc); | |
1099 | v.cpp_mangle_name(s, false); | |
1100 | return buf.extractString(); | |
1101 | } |