1
/**
2
 * Do mangling for C++ linkage for Digital Mars C++ and Microsoft Visual C++.
3
 *
4
 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5
 * Authors: Walter Bright, http://www.digitalmars.com
6
 * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7
 * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmanglewin.d, _cppmanglewin.d)
8
 * Documentation:  https://dlang.org/phobos/dmd_cppmanglewin.html
9
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cppmanglewin.d
10
 */
11

12
module dmd.cppmanglewin;
13

14
import core.stdc.string;
15
import core.stdc.stdio;
16

17
import dmd.arraytypes;
18
import dmd.cppmangle : isPrimaryDtor, isCppOperator, CppOperator;
19
import dmd.dclass;
20
import dmd.declaration;
21
import dmd.denum : isSpecialEnumIdent;
22
import dmd.dstruct;
23
import dmd.dsymbol;
24
import dmd.dtemplate;
25
import dmd.errors;
26
import dmd.expression;
27
import dmd.func;
28
import dmd.globals;
29
import dmd.id;
30
import dmd.mtype;
31
import dmd.root.outbuffer;
32
import dmd.root.rootobject;
33
import dmd.target;
34
import dmd.tokens;
35
import dmd.typesem;
36
import dmd.visitor;
37

38
extern (C++):
39

40

41
const(char)* toCppMangleMSVC(Dsymbol s)
42
{
43 0
    scope VisualCPPMangler v = new VisualCPPMangler(!global.params.mscoff);
44 0
    return v.mangleOf(s);
45
}
46

47
const(char)* cppTypeInfoMangleMSVC(Dsymbol s)
48
{
49
    //printf("cppTypeInfoMangle(%s)\n", s.toChars());
50 0
    assert(0);
51
}
52

53
/**
54
 * Issues an ICE and returns true if `type` is shared or immutable
55
 *
56
 * Params:
57
 *      type = type to check
58
 *
59
 * Returns:
60
 *      true if type is shared or immutable
61
 *      false otherwise
62
 */
63
private bool checkImmutableShared(Type type)
64
{
65 0
    if (type.isImmutable() || type.isShared())
66
    {
67 0
        error(Loc.initial, "Internal Compiler Error: `shared` or `immutable` types cannot be mapped to C++ (%s)", type.toChars());
68 0
        fatal();
69 0
        return true;
70
    }
71 0
    return false;
72
}
73
private final class VisualCPPMangler : Visitor
74
{
75
    enum VC_SAVED_TYPE_CNT = 10u;
76
    enum VC_SAVED_IDENT_CNT = 10u;
77

78
    alias visit = Visitor.visit;
79
    const(char)*[VC_SAVED_IDENT_CNT] saved_idents;
80
    Type[VC_SAVED_TYPE_CNT] saved_types;
81

82
    // IS_NOT_TOP_TYPE: when we mangling one argument, we can call visit several times (for base types of arg type)
83
    // but we must save only arg type:
84
    // For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int"
85
    // This flag is set up by the visit(NextType, ) function  and should be reset when the arg type output is finished.
86
    // MANGLE_RETURN_TYPE: return type shouldn't be saved and substituted in arguments
87
    // IGNORE_CONST: in some cases we should ignore CV-modifiers.
88
    // ESCAPE: toplevel const non-pointer types need a '$$C' escape in addition to a cv qualifier.
89

90
    enum Flags : int
91
    {
92
        IS_NOT_TOP_TYPE = 0x1,
93
        MANGLE_RETURN_TYPE = 0x2,
94
        IGNORE_CONST = 0x4,
95
        IS_DMC = 0x8,
96
        ESCAPE = 0x10,
97
    }
98

99
    alias IS_NOT_TOP_TYPE = Flags.IS_NOT_TOP_TYPE;
100
    alias MANGLE_RETURN_TYPE = Flags.MANGLE_RETURN_TYPE;
101
    alias IGNORE_CONST = Flags.IGNORE_CONST;
102
    alias IS_DMC = Flags.IS_DMC;
103
    alias ESCAPE = Flags.ESCAPE;
104

105
    int flags;
106
    OutBuffer buf;
107

108 0
    extern (D) this(VisualCPPMangler rvl)
109
    {
110 0
        flags |= (rvl.flags & IS_DMC);
111 0
        memcpy(&saved_idents, &rvl.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT);
112 0
        memcpy(&saved_types, &rvl.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT);
113
    }
114

115
public:
116 0
    extern (D) this(bool isdmc)
117
    {
118 0
        if (isdmc)
119
        {
120 0
            flags |= IS_DMC;
121
        }
122 0
        memset(&saved_idents, 0, (const(char)*).sizeof * VC_SAVED_IDENT_CNT);
123 0
        memset(&saved_types, 0, Type.sizeof * VC_SAVED_TYPE_CNT);
124
    }
125

126
    override void visit(Type type)
127
    {
128 0
        if (checkImmutableShared(type))
129 0
            return;
130

131 0
        error(Loc.initial, "Internal Compiler Error: type `%s` cannot be mapped to C++\n", type.toChars());
132 0
        fatal(); //Fatal, because this error should be handled in frontend
133
    }
134

135
    override void visit(TypeNull type)
136
    {
137 0
        if (checkImmutableShared(type))
138 0
            return;
139 0
        if (checkTypeSaved(type))
140 0
            return;
141

142 0
        buf.writestring("$$T");
143 0
        flags &= ~IS_NOT_TOP_TYPE;
144 0
        flags &= ~IGNORE_CONST;
145
    }
146

147
    override void visit(TypeBasic type)
148
    {
149
        //printf("visit(TypeBasic); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
150 0
        if (checkImmutableShared(type))
151 0
            return;
152

153 0
        if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC)))
