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