1 /**
2  * Convert a D type to a type the backend understands.
3  *
4  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/toctype.d, _toctype.d)
8  * Documentation:  https://dlang.org/phobos/dmd_toctype.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/toctype.d
10  */
11 
12 module dmd.toctype;
13 
14 import core.stdc.stdio;
15 import core.stdc.stdlib;
16 
17 import dmd.backend.cc : Classsym, Symbol;
18 import dmd.backend.ty;
19 import dmd.backend.type;
20 
21 import dmd.root.rmem;
22 
23 import dmd.astenums;
24 import dmd.declaration;
25 import dmd.denum;
26 import dmd.dmdparams;
27 import dmd.dstruct;
28 import dmd.globals;
29 import dmd.glue;
30 import dmd.id;
31 import dmd.mtype;
32 import dmd.tocvdebug;
33 
34 
35 /*******************
36  * Determine backend tym bits corresponding to MOD
37  * Params:
38  *  mod = mod bits
39  * Returns:
40  *  corresponding tym_t bits
41  */
42 tym_t modToTym(MOD mod) pure
43 {
44     switch (mod)
45     {
46         case 0:
47             return 0;
48 
49         case MODFlags.const_:
50         case MODFlags.wild:
51         case MODFlags.wildconst:
52             return mTYconst;
53 
54         case MODFlags.shared_:
55             return mTYshared;
56 
57         case MODFlags.shared_ | MODFlags.const_:
58         case MODFlags.shared_ | MODFlags.wild:
59         case MODFlags.shared_ | MODFlags.wildconst:
60             return mTYshared | mTYconst;
61 
62         case MODFlags.immutable_:
63             return mTYimmutable;
64 
65         default:
66             assert(0);
67     }
68 }
69 
70 
71 /************************************
72  * Convert front end type `t` to backend type `t.ctype`.
73  * Memoize the result.
74  * Params:
75  *      t = front end `Type`
76  * Returns:
77  *      back end equivalent `type`
78  */
79 extern (C++) type* Type_toCtype(Type t)
80 {
81     if (t.ctype)
82         return t.ctype;
83 
84     static type* visit(Type t)
85     {
86         type* tr = type_fake(totym(t));
87         tr.Tcount++;
88         return tr;
89     }
90 
91     static type* visitSArray(TypeSArray t)
92     {
93         auto ta = type_static_array(t.dim.toInteger(), Type_toCtype(t.next));
94         ta.Tty |= ta.Tnext.Tty & mTYconst;
95         return ta;
96     }
97 
98     static type* visitDArray(TypeDArray t)
99     {
100         type* tr = type_dyn_array(Type_toCtype(t.next));
101         tr.Tident = t.toPrettyChars(true);
102         return tr;
103     }
104 
105     static type* visitAArray(TypeAArray t)
106     {
107         type* tr = type_assoc_array(Type_toCtype(t.index), Type_toCtype(t.next));
108         tr.Tident = t.toPrettyChars(true);
109         return tr;
110     }
111 
112     static type* visitPointer(TypePointer t)
113     {
114         //printf("TypePointer::toCtype() %s\n", t.toChars());
115         return type_pointer(Type_toCtype(t.next));
116     }
117 
118     static type* visitFunction(TypeFunction t)
119     {
120         const nparams = t.parameterList.length;
121         import dmd.common.string : SmallBuffer;
122         type*[10] tmp = void;
123         auto sb = SmallBuffer!(type*)(nparams, tmp[]);
124         type*[] types = sb[];
125 
126         foreach (i; 0 .. nparams)
127         {
128             Parameter p = t.parameterList[i];
129             type* tp = Type_toCtype(p.type);
130             if (p.isReference())
131                 tp = type_allocn(TYnref, tp);
132             else if (p.isLazy())
133             {
134                 // Mangle as delegate
135                 type* tf = type_function(TYnfunc, null, false, tp);
136                 tp = type_delegate(tf);
137                 tp.Tident = t.toPrettyChars(true);
138             }
139             types[i] = tp;
140         }
141         return type_function(totym(t), types, t.parameterList.varargs == VarArg.variadic, Type_toCtype(t.next));
142     }
143 
144     static type* visitDelegate(TypeDelegate t)
145     {
146         type* tr = type_delegate(Type_toCtype(t.next));
147         tr.Tident = t.toPrettyChars(true);
148         return tr;
149     }
150 
151     static type* visitStruct(TypeStruct t)
152     {
153         //printf("TypeStruct::toCtype() '%s'\n", t.sym.toChars());
154         if (t.mod == 0)
155         {
156             // Create a new backend type
157             StructDeclaration sym = t.sym;
158             auto arg1type = sym.argType(0);
159             auto arg2type = sym.argType(1);
160             t.ctype = type_struct_class(sym.toPrettyChars(true), sym.alignsize, sym.structsize, arg1type ? Type_toCtype(arg1type) : null, arg2type ? Type_toCtype(arg2type) : null, sym.isUnionDeclaration() !is null, false, sym.isPOD() != 0, sym.hasNoFields);
161             /* Add in fields of the struct
162              * (after setting ctype to avoid infinite recursion)
163              */
164             if (driverParams.symdebug && !global.errors)
165             {
166                 foreach (v; sym.fields)
167                 {
168                     if (auto bf = v.isBitFieldDeclaration())
169                         symbol_struct_addBitField(cast(Symbol*)t.ctype.Ttag, v.ident.toChars(), Type_toCtype(v.type), v.offset, bf.fieldWidth, bf.bitOffset);
170                     else
171                         symbol_struct_addField(cast(Symbol*)t.ctype.Ttag, v.ident.toChars(), Type_toCtype(v.type), v.offset);
172                 }
173             }
174             else
175             {
176                 foreach (v; sym.fields)
177                 {
178                     if (auto bf = v.isBitFieldDeclaration())
179                     {
180                         symbol_struct_hasBitFields(cast(Symbol*)t.ctype.Ttag);
181                         break;
182                     }
183                 }
184             }
185 
186             if (driverParams.symdebugref)
187                 toDebug(sym);
188 
189             return t.ctype;
190         }
191 
192         // Copy mutable version of backend type and add modifiers
193         type* mctype = Type_toCtype(t.castMod(0));
194         type* tr = type_alloc(tybasic(mctype.Tty));
195         tr.Tcount++;
196         if (tr.Tty == TYstruct)
197         {
198             tr.Ttag = mctype.Ttag; // structure tag name
199         }
200         tr.Tty |= modToTym(t.mod);
201         //printf("t = %p, Tflags = x%x\n", ctype, ctype.Tflags);
202         return tr;
203     }
204 
205     static type* visitEnum(TypeEnum t)
206     {
207         //printf("TypeEnum::toCtype() '%s'\n", t.sym.toChars());
208         if (t.mod == 0)
209         {
210             EnumDeclaration sym = t.sym;
211             auto symMemtype = sym.memtype;
212             if (!symMemtype)
213             {
214                 // https://issues.dlang.org/show_bug.cgi?id=13792
215                 t.ctype = Type_toCtype(Type.tvoid);
216             }
217             else if (sym.ident == Id.__c_long ||
218                      sym.ident == Id.__c_complex_float ||
219                      sym.ident == Id.__c_complex_double ||
220                      sym.ident == Id.__c_complex_real)
221             {
222                 t.ctype = type_fake(totym(t));
223                 t.ctype.Tcount++;
224                 return t.ctype;
225             }
226             else if (symMemtype.toBasetype().ty == Tint32)
227             {
228                 t.ctype = type_enum(sym.toPrettyChars(true), Type_toCtype(symMemtype));
229             }
230             else
231             {
232                 t.ctype = Type_toCtype(symMemtype);
233             }
234 
235             if (driverParams.symdebugref)
236                 toDebug(t.sym);
237 
238             return t.ctype;
239         }
240 
241         // Copy mutable version of backend type and add modifiers
242         type* mctype = Type_toCtype(t.castMod(0));
243         if (tybasic(mctype.Tty) == TYenum)
244         {
245             Classsym* s = mctype.Ttag;
246             assert(s);
247             type* tr = type_allocn(TYenum, mctype.Tnext);
248             tr.Ttag = s; // enum tag name
249             tr.Tcount++;
250             tr.Tty |= modToTym(t.mod);
251             return tr;
252         }
253         //printf("t = %p, Tflags = x%x\n", t, t.Tflags);
254         return mctype;
255     }
256 
257     static type* visitClass(TypeClass t)
258     {
259         if (t.mod == 0)
260         {
261             //printf("TypeClass::toCtype() %s\n", toChars());
262             type* tc = type_struct_class(t.sym.toPrettyChars(true), t.sym.alignsize, t.sym.structsize, null, null, false, true, true, false);
263             t.ctype = type_pointer(tc);
264             /* Add in fields of the class
265              * (after setting ctype to avoid infinite recursion)
266              */
267             if (driverParams.symdebug)
268             {
269                 foreach (v; t.sym.fields)
270                 {
271                     symbol_struct_addField(cast(Symbol*)tc.Ttag, v.ident.toChars(), Type_toCtype(v.type), v.offset);
272                 }
273                 if (auto bc = t.sym.baseClass)
274                 {
275                     auto ptr_to_basetype = Type_toCtype(bc.type);
276                     assert(ptr_to_basetype .Tty == TYnptr);
277                     symbol_struct_addBaseClass(cast(Symbol*)tc.Ttag, ptr_to_basetype.Tnext, 0);
278                 }
279             }
280 
281             if (driverParams.symdebugref)
282                 toDebug(t.sym);
283             return t.ctype;
284         }
285 
286         // Copy mutable version of backend type and add modifiers
287         type* mctype = Type_toCtype(t.castMod(0));
288         type* tr = type_allocn(tybasic(mctype.Tty), mctype.Tnext); // pointer to class instance
289         tr.Tcount++;
290         tr.Tty |= modToTym(t.mod);
291         return tr;
292     }
293 
294     type* tr;
295     switch (t.ty)
296     {
297         default:        tr = visit        (t);                  break;
298         case Tsarray:   tr = visitSArray  (t.isTypeSArray());   break;
299         case Tarray:    tr = visitDArray  (t.isTypeDArray());   break;
300         case Taarray:   tr = visitAArray  (t.isTypeAArray());   break;
301         case Tpointer:  tr = visitPointer (t.isTypePointer());  break;
302         case Tfunction: tr = visitFunction(t.isTypeFunction()); break;
303         case Tdelegate: tr = visitDelegate(t.isTypeDelegate()); break;
304         case Tstruct:   tr = visitStruct  (t.isTypeStruct());   break;
305         case Tenum:     tr = visitEnum    (t.isTypeEnum());     break;
306         case Tclass:    tr = visitClass   (t.isTypeClass());    break;
307     }
308 
309     t.ctype = tr;
310     return tr;
311 }