154
        {
155 0
            if (checkTypeSaved(type))
156 0
                return;
157
        }
158 0
        if ((type.ty == Tbool) && checkTypeSaved(type)) // try to replace long name with number
159
        {
160 0
            return;
161
        }
162 0
        if (!(flags & IS_DMC))
163
        {
164 0
            switch (type.ty)
165
            {
166 0
            case Tint64:
167 0
            case Tuns64:
168 0
            case Tint128:
169 0
            case Tuns128:
170 0
            case Tfloat80:
171 0
            case Twchar:
172 0
                if (checkTypeSaved(type))
173 0
                    return;
174 0
                break;
175

176 0
            default:
177 0
                break;
178
            }
179
        }
180 0
        mangleModifier(type);
181 0
        switch (type.ty)
182
        {
183 0
        case Tvoid:
184 0
            buf.writeByte('X');
185 0
            break;
186 0
        case Tint8:
187 0
            buf.writeByte('C');
188 0
            break;
189 0
        case Tuns8:
190 0
            buf.writeByte('E');
191 0
            break;
192 0
        case Tint16:
193 0
            buf.writeByte('F');
194 0
            break;
195 0
        case Tuns16:
196 0
            buf.writeByte('G');
197 0
            break;
198 0
        case Tint32:
199 0
            buf.writeByte('H');
200 0
            break;
201 0
        case Tuns32:
202 0
            buf.writeByte('I');
203 0
            break;
204 0
        case Tfloat32:
205 0
            buf.writeByte('M');
206 0
            break;
207 0
        case Tint64:
208 0
            buf.writestring("_J");
209 0
            break;
210 0
        case Tuns64:
211 0
            buf.writestring("_K");
212 0
            break;
213 0
        case Tint128:
214 0
            buf.writestring("_L");
215 0
            break;
216 0
        case Tuns128:
217 0
            buf.writestring("_M");
218 0
            break;
219 0
        case Tfloat64:
220 0
            buf.writeByte('N');
221 0
            break;
222 0
        case Tfloat80:
223 0
            if (flags & IS_DMC)
224 0
                buf.writestring("_Z"); // DigitalMars long double
225
            else
226 0
                buf.writestring("_T"); // Intel long double
227 0
            break;
228 0
        case Tbool:
229 0
            buf.writestring("_N");
230 0
            break;
231 0
        case Tchar:
232 0
            buf.writeByte('D');
233 0
            break;
234 0
        case Twchar:
235 0
            buf.writestring("_S"); // Visual C++ char16_t (since C++11)
236 0
            break;
237 0
        case Tdchar:
238 0
            buf.writestring("_U"); // Visual C++ char32_t (since C++11)
239 0
            break;
240 0
        default:
241 0
            visit(cast(Type)type);
242 0
            return;
243
        }
244 0
        flags &= ~IS_NOT_TOP_TYPE;
245 0
        flags &= ~IGNORE_CONST;
246
    }
247

248
    override void visit(TypeVector type)
249
    {
250
        //printf("visit(TypeVector); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
251 0
        if (checkTypeSaved(type))
252 0
            return;
253 0
        buf.writestring("T__m128@@"); // may be better as __m128i or __m128d?
254 0
        flags &= ~IS_NOT_TOP_TYPE;
255 0
        flags &= ~IGNORE_CONST;
256
    }
257

258
    override void visit(TypeSArray type)
259
    {
260
        // This method can be called only for static variable type mangling.
261
        //printf("visit(TypeSArray); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
262 0
        if (checkTypeSaved(type))
263 0
            return;
264
        // first dimension always mangled as const pointer
265 0
        if (flags & IS_DMC)
266 0
            buf.writeByte('Q');
267
        else
268 0
            buf.writeByte('P');
269 0
        flags |= IS_NOT_TOP_TYPE;
270 0
        assert(type.next);
271 0
        if (type.next.ty == Tsarray)
272
        {
273 0
            mangleArray(cast(TypeSArray)type.next);
274
        }
275
        else
276
        {
277 0
            type.next.accept(this);
278
        }
279
    }
280

281
    // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation)
282
    // There is not way to map int C++ (*arr)[2][1] to D
283
    override void visit(TypePointer type)
284
    {
285
        //printf("visit(TypePointer); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
286 0
        if (checkImmutableShared(type))
287 0
            return;
288

289 0
        assert(type.next);
290 0
        if (type.next.ty == Tfunction)
291
        {
292 0
            const(char)* arg = mangleFunctionType(cast(TypeFunction)type.next); // compute args before checking to save; args should be saved before function type
293
            // If we've mangled this function early, previous call is meaningless.
294
            // However we should do it before checking to save types of function arguments before function type saving.
295
            // If this function was already mangled, types of all it arguments are save too, thus previous can't save
296
            // anything if function is saved.
297 0
            if (checkTypeSaved(type))
298 0
                return;
299 0
            if (type.isConst())
300 0
                buf.writeByte('Q'); // const
301
            else
302 0
                buf.writeByte('P'); // mutable
303 0
            buf.writeByte('6'); // pointer to a function
304 0
            buf.writestring(arg);
305 0
            flags &= ~IS_NOT_TOP_TYPE;
306 0
            flags &= ~IGNORE_CONST;
307 0
            return;
308
        }
309 0
        else if (type.next.ty == Tsarray)
310
        {
311 0
            if (checkTypeSaved(type))
312 0
                return;
313 0
            mangleModifier(type);
314 0
            if (type.isConst() || !(flags & IS_DMC))
315 0
                buf.writeByte('Q'); // const
316
            else
317 0
                buf.writeByte('P'); // mutable
318 0
            if (global.params.is64bit)
319 0
                buf.writeByte('E');
320 0
            flags |= IS_NOT_TOP_TYPE;
321 0
            mangleArray(cast(TypeSArray)type.next);
322 0
            return;
323
        }
324
        else
325
        {
326 0
            if (checkTypeSaved(type))
327 0
                return;
328 0
            mangleModifier(type);
329 0
            if (type.isConst())
330
            {
331 0
                buf.writeByte('Q'); // const
332
            }
333
            else
334
            {
335 0
                buf.writeByte('P'); // mutable
336
            }
337 0
            if (global.params.is64bit)
338 0
                buf.writeByte('E');
339 0
            flags |= IS_NOT_TOP_TYPE;
340 0
            type.next.accept(this);
341
        }
342
    }
