1 /**
2  * Handles target-specific parameters
3  *
4  * In order to allow for cross compilation, when the compiler produces a binary
5  * for a different platform than it is running on, target information needs
6  * to be abstracted. This is done in this module, primarily through `Target`.
7  *
8  * Note:
9  * While DMD itself does not support cross-compilation, GDC and LDC do.
10  * Hence, this module is (sometimes heavily) modified by them,
11  * and contributors should review how their changes affect them.
12  *
13  * See_Also:
14  * - $(LINK2 https://wiki.osdev.org/Target_Triplet, Target Triplets)
15  * - $(LINK2 https://github.com/ldc-developers/ldc, LDC repository)
16  * - $(LINK2 https://github.com/D-Programming-GDC/gcc, GDC repository)
17  *
18  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
19  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
20  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
21  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d)
22  * Documentation:  https://dlang.org/phobos/dmd_target.html
23  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/target.d
24  */
25 
26 module dmd.target;
27 
28 import dmd.argtypes;
29 import core.stdc.string : strlen;
30 import dmd.cppmangle;
31 import dmd.cppmanglewin;
32 import dmd.dclass;
33 import dmd.declaration;
34 import dmd.dstruct;
35 import dmd.dsymbol;
36 import dmd.expression;
37 import dmd.func;
38 import dmd.globals;
39 import dmd.id;
40 import dmd.identifier;
41 import dmd.mtype;
42 import dmd.typesem;
43 import dmd.tokens : TOK;
44 import dmd.root.ctfloat;
45 import dmd.root.outbuffer;
46 import dmd.root.string : toDString;
47 
48 ////////////////////////////////////////////////////////////////////////////////
49 /**
50  * Describes a back-end target. At present it is incomplete, but in the future
51  * it should grow to contain most or all target machine and target O/S specific
52  * information.
53  *
54  * In many cases, calls to sizeof() can't be used directly for getting data type
55  * sizes since cross compiling is supported and would end up using the host
56  * sizes rather than the target sizes.
57  */
58 extern (C++) struct Target
59 {
60     // D ABI
61     uint ptrsize;             /// size of a pointer in bytes
62     uint realsize;            /// size a real consumes in memory
63     uint realpad;             /// padding added to the CPU real size to bring it up to realsize
64     uint realalignsize;       /// alignment for reals
65     uint classinfosize;       /// size of `ClassInfo`
66     ulong maxStaticDataSize;  /// maximum size of static data
67 
68     /// C ABI
69     TargetC c;
70 
71     /// C++ ABI
72     TargetCPP cpp;
73 
74     /// Objective-C ABI
75     TargetObjC objc;
76 
77     /**
78      * Values representing all properties for floating point types
79      */
80     extern (C++) struct FPTypeProperties(T)
81     {
82         real_t max;                         /// largest representable value that's not infinity
83         real_t min_normal;                  /// smallest representable normalized value that's not 0
84         real_t nan;                         /// NaN value
85         real_t infinity;                    /// infinity value
86         real_t epsilon;                     /// smallest increment to the value 1
87 
88         d_int64 dig = T.dig;                /// number of decimal digits of precision
89         d_int64 mant_dig = T.mant_dig;      /// number of bits in mantissa
90         d_int64 max_exp = T.max_exp;        /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable
91         d_int64 min_exp = T.min_exp;        /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value
92         d_int64 max_10_exp = T.max_10_exp;  /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable)
93         d_int64 min_10_exp = T.min_10_exp;  /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value
94 
95         extern (D) void initialize()
96         {
97             max = T.max;
98             min_normal = T.min_normal;
99             nan = T.nan;
100             infinity = T.infinity;
101             epsilon = T.epsilon;
102         }
103     }
104 
105     FPTypeProperties!float FloatProperties;     ///
106     FPTypeProperties!double DoubleProperties;   ///
107     FPTypeProperties!real_t RealProperties;     ///
108 
109     /**
110      * Initialize the Target
111      */
112     extern (C++) void _init(ref const Param params)
113     {
114         FloatProperties.initialize();
115         DoubleProperties.initialize();
116         RealProperties.initialize();
117 
118         // These have default values for 32 bit code, they get
119         // adjusted for 64 bit code.
120         ptrsize = 4;
121         classinfosize = 0x4C; // 76
122 
123         /* gcc uses int.max for 32 bit compilations, and long.max for 64 bit ones.
124          * Set to int.max for both, because the rest of the compiler cannot handle
125          * 2^64-1 without some pervasive rework. The trouble is that much of the
126          * front and back end uses 32 bit ints for sizes and offsets. Since C++
127          * silently truncates 64 bit ints to 32, finding all these dependencies will be a problem.
128          */
129         maxStaticDataSize = int.max;
130 
131         if (params.isLP64)
132         {
133             ptrsize = 8;
134             classinfosize = 0x98; // 152
135         }
136         if (params.isLinux || params.isFreeBSD || params.isOpenBSD || params.isDragonFlyBSD || params.isSolaris)
137         {
138             realsize = 12;
139             realpad = 2;
140             realalignsize = 4;
141         }
142         else if (params.isOSX)
143         {
144             realsize = 16;
145             realpad = 6;
146             realalignsize = 16;
147         }
148         else if (params.isWindows)
149         {
150             realsize = 10;
151             realpad = 0;
152             realalignsize = 2;
153             if (ptrsize == 4)
154             {
155                 /* Optlink cannot deal with individual data chunks
156                  * larger than 16Mb
157                  */
158                 maxStaticDataSize = 0x100_0000;  // 16Mb
159             }
160         }
161         else
162             assert(0);
163         if (params.is64bit)
164         {
165             if (params.isLinux || params.isFreeBSD || params.isDragonFlyBSD || params.isSolaris)
166             {
167                 realsize = 16;
168                 realpad = 6;
169                 realalignsize = 16;
170             }
171         }
172 
173         c.initialize(params, this);
174         cpp.initialize(params, this);
175         objc.initialize(params, this);
176     }
177 
178     /**
179      * Deinitializes the global state of the compiler.
180      *
181      * This can be used to restore the state set by `_init` to its original
182      * state.
183      */
184     void deinitialize()
185     {
186         this = this.init;
187     }
188 
189     /**
190      * Requested target memory alignment size of the given type.
191      * Params:
192      *      type = type to inspect
193      * Returns:
194      *      alignment in bytes
195      */
196     extern (C++) uint alignsize(Type type)
197     {
198         assert(type.isTypeBasic());
199         switch (type.ty)
200         {
201         case Tfloat80:
202         case Timaginary80:
203         case Tcomplex80:
204             return target.realalignsize;
205         case Tcomplex32:
206             if (global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isOpenBSD ||
207                 global.params.isDragonFlyBSD || global.params.isSolaris)
208                 return 4;
209             break;
210         case Tint64:
211         case Tuns64:
212         case Tfloat64:
213         case Timaginary64:
214         case Tcomplex64:
215             if (global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isOpenBSD ||
216                 global.params.isDragonFlyBSD || global.params.isSolaris)
217                 return global.params.is64bit ? 8 : 4;
218             break;
219         default:
220             break;
221         }
222         return cast(uint)type.size(Loc.initial);
223     }
224 
225     /**
226      * Requested target field alignment size of the given type.
227      * Params:
228      *      type = type to inspect
229      * Returns:
230      *      alignment in bytes
231      */
232     extern (C++) uint fieldalign(Type type)
233     {
234         const size = type.alignsize();
235 
236         if ((global.params.is64bit || global.params.isOSX) && (size == 16 || size == 32))
237             return size;
238 
239         return (8 < size) ? 8 : size;
240     }
241 
242     /**
243      * Size of the target OS critical section.
244      * Returns:
245      *      size in bytes
246      */
247     extern (C++) uint critsecsize()
248     {
249         return c.criticalSectionSize;
250     }
251 
252     /**
253      * Type for the `va_list` type for the target.
254      * NOTE: For Posix/x86_64 this returns the type which will really
255      * be used for passing an argument of type va_list.
256      * Returns:
257      *      `Type` that represents `va_list`.
258      */
259     extern (C++) Type va_listType()
260     {
261         if (global.params.isWindows)
262         {
263             return Type.tchar.pointerTo();
264         }
265         else if (global.params.isLinux || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isDragonFlyBSD ||
266             global.params.isSolaris || global.params.isOSX)
267         {
268             if (global.params.is64bit)
269             {
270                 return (new TypeIdentifier(Loc.initial, Identifier.idPool("__va_list_tag"))).pointerTo();
271             }
272             else
273             {
274                 return Type.tchar.pointerTo();
275             }
276         }
277         else
278         {
279             assert(0);
280         }
281     }
282 
283     /**
284      * Checks whether the target supports a vector type.
285      * Params:
286      *      sz   = vector type size in bytes
287      *      type = vector element type
288      * Returns:
289      *      0   vector type is supported,
290      *      1   vector type is not supported on the target at all
291      *      2   vector element type is not supported
292      *      3   vector size is not supported
293      */
294     extern (C++) int isVectorTypeSupported(int sz, Type type)
295     {
296         if (!isXmmSupported())
297             return 1; // not supported
298 
299         switch (type.ty)
300         {
301         case Tvoid:
302         case Tint8:
303         case Tuns8:
304         case Tint16:
305         case Tuns16:
306         case Tint32:
307         case Tuns32:
308         case Tfloat32:
309         case Tint64:
310         case Tuns64:
311         case Tfloat64:
312             break;
313         default:
314             return 2; // wrong base type
315         }
316         if (sz != 16 && !(global.params.cpu >= CPU.avx && sz == 32))
317             return 3; // wrong size
318         return 0;
319     }
320 
321     /**
322      * Checks whether the target supports the given operation for vectors.
323      * Params:
324      *      type = target type of operation
325      *      op   = the unary or binary op being done on the `type`
326      *      t2   = type of second operand if `op` is a binary operation
327      * Returns:
328      *      true if the operation is supported or type is not a vector
329      */
330     extern (C++) bool isVectorOpSupported(Type type, ubyte op, Type t2 = null)
331     {
332         import dmd.tokens;
333 
334         if (type.ty != Tvector)
335             return true; // not a vector op
336         auto tvec = cast(TypeVector) type;
337 
338         bool supported;
339         switch (op)
340         {
341         case TOK.negate, TOK.uadd:
342             supported = tvec.isscalar();
343             break;
344 
345         case TOK.lessThan, TOK.greaterThan, TOK.lessOrEqual, TOK.greaterOrEqual, TOK.equal, TOK.notEqual, TOK.identity, TOK.notIdentity:
346             supported = false;
347             break;
348 
349         case TOK.leftShift, TOK.leftShiftAssign, TOK.rightShift, TOK.rightShiftAssign, TOK.unsignedRightShift, TOK.unsignedRightShiftAssign:
350             supported = false;
351             break;
352 
353         case TOK.add, TOK.addAssign, TOK.min, TOK.minAssign:
354             supported = tvec.isscalar();
355             break;
356 
357         case TOK.mul, TOK.mulAssign:
358             // only floats and short[8]/ushort[8] (PMULLW)
359             if (tvec.isfloating() || tvec.elementType().size(Loc.initial) == 2 ||
360                 // int[4]/uint[4] with SSE4.1 (PMULLD)
361                 global.params.cpu >= CPU.sse4_1 && tvec.elementType().size(Loc.initial) == 4)
362                 supported = true;
363             else
364                 supported = false;
365             break;
366 
367         case TOK.div, TOK.divAssign:
368             supported = tvec.isfloating();
369             break;
370 
371         case TOK.mod, TOK.modAssign:
372             supported = false;
373             break;
374 
375         case TOK.and, TOK.andAssign, TOK.or, TOK.orAssign, TOK.xor, TOK.xorAssign:
376             supported = tvec.isintegral();
377             break;
378 
379         case TOK.not:
380             supported = false;
381             break;
382 
383         case TOK.tilde:
384             supported = tvec.isintegral();
385             break;
386 
387         case TOK.pow, TOK.powAssign:
388             supported = false;
389             break;
390 
391         default:
392             // import std.stdio : stderr, writeln;
393             // stderr.writeln(op);
394             assert(0, "unhandled op " ~ Token.toString(cast(TOK)op));
395         }
396         return supported;
397     }
398 
399     /**
400      * Default system linkage for the target.
401      * Returns:
402      *      `LINK` to use for `extern(System)`
403      */
404     extern (C++) LINK systemLinkage()
405     {
406         return global.params.isWindows ? LINK.windows : LINK.c;
407     }
408 
409     /**
410      * Describes how an argument type is passed to a function on target.
411      * Params:
412      *      t = type to break down
413      * Returns:
414      *      tuple of types if type is passed in one or more registers
415      *      empty tuple if type is always passed on the stack
416      *      null if the type is a `void` or argtypes aren't supported by the target
417      */
418     extern (C++) TypeTuple toArgTypes(Type t)
419     {
420         if (global.params.is64bit && global.params.isWindows)
421             return null;
422         return .toArgTypes(t);
423     }
424 
425     /**
426      * Determine return style of function - whether in registers or
427      * through a hidden pointer to the caller's stack.
428      * Params:
429      *   tf = function type to check
430      *   needsThis = true if the function type is for a non-static member function
431      * Returns:
432      *   true if return value from function is on the stack
433      */
434     extern (C++) bool isReturnOnStack(TypeFunction tf, bool needsThis)
435     {
436         if (tf.isref)
437         {
438             //printf("  ref false\n");
439             return false;                 // returns a pointer
440         }
441 
442         Type tn = tf.next.toBasetype();
443         //printf("tn = %s\n", tn.toChars());
444         d_uns64 sz = tn.size();
445         Type tns = tn;
446 
447         if (global.params.isWindows && global.params.is64bit)
448         {
449             // http://msdn.microsoft.com/en-us/library/7572ztz4.aspx
450             if (tns.ty == Tcomplex32)
451                 return true;
452             if (tns.isscalar())
453                 return false;
454 
455             tns = tns.baseElemOf();
456             if (tns.ty == Tstruct)
457             {
458                 StructDeclaration sd = (cast(TypeStruct)tns).sym;
459                 if (tf.linkage == LINK.cpp && needsThis)
460                     return true;
461                 if (!sd.isPOD() || sz > 8)
462                     return true;
463                 if (sd.fields.dim == 0)
464                     return true;
465             }
466             if (sz <= 16 && !(sz & (sz - 1)))
467                 return false;
468             return true;
469         }
470         else if (global.params.isWindows && global.params.mscoff)
471         {
472             Type tb = tns.baseElemOf();
473             if (tb.ty == Tstruct)
474             {
475                 if (tf.linkage == LINK.cpp && needsThis)
476                     return true;
477             }
478         }
479 
480     Lagain:
481         if (tns.ty == Tsarray)
482         {
483             tns = tns.baseElemOf();
484             if (tns.ty != Tstruct)
485             {
486     L2:
487                 if (global.params.isLinux && tf.linkage != LINK.d && !global.params.is64bit)
488                 {
489                                                     // 32 bit C/C++ structs always on stack
490                 }
491                 else
492                 {
493                     switch (sz)
494                     {
495                         case 1:
496                         case 2:
497                         case 4:
498                         case 8:
499                             //printf("  sarray false\n");
500                             return false; // return small structs in regs
501                                                 // (not 3 byte structs!)
502                         default:
503                             break;
504                     }
505                 }
506                 //printf("  sarray true\n");
507                 return true;
508             }
509         }
510 
511         if (tns.ty == Tstruct)
512         {
513             StructDeclaration sd = (cast(TypeStruct)tns).sym;
514             if (global.params.isLinux && tf.linkage != LINK.d && !global.params.is64bit)
515             {
516                 //printf("  2 true\n");
517                 return true;            // 32 bit C/C++ structs always on stack
518             }
519             if (global.params.isWindows && tf.linkage == LINK.cpp && !global.params.is64bit &&
520                      sd.isPOD() && sd.ctor)
521             {
522                 // win32 returns otherwise POD structs with ctors via memory
523                 return true;
524             }
525             if (sd.arg1type && !sd.arg2type)
526             {
527                 tns = sd.arg1type;
528                 if (tns.ty != Tstruct)
529                     goto L2;
530                 goto Lagain;
531             }
532             else if (global.params.is64bit && !sd.arg1type && !sd.arg2type)
533                 return true;
534             else if (sd.isPOD())
535             {
536                 switch (sz)
537                 {
538                     case 1:
539                     case 2:
540                     case 4:
541                     case 8:
542                         //printf("  3 false\n");
543                         return false;     // return small structs in regs
544                                             // (not 3 byte structs!)
545                     case 16:
546                         if (!global.params.isWindows && global.params.is64bit)
547                            return false;
548                         break;
549 
550                     default:
551                         break;
552                 }
553             }
554             //printf("  3 true\n");
555             return true;
556         }
557         else if ((global.params.isLinux || global.params.isOSX ||
558                   global.params.isFreeBSD || global.params.isSolaris ||
559                   global.params.isDragonFlyBSD) &&
560                  tf.linkage == LINK.c &&
561                  tns.iscomplex())
562         {
563             if (tns.ty == Tcomplex32)
564                 return false;     // in EDX:EAX, not ST1:ST0
565             else
566                 return true;
567         }
568         else
569         {
570             //assert(sz <= 16);
571             //printf("  4 false\n");
572             return false;
573         }
574     }
575 
576     /***
577      * Determine the size a value of type `t` will be when it
578      * is passed on the function parameter stack.
579      * Params:
580      *  loc = location to use for error messages
581      *  t = type of parameter
582      * Returns:
583      *  size used on parameter stack
584      */
585     extern (C++) ulong parameterSize(const ref Loc loc, Type t)
586     {
587         if (!global.params.is64bit &&
588             (global.params.isFreeBSD || global.params.isOSX))
589         {
590             /* These platforms use clang, which regards a struct
591              * with size 0 as being of size 0 on the parameter stack,
592              * even while sizeof(struct) is 1.
593              * It's an ABI incompatibility with gcc.
594              */
595             if (t.ty == Tstruct)
596             {
597                 auto ts = cast(TypeStruct)t;
598                 if (ts.sym.hasNoFields)
599                     return 0;
600             }
601         }
602         const sz = t.size(loc);
603         return global.params.is64bit ? (sz + 7) & ~7 : (sz + 3) & ~3;
604     }
605 
606     // this guarantees `getTargetInfo` and `allTargetInfos` remain in sync
607     private enum TargetInfoKeys
608     {
609         cppRuntimeLibrary,
610         cppStd,
611         floatAbi,
612         objectFormat,
613     }
614 
615     /**
616      * Get targetInfo by key
617      * Params:
618      *  name = name of targetInfo to get
619      *  loc = location to use for error messages
620      * Returns:
621      *  Expression for the requested targetInfo
622      */
623     extern (C++) Expression getTargetInfo(const(char)* name, const ref Loc loc)
624     {
625         StringExp stringExp(const(char)[] sval)
626         {
627             return new StringExp(loc, sval);
628         }
629 
630         switch (name.toDString) with (TargetInfoKeys)
631         {
632             case objectFormat.stringof:
633                 if (global.params.isWindows)
634                     return stringExp(global.params.mscoff ? "coff" : "omf");
635                 else if (global.params.isOSX)
636                     return stringExp("macho");
637                 else
638                     return stringExp("elf");
639             case floatAbi.stringof:
640                 return stringExp("hard");
641             case cppRuntimeLibrary.stringof:
642                 if (global.params.isWindows)
643                 {
644                     if (global.params.mscoff)
645                         return stringExp(global.params.mscrtlib);
646                     return stringExp("snn");
647                 }
648                 return stringExp("");
649             case cppStd.stringof:
650                 return new IntegerExp(cast(uint)global.params.cplusplus);
651 
652             default:
653                 return null;
654         }
655     }
656 
657     ////////////////////////////////////////////////////////////////////////////
658     /* All functions after this point are extern (D), as they are only relevant
659      * for targets of DMD, and should not be used in front-end code.
660      */
661 
662     /******************
663      * Returns:
664      *  true if xmm usage is supported
665      */
666     extern (D) bool isXmmSupported()
667     {
668         return global.params.is64bit || global.params.isOSX;
669     }
670 
671     /**
672      * Returns:
673      *  true if generating code for POSIX
674      */
675     extern (D) @property bool isPOSIX() scope const nothrow @nogc
676     out(result) { assert(result || global.params.isWindows); }
677     do
678     {
679         return global.params.isLinux
680             || global.params.isOSX
681             || global.params.isFreeBSD
682             || global.params.isOpenBSD
683             || global.params.isDragonFlyBSD
684             || global.params.isSolaris;
685     }
686 }
687 
688 ////////////////////////////////////////////////////////////////////////////////
689 /**
690  * Functions and variables specific to interfacing with extern(C) ABI.
691  */
692 struct TargetC
693 {
694     uint longsize;            /// size of a C `long` or `unsigned long` type
695     uint long_doublesize;     /// size of a C `long double`
696     uint criticalSectionSize; /// size of os critical section
697 
698     extern (D) void initialize(ref const Param params, ref const Target target)
699     {
700         if (params.isLinux || params.isFreeBSD || params.isOpenBSD || params.isDragonFlyBSD || params.isSolaris)
701             longsize = 4;
702         else if (params.isOSX)
703             longsize = 4;
704         else if (params.isWindows)
705             longsize = 4;
706         else
707             assert(0);
708         if (params.is64bit)
709         {
710             if (params.isLinux || params.isFreeBSD || params.isDragonFlyBSD || params.isSolaris)
711                 longsize = 8;
712             else if (params.isOSX)
713                 longsize = 8;
714         }
715         if (params.is64bit && params.isWindows)
716             long_doublesize = 8;
717         else
718             long_doublesize = target.realsize;
719 
720         criticalSectionSize = getCriticalSectionSize(params);
721     }
722 
723     private static uint getCriticalSectionSize(ref const Param params) pure
724     {
725         if (params.isWindows)
726         {
727             // sizeof(CRITICAL_SECTION) for Windows.
728             return params.isLP64 ? 40 : 24;
729         }
730         else if (params.isLinux)
731         {
732             // sizeof(pthread_mutex_t) for Linux.
733             if (params.is64bit)
734                 return params.isLP64 ? 40 : 32;
735             else
736                 return params.isLP64 ? 40 : 24;
737         }
738         else if (params.isFreeBSD)
739         {
740             // sizeof(pthread_mutex_t) for FreeBSD.
741             return params.isLP64 ? 8 : 4;
742         }
743         else if (params.isOpenBSD)
744         {
745             // sizeof(pthread_mutex_t) for OpenBSD.
746             return params.isLP64 ? 8 : 4;
747         }
748         else if (params.isDragonFlyBSD)
749         {
750             // sizeof(pthread_mutex_t) for DragonFlyBSD.
751             return params.isLP64 ? 8 : 4;
752         }
753         else if (params.isOSX)
754         {
755             // sizeof(pthread_mutex_t) for OSX.
756             return params.isLP64 ? 64 : 44;
757         }
758         else if (params.isSolaris)
759         {
760             // sizeof(pthread_mutex_t) for Solaris.
761             return 24;
762         }
763         assert(0);
764     }
765 }
766 
767 ////////////////////////////////////////////////////////////////////////////////
768 /**
769  * Functions and variables specific to interface with extern(C++) ABI.
770  */
771 struct TargetCPP
772 {
773     bool reverseOverloads;    /// set if overloaded functions are grouped and in reverse order (such as in dmc and cl)
774     bool exceptions;          /// set if catching C++ exceptions is supported
775     bool twoDtorInVtable;     /// target C++ ABI puts deleting and non-deleting destructor into vtable
776 
777     extern (D) void initialize(ref const Param params, ref const Target target)
778     {
779         if (params.isLinux || params.isFreeBSD || params.isOpenBSD || params.isDragonFlyBSD || params.isSolaris)
780             twoDtorInVtable = true;
781         else if (params.isOSX)
782             twoDtorInVtable = true;
783         else if (params.isWindows)
784             reverseOverloads = true;
785         else
786             assert(0);
787         exceptions = params.isLinux || params.isFreeBSD ||
788             params.isDragonFlyBSD || params.isOSX;
789     }
790 
791     /**
792      * Mangle the given symbol for C++ ABI.
793      * Params:
794      *      s = declaration with C++ linkage
795      * Returns:
796      *      string mangling of symbol
797      */
798     extern (C++) const(char)* toMangle(Dsymbol s)
799     {
800         static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.DragonFlyBSD || TARGET.Solaris)
801             return toCppMangleItanium(s);
802         else static if (TARGET.Windows)
803             return toCppMangleMSVC(s);
804         else
805             static assert(0, "fix this");
806     }
807 
808     /**
809      * Get RTTI mangling of the given class declaration for C++ ABI.
810      * Params:
811      *      cd = class with C++ linkage
812      * Returns:
813      *      string mangling of C++ typeinfo
814      */
815     extern (C++) const(char)* typeInfoMangle(ClassDeclaration cd)
816     {
817         static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD)
818             return cppTypeInfoMangleItanium(cd);
819         else static if (TARGET.Windows)
820             return cppTypeInfoMangleMSVC(cd);
821         else
822             static assert(0, "fix this");
823     }
824 
825     /**
826      * Gets vendor-specific type mangling for C++ ABI.
827      * Params:
828      *      t = type to inspect
829      * Returns:
830      *      string if type is mangled specially on target
831      *      null if unhandled
832      */
833     extern (C++) const(char)* typeMangle(Type t)
834     {
835         return null;
836     }
837 
838     /**
839      * Get the type that will really be used for passing the given argument
840      * to an `extern(C++)` function.
841      * Params:
842      *      p = parameter to be passed.
843      * Returns:
844      *      `Type` to use for parameter `p`.
845      */
846     extern (C++) Type parameterType(Parameter p)
847     {
848         Type t = p.type.merge2();
849         if (p.storageClass & (STC.out_ | STC.ref_))
850             t = t.referenceTo();
851         else if (p.storageClass & STC.lazy_)
852         {
853             // Mangle as delegate
854             Type td = new TypeFunction(ParameterList(), t, LINK.d);
855             td = new TypeDelegate(td);
856             t = merge(t);
857         }
858         return t;
859     }
860 
861     /**
862      * Checks whether type is a vendor-specific fundamental type.
863      * Params:
864      *      t = type to inspect
865      *      isFundamental = where to store result
866      * Returns:
867      *      true if isFundamental was set by function
868      */
869     extern (C++) bool fundamentalType(const Type t, ref bool isFundamental)
870     {
871         return false;
872     }
873 }
874 
875 ////////////////////////////////////////////////////////////////////////////////
876 /**
877  * Functions and variables specific to interface with extern(Objective-C) ABI.
878  */
879 struct TargetObjC
880 {
881     bool supported;     /// set if compiler can interface with Objective-C
882 
883     extern (D) void initialize(ref const Param params, ref const Target target)
884     {
885         if (params.isOSX && params.is64bit)
886             supported = true;
887     }
888 }
889 
890 ////////////////////////////////////////////////////////////////////////////////
891 extern (C++) __gshared Target target;