1 /**
2  * Convert a D type to a type the backend understands.
3  *
4  * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
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/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.declaration;
24 import dmd.denum;
25 import dmd.dstruct;
26 import dmd.globals;
27 import dmd.glue;
28 import dmd.id;
29 import dmd.mtype;
30 import dmd.tocvdebug;
31 import dmd.visitor;
32 
33 
34 /*******************
35  * Determine backend tym bits corresponding to MOD
36  * Params:
37  *  mod = mod bits
38  * Returns:
39  *  corresponding tym_t bits
40  */
41 tym_t modToTym(MOD mod) pure
42 {
43     switch (mod)
44     {
45         case 0:
46             return 0;
47 
48         case MODFlags.const_:
49         case MODFlags.wild:
50         case MODFlags.wildconst:
51             return mTYconst;
52 
53         case MODFlags.shared_:
54             return mTYshared;
55 
56         case MODFlags.shared_ | MODFlags.const_:
57         case MODFlags.shared_ | MODFlags.wild:
58         case MODFlags.shared_ | MODFlags.wildconst:
59             return mTYshared | mTYconst;
60 
61         case MODFlags.immutable_:
62             return mTYimmutable;
63 
64         default:
65             assert(0);
66     }
67 }
68 
69 
70 /************************************
71  * Convert front end type `t` to backend type `t.ctype`.
72  * Memoize the result.
73  * Params:
74  *      t = front end `Type`
75  * Returns:
76  *      back end equivalent `type`
77  */
78 extern (C++) type* Type_toCtype(Type t)
79 {
80     if (!t.ctype)
81     {
82         scope ToCtypeVisitor v = new ToCtypeVisitor();
83         t.accept(v);
84     }
85     return t.ctype;
86 }
87 
88 private extern (C++) final class ToCtypeVisitor : Visitor
89 {
90     alias visit = Visitor.visit;
91 public:
92     extern (D) this()
93     {
94     }
95 
96     override void visit(Type t)
97     {
98         t.ctype = type_fake(totym(t));
99         t.ctype.Tcount++;
100     }
101 
102     override void visit(TypeSArray t)
103     {
104         t.ctype = type_static_array(t.dim.toInteger(), Type_toCtype(t.next));
105     }
106 
107     override void visit(TypeDArray t)
108     {
109         t.ctype = type_dyn_array(Type_toCtype(t.next));
110         t.ctype.Tident = t.toPrettyChars(true);
111     }
112 
113     override void visit(TypeAArray t)
114     {
115         t.ctype = type_assoc_array(Type_toCtype(t.index), Type_toCtype(t.next));
116         t.ctype.Tident = t.toPrettyChars(true);
117     }
118 
119     override void visit(TypePointer t)
120     {
121         //printf("TypePointer::toCtype() %s\n", t.toChars());
122         t.ctype = type_pointer(Type_toCtype(t.next));
123     }
124 
125     override void visit(TypeFunction t)
126     {
127         const nparams = t.parameterList.length;
128         type*[10] tmp = void;
129         type** ptypes = (nparams <= tmp.length)
130                         ? tmp.ptr
131                         : cast(type**)Mem.check(malloc((type*).sizeof * nparams));
132         type*[] types = ptypes[0 .. nparams];
133 
134         foreach (i; 0 .. nparams)
135         {
136             Parameter p = t.parameterList[i];
137             type* tp = Type_toCtype(p.type);
138             if (p.isReference())
139                 tp = type_allocn(TYnref, tp);
140             else if (p.storageClass & STC.lazy_)
141             {
142                 // Mangle as delegate
143                 type* tf = type_function(TYnfunc, null, false, tp);
144                 tp = type_delegate(tf);
145             }
146             types[i] = tp;
147         }
148         t.ctype = type_function(totym(t), types, t.parameterList.varargs == VarArg.variadic, Type_toCtype(t.next));
149         if (types.ptr != tmp.ptr)
150             free(types.ptr);
151     }
152 
153     override void visit(TypeDelegate t)
154     {
155         t.ctype = type_delegate(Type_toCtype(t.next));
156     }
157 
158     override void visit(TypeStruct t)
159     {
160         //printf("TypeStruct::toCtype() '%s'\n", t.sym.toChars());
161         if (t.mod == 0)
162         {
163             // Create a new backend type
164             StructDeclaration sym = t.sym;
165             auto arg1type = sym.argType(0);
166             auto arg2type = sym.argType(1);
167             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);
168             /* Add in fields of the struct
169              * (after setting ctype to avoid infinite recursion)
170              */
171             if (global.params.symdebug && !global.errors)
172             {
173                 foreach (v; sym.fields)
174                 {
175                     symbol_struct_addField(cast(Symbol*)t.ctype.Ttag, v.ident.toChars(), Type_toCtype(v.type), v.offset);
176                 }
177             }
178 
179             if (global.params.symdebugref)
180                 toDebug(sym);
181 
182             return;
183         }
184 
185         // Copy mutable version of backend type and add modifiers
186         type* mctype = Type_toCtype(t.castMod(0));
187         t.ctype = type_alloc(tybasic(mctype.Tty));
188         t.ctype.Tcount++;
189         if (t.ctype.Tty == TYstruct)
190         {
191             t.ctype.Ttag = mctype.Ttag; // structure tag name
192         }
193         t.ctype.Tty |= modToTym(t.mod);
194         //printf("t = %p, Tflags = x%x\n", ctype, ctype.Tflags);
195     }
196 
197     override void visit(TypeEnum t)
198     {
199         //printf("TypeEnum::toCtype() '%s'\n", t.sym.toChars());
200         if (t.mod == 0)
201         {
202             EnumDeclaration sym = t.sym;
203             auto symMemtype = sym.memtype;
204             if (!symMemtype)
205             {
206                 // https://issues.dlang.org/show_bug.cgi?id=13792
207                 t.ctype = Type_toCtype(Type.tvoid);
208             }
209             else if (sym.ident == Id.__c_long ||
210                      sym.ident == Id.__c_complex_float ||
211                      sym.ident == Id.__c_complex_double ||
212                      sym.ident == Id.__c_complex_real)
213             {
214                 t.ctype = type_fake(totym(t));
215                 t.ctype.Tcount++;
216                 return;
217             }
218             else if (symMemtype.toBasetype().ty == Tint32)
219             {
220                 t.ctype = type_enum(sym.toPrettyChars(true), Type_toCtype(symMemtype));
221             }
222             else
223             {
224                 t.ctype = Type_toCtype(symMemtype);
225             }
226 
227             if (global.params.symdebugref)
228                 toDebug(t.sym);
229 
230             return;
231         }
232 
233         // Copy mutable version of backend type and add modifiers
234         type* mctype = Type_toCtype(t.castMod(0));
235         if (tybasic(mctype.Tty) == TYenum)
236         {
237             Classsym* s = mctype.Ttag;
238             assert(s);
239             t.ctype = type_allocn(TYenum, mctype.Tnext);
240             t.ctype.Ttag = s; // enum tag name
241             t.ctype.Tcount++;
242             t.ctype.Tty |= modToTym(t.mod);
243         }
244         else
245             t.ctype = mctype;
246 
247         //printf("t = %p, Tflags = x%x\n", t, t.Tflags);
248     }
249 
250     override void visit(TypeClass t)
251     {
252         if (t.mod == 0)
253         {
254             //printf("TypeClass::toCtype() %s\n", toChars());
255             type* tc = type_struct_class(t.sym.toPrettyChars(true), t.sym.alignsize, t.sym.structsize, null, null, false, true, true, false);
256             t.ctype = type_pointer(tc);
257             /* Add in fields of the class
258              * (after setting ctype to avoid infinite recursion)
259              */
260             if (global.params.symdebug)
261             {
262                 foreach (v; t.sym.fields)
263                 {
264                     symbol_struct_addField(cast(Symbol*)tc.Ttag, v.ident.toChars(), Type_toCtype(v.type), v.offset);
265                 }
266             }
267 
268             if (global.params.symdebugref)
269                 toDebug(t.sym);
270             return;
271         }
272 
273         // Copy mutable version of backend type and add modifiers
274         type* mctype = Type_toCtype(t.castMod(0));
275         t.ctype = type_allocn(tybasic(mctype.Tty), mctype.Tnext); // pointer to class instance
276         t.ctype.Tcount++;
277         t.ctype.Tty |= modToTym(t.mod);
278     }
279 }