343

344
    override void visit(TypeReference type)
345
    {
346
        //printf("visit(TypeReference); type = %s\n", type.toChars());
347 0
        if (checkTypeSaved(type))
348 0
            return;
349

350 0
        if (checkImmutableShared(type))
351 0
            return;
352

353 0
        buf.writeByte('A'); // mutable
354 0
        if (global.params.is64bit)
355 0
            buf.writeByte('E');
356 0
        flags |= IS_NOT_TOP_TYPE;
357 0
        assert(type.next);
358 0
        if (type.next.ty == Tsarray)
359
        {
360 0
            mangleArray(cast(TypeSArray)type.next);
361
        }
362
        else
363
        {
364 0
            type.next.accept(this);
365
        }
366
    }
367

368
    override void visit(TypeFunction type)
369
    {
370 0
        const(char)* arg = mangleFunctionType(type);
371 0
        if ((flags & IS_DMC))
372
        {
373 0
            if (checkTypeSaved(type))
374 0
                return;
375
        }
376
        else
377
        {
378 0
            buf.writestring("$$A6");
379
        }
380 0
        buf.writestring(arg);
381 0
        flags &= ~(IS_NOT_TOP_TYPE | IGNORE_CONST);
382
    }
383

384
    override void visit(TypeStruct type)
385
    {
386 0
        if (checkTypeSaved(type))
387 0
            return;
388
        //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
389 0
        mangleModifier(type);
390 0
        const agg = type.sym.isStructDeclaration();
391 0
        if (type.sym.isUnionDeclaration())
392 0
            buf.writeByte('T');
393
        else
394 0
            buf.writeByte(agg.cppmangle == CPPMANGLE.asClass ? 'V' : 'U');
395 0
        mangleIdent(type.sym);
396 0
        flags &= ~IS_NOT_TOP_TYPE;
397 0
        flags &= ~IGNORE_CONST;
398
    }
399

400
    override void visit(TypeEnum type)
401
    {
402
        //printf("visit(TypeEnum); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
403 0
        const id = type.sym.ident;
404 0
        string c;
405 0
        if (id == Id.__c_long_double)
406 0
            c = "O"; // VC++ long double
407 0
        else if (id == Id.__c_long)
408 0
            c = "J"; // VC++ long
409 0
        else if (id == Id.__c_ulong)
410 0
            c = "K"; // VC++ unsigned long
411 0
        else if (id == Id.__c_longlong)
412 0
            c = "_J"; // VC++ long long
413 0
        else if (id == Id.__c_ulonglong)
414 0
            c = "_K"; // VC++ unsigned long long
415 0
        else if (id == Id.__c_wchar_t)
416
        {
417 0
            c = (flags & IS_DMC) ? "_Y" : "_W";
418
        }
419

420 0
        if (c.length)
421
        {
422 0
            if (checkImmutableShared(type))
423 0
                return;
424

425 0
            if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC)))
426
            {
427 0
                if (checkTypeSaved(type))
428 0
                    return;
429
            }
430 0
            mangleModifier(type);
431 0
            buf.writestring(c);
432
        }
433
        else
434
        {
435 0
            if (checkTypeSaved(type))
436 0
                return;
437 0
            mangleModifier(type);
438 0
            buf.writestring("W4");
439 0
            mangleIdent(type.sym);
440
        }
441 0
        flags &= ~IS_NOT_TOP_TYPE;
442 0
        flags &= ~IGNORE_CONST;
443
    }
444

445
    // D class mangled as pointer to C++ class
446
    // const(Object) mangled as Object const* const
447
    override void visit(TypeClass type)
448
    {
449
        //printf("visit(TypeClass); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
450 0
        if (checkTypeSaved(type))
451 0
            return;
452 0
        if (flags & IS_NOT_TOP_TYPE)
453 0
            mangleModifier(type);
454 0
        if (type.isConst())
455 0
            buf.writeByte('Q');
456
        else
457 0
            buf.writeByte('P');
458 0
        if (global.params.is64bit)
459 0
            buf.writeByte('E');
460 0
        flags |= IS_NOT_TOP_TYPE;
461 0
        mangleModifier(type);
462 0
        const cldecl = type.sym.isClassDeclaration();
463 0
        buf.writeByte(cldecl.cppmangle == CPPMANGLE.asStruct ? 'U' : 'V');
464 0
        mangleIdent(type.sym);
465 0
        flags &= ~IS_NOT_TOP_TYPE;
466 0
        flags &= ~IGNORE_CONST;
467
    }
468

469
    const(char)* mangleOf(Dsymbol s)
470
    {
471 0
        VarDeclaration vd = s.isVarDeclaration();
472 0
        FuncDeclaration fd = s.isFuncDeclaration();
473 0
        if (vd)
474
        {
475 0
            mangleVariable(vd);
476
        }
477 0
        else if (fd)
478
        {
479 0
            mangleFunction(fd);
480
        }
481
        else
482
        {
483 0
            assert(0);
484
        }
485 0
        return buf.extractChars();
486
    }
487

488
private:
489
    void mangleFunction(FuncDeclaration d)
490
    {
491
        // <function mangle> ? <qualified name> <flags> <return type> <arg list>
492 0
        assert(d);
493 0
        buf.writeByte('?');
494 0
        mangleIdent(d);
495 0
        if (d.needThis()) // <flags> ::= <virtual/protection flag> <const/volatile flag> <calling convention flag>
496
        {
497
            // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++
498
            //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n",
499
                //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual);
500 0
            if ((d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) || (d.isDtorDeclaration() && d.parent.isClassDeclaration() && !d.isFinal()))
501
            {
502 0
                switch (d.protection.kind)
503
                {
504 0
                case Prot.Kind.private_:
505 0
                    buf.writeByte('E');
506 0
                    break;
507 0
                case Prot.Kind.protected_:
508 0
                    buf.writeByte('M');
509 0
                    break;
510 0
                default:
511 0
                    buf.writeByte('U');
512 0
                    break;
513
                }
514
            }
515
            else
516
            {
517 0
                switch (d.protection.kind)
518
                {
519 0
                case Prot.Kind.private_:
520 0
                    buf.writeByte('A');
521 0
                    break;
522 0
                case Prot.Kind.protected_:
523 0
                    buf.writeByte('I');
524 0
                    break;
525 0
                default:
526 0
                    buf.writeByte('Q');
527 0
                    break;
528
                }
529
            }
530 0
            if (global.params.is64bit)
531 0
                buf.writeByte('E');
532 0
            if (d.type.isConst())
533
            {
534 0
                buf.writeByte('B');
535
            }
536
            else
537
            {
538 0
                buf.writeByte('A');
539
            }
540
        }
541 0
        else if (d.isMember2()) // static function
542
        {
543
            // <flags> ::= <virtual/protection flag> <calling convention flag>
544 0
            switch (d.protection.kind)
545
            {
546 0
            case Prot.Kind.private_:
547 0
                buf.writeByte('C');
548 0
                break;
549 0
            case Prot.Kind.protected_:
550 0
                buf.writeByte('K');
551 0
                break;
552 0
            default:
553 0
                buf.writeByte('S');
554 0
                break;
555
            }
556
        }
557
        else // top-level function
558
        {
559
            // <flags> ::= Y <calling convention flag>
560 0
            buf.writeByte('Y');
561
        }
562 0
        const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || isPrimaryDtor(d));
563 0
        buf.writestring(args);
564
    }
565

566
    void mangleVariable(VarDeclaration d)
567
    {
568
        // <static variable mangle> ::= ? <qualified name> <protection flag> <const/volatile flag> <type>
569 0
        assert(d);
570
        // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525
571 0
        if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared)))
572
        {
573 0
            d.error("Internal Compiler Error: C++ static non-__gshared non-extern variables not supported");
574 0
            fatal();
575
        }
576 0
        buf.writeByte('?');
577 0
        mangleIdent(d);
578 0
        assert((d.storage_class & STC.field) || !d.needThis());
579 0
        Dsymbol parent = d.toParent();
580 0
        while (parent && parent.isNspace())
581
        {
582 0
            parent = parent.toParent();
583
        }
584 0
        if (parent && parent.isModule()) // static member
585
        {
586 0
            buf.writeByte('3');
587
        }
588
        else
589
        {
590 0
            switch (d.protection.kind)
591
            {
592 0
            case Prot.Kind.private_:
593 0
                buf.writeByte('0');
594 0
                break;
595 0
            case Prot.Kind.protected_:
596 0
                buf.writeByte('1');
597 0
                break;
598 0
            default:
599 0
                buf.writeByte('2');
600 0
                break;
601
            }
602
        }
603 0
        char cv_mod = 0;
604 0
        Type t = d.type;
605

606 0
        if (checkImmutableShared(t))
607 0
            return;
608

609 0
        if (t.isConst())
610
        {
611 0
            cv_mod = 'B'; // const
612
        }
613
        else
614
        {
615 0
            cv_mod = 'A'; // mutable
616
        }
617 0
        if (t.ty != Tpointer)
618 0
            t = t.mutableOf();
619 0
        t.accept(this);
620 0
        if ((t.ty == Tpointer || t.ty == Treference || t.ty == Tclass) && global.params.is64bit)
621
        {
622 0
            buf.writeByte('E');
623
        }
624 0
        buf.writeByte(cv_mod);
625
    }
626

627
    /**
628
     * Computes mangling for symbols with special mangling.
629
     * Params:
630
     *      sym = symbol to mangle
631
     * Returns:
632
     *      mangling for special symbols,
633
     *      null if not a special symbol
634
     */
635
    extern (D) static string mangleSpecialName(Dsymbol sym)
636
    {
637 0
        string mangle;
638 0
        if (sym.isCtorDeclaration())
639 0
            mangle = "?0";
640 0
        else if (sym.isPrimaryDtor())
641 0
            mangle = "?1";
642 0
        else if (!sym.ident)
643 0
            return null;
644 0
        else if (sym.ident == Id.assign)
645 0
            mangle = "?4";
646 0
        else if (sym.ident == Id.eq)
647 0
            mangle = "?8";
648 0
        else if (sym.ident == Id.index)
649 0
            mangle = "?A";
650 0
        else if (sym.ident == Id.call)
651 0
            mangle = "?R";
652 0
        else if (sym.ident == Id.cppdtor)
653 0
            mangle = "?_G";
654
        else
655 0
            return null;
656

657 0
        return mangle;
658
    }
659

660
    /**
661
     * Mangles an operator, if any
662
     *
663
     * Params:
664
     *      ti                  = associated template instance of the operator
665
     *      symName             = symbol name
666
     *      firstTemplateArg    = index if the first argument of the template (because the corresponding c++ operator is not a template)
667
     * Returns:
668
     *      true if sym has no further mangling needed
669
     *      false otherwise
670
     */
671
    bool mangleOperator(TemplateInstance ti, ref const(char)* symName, ref int firstTemplateArg)
672
    {
673 0
        auto whichOp = isCppOperator(ti.name);
674 0
        final switch (whichOp)
675
        {
676 0
        case CppOperator.Unknown:
677 0
            return false;
678 0
        case CppOperator.Cast:
679 0
            buf.writestring("?B");
680 0
            return true;
681 0
        case CppOperator.Assign:
682 0
            symName = "?4";
683 0
            return false;
684 0
        case CppOperator.Eq:
685 0
            symName = "?8";
686 0
            return false;
687 0
        case CppOperator.Index:
688 0
            symName = "?A";
689 0
            return false;
690 0
        case CppOperator.Call:
691 0
            symName = "?R";
692 0
            return false;
693

694 0
        case CppOperator.Unary:
695 0
        case CppOperator.Binary:
696 0
        case CppOperator.OpAssign:
697 0
            TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
698 0
            assert(td);
699 0
            assert(ti.tiargs.dim >= 1);
700 0
            TemplateParameter tp = (*td.parameters)[0];
701 0
            TemplateValueParameter tv = tp.isTemplateValueParameter();
702 0
            if (!tv || !tv.valType.isString())
703 0
                return false; // expecting a string argument to operators!
704 0
            Expression exp = (*ti.tiargs)[0].isExpression();
705 0
            StringExp str = exp.toStringExp();
706 0
            switch (whichOp)
707
            {
708 0
            case CppOperator.Unary:
709 0
                switch (str.peekString())
710
                {
711 0
                    case "*":   symName = "?D";     goto continue_template;
712 0
                    case "++":  symName = "?E";     goto continue_template;
713 0
                    case "--":  symName = "?F";     goto continue_template;
714 0
                    case "-":   symName = "?G";     goto continue_template;
715 0
                    case "+":   symName = "?H";     goto continue_template;
716 0
                    case "~":   symName = "?S";     goto continue_template;
717 0
                    default:    return false;
718
                }
719 0
            case CppOperator.Binary:
720 0
                switch (str.peekString())
721
                {
722 0
                    case ">>":  symName = "?5";     goto continue_template;
723 0
                    case "<<":  symName = "?6";     goto continue_template;
724 0
                    case "*":   symName = "?D";     goto continue_template;
725 0
                    case "-":   symName = "?G";     goto continue_template;
726 0
                    case "+":   symName = "?H";     goto continue_template;
727 0
                    case "&":   symName = "?I";     goto continue_template;
728 0
                    case "/":   symName = "?K";     goto continue_template;
729 0
                    case "%":   symName = "?L";     goto continue_template;
730 0
                    case "^":   symName = "?T";     goto continue_template;
731 0
                    case "|":   symName = "?U";     goto continue_template;
732 0
                    default:    return false;
733
                    }
734 0
            case CppOperator.OpAssign:
735 0
                switch (str.peekString())
736
                {
737 0
                    case "*":   symName = "?X";     goto continue_template;
738 0
                    case "+":   symName = "?Y";     goto continue_template;
739 0
                    case "-":   symName = "?Z";     goto continue_template;
740 0
                    case "/":   symName = "?_0";    goto continue_template;
741 0
                    case "%":   symName = "?_1";    goto continue_template;
742 0
                    case ">>":  symName = "?_2";    goto continue_template;
743 0
                    case "<<":  symName = "?_3";    goto continue_template;
744 0
                    case "&":   symName = "?_4";    goto continue_template;
745 0
                    case "|":   symName = "?_5";    goto continue_template;
746 0
                    case "^":   symName = "?_6";    goto continue_template;
747 0
                    default:    return false;
748
                }
749 0
            default: assert(0);
750
            }
751
        }
752
        continue_template:
753 0
        if (ti.tiargs.dim == 1)
754
        {
755 0
            buf.writestring(symName);
756 0
            return true;
757
        }
758 0
        firstTemplateArg = 1;
759 0
        return false;
760
    }
761

762
    /**
763
     * Mangles a template value
764
     *
765
     * Params:
766
     *      o               = expression that represents the value
767
     *      tv              = template value
768
     *      is_dmc_template = use DMC mangling
769
     */
770
    void manlgeTemplateValue(RootObject o,TemplateValueParameter tv, Dsymbol sym,bool is_dmc_template)
771
    {
772 0
        if (!tv.valType.isintegral())
773
        {
774 0
            sym.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars());
775 0
            fatal();
776 0
            return;
777
        }
778 0
        buf.writeByte('$');
779 0
        buf.writeByte('0');
780 0
        Expression e = isExpression(o);
781 0
        assert(e);
782 0
        if (tv.valType.isunsigned())
783
        {
784 0
            mangleNumber(e.toUInteger());
785
        }
786 0
        else if (is_dmc_template)
787
        {
788
            // NOTE: DMC mangles everything based on
789
            // unsigned int
790 0
            mangleNumber(e.toInteger());
791
        }
792
        else
793
        {
794 0
            sinteger_t val = e.toInteger();
795 0
            if (val < 0)
796
            {
797 0
                val = -val;
798 0
                buf.writeByte('?');
799
            }
800 0
            mangleNumber(val);
801
        }
802
    }
803

804
    /**
805
     * Mangles a template alias parameter
806
     *
807
     * Params:
808
     *      o   = the alias value, a symbol or expression
809
     */
810
    void mangleTemplateAlias(RootObject o, Dsymbol sym)
811
    {
812 0
        Dsymbol d = isDsymbol(o);
813 0
        Expression e = isExpression(o);
814

815 0
        if (d && d.isFuncDeclaration())
816
        {
817 0
            buf.writeByte('$');
818 0
            buf.writeByte('1');
819 0
            mangleFunction(d.isFuncDeclaration());
820
        }
821 0
        else if (e && e.op == TOK.variable && (cast(VarExp)e).var.isVarDeclaration())
822
        {
823 0
            buf.writeByte('$');
824 0
            if (flags & IS_DMC)
825 0
                buf.writeByte('1');
826
            else
827 0
                buf.writeByte('E');
828 0
            mangleVariable((cast(VarExp)e).var.isVarDeclaration());
829
        }
830 0
        else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember)
831
        {
832 0
            Dsymbol ds = d.isTemplateDeclaration().onemember;
833 0
            if (flags & IS_DMC)
834
            {
835 0
                buf.writeByte('V');
836
            }
837
            else
838
            {
839 0
                if (ds.isUnionDeclaration())
840
                {
841 0
                    buf.writeByte('T');
842
                }
843 0
                else if (ds.isStructDeclaration())
844
                {
845 0
                    buf.writeByte('U');
846
                }
847 0
                else if (ds.isClassDeclaration())
848
                {
849 0
                    buf.writeByte('V');
850
                }
851
                else
852
                {
853 0
                    sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters");
854 0
                    fatal();
855
                }
856
            }
857 0
            mangleIdent(d);
858
        }
859
        else
860
        {
861 0
            sym.error("Internal Compiler Error: `%s` is unsupported parameter for C++ template", o.toChars());
862 0
            fatal();
863
        }
864
    }
865

866
    /**
867
     * Mangles a template alias parameter
868
     *
869
     * Params:
870
     *      o   = type
871
     */
872
    void mangleTemplateType(RootObject o)
873
    {
874 0
        flags |= ESCAPE;
875 0
        Type t = isType(o);
876 0
        assert(t);
877 0
        t.accept(this);
878 0
        flags &= ~ESCAPE;
879
    }
880

881
    /**
882
     * Mangles the name of a symbol
883
     *
884
     * Params:
885
     *      sym   = symbol to mangle
886
     *      dont_use_back_reference = dont use back referencing
887
     */
888
    void mangleName(Dsymbol sym, bool dont_use_back_reference)
889
    {
890
        //printf("mangleName('%s')\n", sym.toChars());
891 0
        const(char)* name = null;
892 0
        bool is_dmc_template = false;
893

894 0
        if (string s = mangleSpecialName(sym))
895
        {
896 0
            buf.writestring(s);
897 0
            return;
898
        }
899

900 0
        if (TemplateInstance ti = sym.isTemplateInstance())
901
        {
902 0
            auto id = ti.tempdecl.ident;
903 0
            const(char)* symName = id.toChars();
904

905 0
            int firstTemplateArg = 0;
906

907
            // test for special symbols
908 0
            if (mangleOperator(ti,symName,firstTemplateArg))
909 0
                return;
910

911 0
            scope VisualCPPMangler tmp = new VisualCPPMangler((flags & IS_DMC) ? true : false);
912 0
            tmp.buf.writeByte('?');
913 0
            tmp.buf.writeByte('$');
914 0
            tmp.buf.writestring(symName);
915 0
            tmp.saved_idents[0] = symName;
916 0
            if (symName == id.toChars())
917 0
                tmp.buf.writeByte('@');
918 0
            if (flags & IS_DMC)
919
            {
920 0
                tmp.mangleIdent(sym.parent, true);
921 0
                is_dmc_template = true;
922
            }
923 0
            bool is_var_arg = false;
924 0
            for (size_t i = firstTemplateArg; i < ti.tiargs.dim; i++)
925
            {
926 0
                RootObject o = (*ti.tiargs)[i];
927 0
                TemplateParameter tp = null;
928 0
                TemplateValueParameter tv = null;
929 0
                TemplateTupleParameter tt = null;
930 0
                if (!is_var_arg)
931
                {
932 0
                    TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
933 0
                    assert(td);
934 0
                    tp = (*td.parameters)[i];
935 0
                    tv = tp.isTemplateValueParameter();
936 0
                    tt = tp.isTemplateTupleParameter();
937
                }
938 0
                if (tt)
939
                {
940 0
                    is_var_arg = true;
941 0
                    tp = null;
942
                }
943 0
                if (tv)
944
                {
945 0
                    tmp.manlgeTemplateValue(o, tv, sym, is_dmc_template);
946
                }
947 0
                else if (!tp || tp.isTemplateTypeParameter())
948
                {
949 0
                    tmp.mangleTemplateType(o);
950
                }
951 0
                else if (tp.isTemplateAliasParameter())
952
                {
953 0
                    tmp.mangleTemplateAlias(o, sym);
954
                }
955
                else
956
                {
957 0
                    sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters");
958 0
                    fatal();
959
                }
960
            }
961 0
            name = tmp.buf.extractChars();
962
        }
963
        else
964
        {
965
            // Not a template
966 0
            name = sym.ident.toChars();
967
        }
968 0
        assert(name);
969 0
        if (is_dmc_template)
970
        {
971 0
            if (checkAndSaveIdent(name))
972 0
                return;
973
        }
974
        else
975
        {
976 0
            if (dont_use_back_reference)
977
            {
978 0
                saveIdent(name);
979
            }
980
            else
981
            {
982 0
                if (checkAndSaveIdent(name))
983 0
                    return;
984
            }
985
        }
986 0
        buf.writestring(name);
987 0
        buf.writeByte('@');
988
    }
989

990
    // returns true if name already saved
991
    bool checkAndSaveIdent(const(char)* name)
992
    {
993 0
        foreach (i; 0 .. VC_SAVED_IDENT_CNT)
994
        {
995 0
            if (!saved_idents[i]) // no saved same name
996
            {
997 0
                saved_idents[i] = name;
998 0
                break;
999
            }
1000 0
            if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name
1001
            {
1002 0
                buf.writeByte(i + '0');
1003 0
                return true;
1004
            }
1005
        }
1006 0
        return false;
1007
    }
1008

1009
    void saveIdent(const(char)* name)
1010
    {
1011 0
        foreach (i; 0 .. VC_SAVED_IDENT_CNT)
1012
        {
1013 0
            if (!saved_idents[i]) // no saved same name
1014
            {
1015 0
                saved_idents[i] = name;
1016 0
                break;
1017
            }
1018 0
            if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name
1019
            {
1020 0
                return;
1021
            }
1022
        }
1023
    }
1024

1025
    void mangleIdent(Dsymbol sym, bool dont_use_back_reference = false)
1026
    {
1027
        // <qualified name> ::= <sub-name list> @
1028
        // <sub-name list>  ::= <sub-name> <name parts>
1029
        //                  ::= <sub-name>
1030
        // <sub-name> ::= <identifier> @
1031
        //            ::= ?$ <identifier> @ <template args> @
1032
        //            :: <back reference>
1033
        // <back reference> ::= 0-9
1034
        // <template args> ::= <template arg> <template args>
1035
        //                ::= <template arg>
1036
        // <template arg>  ::= <type>
1037
        //                ::= $0<encoded integral number>
1038
        //printf("mangleIdent('%s')\n", sym.toChars());
1039 0
        Dsymbol p = sym;
1040 0
        if (p.toParent() && p.toParent().isTemplateInstance())
1041
        {
1042 0
            p = p.toParent();
1043
        }
1044 0
        while (p && !p.isModule())
1045
        {
1046 0
            mangleName(p, dont_use_back_reference);
1047
            // Mangle our string namespaces as well
1048 0
            for (auto ns = p.cppnamespace; ns !is null; ns = ns.cppnamespace)
1049 0
                mangleName(ns, dont_use_back_reference);
1050 0
            p = p.toParent();
1051 0
            if (p.toParent() && p.toParent().isTemplateInstance())
1052
            {
1053 0
                p = p.toParent();
1054
            }
1055
        }
1056 0
        if (!dont_use_back_reference)
1057 0
            buf.writeByte('@');
1058
    }
1059

1060
    void mangleNumber(dinteger_t num)
1061
    {
1062 0
        if (!num) // 0 encoded as "A@"
1063
        {
1064 0
            buf.writeByte('A');
1065 0
            buf.writeByte('@');
1066 0
            return;
1067
        }
1068 0
        if (num <= 10) // 5 encoded as "4"
1069
        {
1070 0
            buf.writeByte(cast(char)(num - 1 + '0'));
1071 0
            return;
1072
        }
1073 0
        char[17] buff;
1074 0
        buff[16] = 0;
1075 0
        size_t i = 16;
1076 0
        while (num)
1077
        {
1078 0
            --i;
1079 0
            buff[i] = num % 16 + 'A';
1080 0
            num /= 16;
1081
        }
1082 0
        buf.writestring(&buff[i]);
1083 0
        buf.writeByte('@');
1084
    }
1085

1086
    bool checkTypeSaved(Type type)
1087
    {
1088 0
        if (flags & IS_NOT_TOP_TYPE)
1089 0
            return false;
1090 0
        if (flags & MANGLE_RETURN_TYPE)
1091 0
            return false;
1092 0
        for (uint i = 0; i < VC_SAVED_TYPE_CNT; i++)
1093
        {
1094 0
            if (!saved_types[i]) // no saved same type
1095
            {
1096 0
                saved_types[i] = type;
1097 0
                return false;
1098
            }
1099 0
            if (saved_types[i].equals(type)) // ok, we've found same type. use index instead of type
1100
            {
1101 0
                buf.writeByte(i + '0');
1102 0
                flags &= ~IS_NOT_TOP_TYPE;
1103 0
                flags &= ~IGNORE_CONST;
1104 0
                return true;
1105
            }
1106
        }
1107 0
        return false;
1108
    }
1109

1110
    void mangleModifier(Type type)
1111
    {
1112 0
        if (flags & IGNORE_CONST)
1113 0
            return;
1114 0
        if (checkImmutableShared(type))
1115 0
            return;
1116

1117 0
        if (type.isConst())
1118
        {
1119
            // Template parameters that are not pointers and are const need an $$C escape
1120
            // in addition to 'B' (const).
1121 0
            if ((flags & ESCAPE) && type.ty != Tpointer)
1122 0
                buf.writestring("$$CB");
1123 0
            else if (flags & IS_NOT_TOP_TYPE)
1124 0
                buf.writeByte('B'); // const
1125 0
            else if ((flags & IS_DMC) && type.ty != Tpointer)
1126 0
                buf.writestring("_O");
1127
        }
1128 0
        else if (flags & IS_NOT_TOP_TYPE)
1129 0
            buf.writeByte('A'); // mutable
1130

1131 0
        flags &= ~ESCAPE;
1132
    }
1133

1134
    void mangleArray(TypeSArray type)
1135
    {
1136 0
        mangleModifier(type);
1137 0
        size_t i = 0;
1138 0
        Type cur = type;
1139 0
        while (cur && cur.ty == Tsarray)
1140
        {
1141 0
            i++;
1142 0
            cur = cur.nextOf();
1143
        }
1144 0
        buf.writeByte('Y');
1145 0
        mangleNumber(i); // count of dimensions
1146 0
        cur = type;
1147 0
        while (cur && cur.ty == Tsarray) // sizes of dimensions
1148
        {
1149 0
            TypeSArray sa = cast(TypeSArray)cur;
1150 0
            mangleNumber(sa.dim ? sa.dim.toInteger() : 0);
1151 0
            cur = cur.nextOf();
1152
        }
1153 0
        flags |= IGNORE_CONST;
1154 0
        cur.accept(this);
1155
    }
1156

1157
    const(char)* mangleFunctionType(TypeFunction type, bool needthis = false, bool noreturn = false)
1158
    {
1159 0
        scope VisualCPPMangler tmp = new VisualCPPMangler(this);
1160
        // Calling convention
1161 0
        if (global.params.is64bit) // always Microsoft x64 calling convention
1162
        {
1163 0
            tmp.buf.writeByte('A');
1164
        }
1165
        else
1166
        {
1167 0
            final switch (type.linkage)
1168
            {
1169 0
            case LINK.c:
1170 0
                tmp.buf.writeByte('A');
1171 0
                break;
1172 0
            case LINK.cpp:
1173 0
                if (needthis && type.parameterList.varargs != VarArg.variadic)
1174 0
                    tmp.buf.writeByte('E'); // thiscall
1175
                else
1176 0
                    tmp.buf.writeByte('A'); // cdecl
1177 0
                break;
1178 0
            case LINK.windows:
1179 0
                tmp.buf.writeByte('G'); // stdcall
1180 0
                break;
1181 0
            case LINK.pascal:
1182 0
                tmp.buf.writeByte('C');
1183 0
                break;
1184 0
            case LINK.d:
1185 0
            case LINK.default_:
1186 0
            case LINK.system:
1187 0
            case LINK.objc:
1188 0
                tmp.visit(cast(Type)type);
1189 0
                break;
1190
            }
1191
        }
1192 0
        tmp.flags &= ~IS_NOT_TOP_TYPE;
1193 0
        if (noreturn)
1194
        {
1195 0
            tmp.buf.writeByte('@');
1196
        }
1197
        else
1198
        {
1199 0
            Type rettype = type.next;
1200 0
            if (type.isref)
1201 0
                rettype = rettype.referenceTo();
1202 0
            flags &= ~IGNORE_CONST;
1203 0
            if (rettype.ty == Tstruct)
1204
            {
1205 0
                tmp.buf.writeByte('?');
1206 0
                tmp.buf.writeByte('A');
1207
            }
1208 0
            else if (rettype.ty == Tenum)
1209
            {
1210 0
                const id = rettype.toDsymbol(null).ident;
1211 0
                if (!isSpecialEnumIdent(id))
1212
                {
1213 0
                    tmp.buf.writeByte('?');
1214 0
                    tmp.buf.writeByte('A');
1215
                }
1216
            }
1217 0
            tmp.flags |= MANGLE_RETURN_TYPE;
1218 0
            rettype.accept(tmp);
1219 0
            tmp.flags &= ~MANGLE_RETURN_TYPE;
1220
        }
1221 0
        if (!type.parameterList.parameters || !type.parameterList.parameters.dim)
1222
        {
1223 0
            if (type.parameterList.varargs == VarArg.variadic)
1224 0
                tmp.buf.writeByte('Z');
1225
            else
1226 0
                tmp.buf.writeByte('X');
1227
        }
1228
        else
1229
        {
1230 0
            foreach (n, p; type.parameterList)
1231
            {
1232 0
                Type t = p.type;
1233 0
                if (p.isReference())
1234
                {
1235 0
                    t = t.referenceTo();
1236
                }
1237 0
                else if (p.storageClass & STC.lazy_)
1238
                {
1239
                    // Mangle as delegate
1240 0
                    Type td = new TypeFunction(ParameterList(), t, LINK.d);
1241 0
                    td = new TypeDelegate(td);
1242 0
                    t = merge(t);
1243
                }
1244 0
                if (t.ty == Tsarray)
1245
                {
1246 0
                    error(Loc.initial, "Internal Compiler Error: unable to pass static array to `extern(C++)` function.");
1247 0
                    error(Loc.initial, "Use pointer instead.");
1248 0
                    assert(0);
1249
                }
1250 0
                tmp.flags &= ~IS_NOT_TOP_TYPE;
1251 0
                tmp.flags &= ~IGNORE_CONST;
1252 0
                t.accept(tmp);
1253
            }
1254

1255 0
            if (type.parameterList.varargs == VarArg.variadic)
1256
            {
1257 0
                tmp.buf.writeByte('Z');
1258
            }
1259
            else
1260
            {
1261 0
                tmp.buf.writeByte('@');
1262
            }
1263
        }
1264 0
        tmp.buf.writeByte('Z');
1265 0
        const(char)* ret = tmp.buf.extractChars();
1266 0
        memcpy(&saved_idents, &tmp.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT);
1267 0
        memcpy(&saved_types, &tmp.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT);
1268 0
        return ret;
1269
    }
1270
}

Read our documentation on viewing source code .

Loading