1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _typeinf.d)
9  */
10 
11 module ddmd.typinf;
12 
13 import ddmd.declaration;
14 import ddmd.dmodule;
15 import ddmd.dscope;
16 import ddmd.dstruct;
17 import ddmd.errors;
18 import ddmd.globals;
19 import ddmd.gluelayer;
20 import ddmd.mtype;
21 import ddmd.visitor;
22 
23 /****************************************************
24  * Get the exact TypeInfo.
25  */
26 extern (C++) void genTypeInfo(Type torig, Scope* sc)
27 {
28     //printf("Type::genTypeInfo() %p, %s\n", this, toChars());
29     if (!Type.dtypeinfo)
30     {
31         torig.error(Loc(), "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch");
32         fatal();
33     }
34 
35     Type t = torig.merge2(); // do this since not all Type's are merge'd
36     if (!t.vtinfo)
37     {
38         if (t.isShared()) // does both 'shared' and 'shared const'
39             t.vtinfo = TypeInfoSharedDeclaration.create(t);
40         else if (t.isConst())
41             t.vtinfo = TypeInfoConstDeclaration.create(t);
42         else if (t.isImmutable())
43             t.vtinfo = TypeInfoInvariantDeclaration.create(t);
44         else if (t.isWild())
45             t.vtinfo = TypeInfoWildDeclaration.create(t);
46         else
47             t.vtinfo = getTypeInfoDeclaration(t);
48         assert(t.vtinfo);
49 
50         /* If this has a custom implementation in std/typeinfo, then
51          * do not generate a COMDAT for it.
52          */
53         if (!builtinTypeInfo(t))
54         {
55             // Generate COMDAT
56             if (sc) // if in semantic() pass
57             {
58                 // Find module that will go all the way to an object file
59                 Module m = sc._module.importedFrom;
60                 m.members.push(t.vtinfo);
61             }
62             else // if in obj generation pass
63             {
64                 toObjFile(t.vtinfo, global.params.multiobj);
65             }
66         }
67     }
68     if (!torig.vtinfo)
69         torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
70     assert(torig.vtinfo);
71 }
72 
73 extern (C++) Type getTypeInfoType(Type t, Scope* sc)
74 {
75     assert(t.ty != Terror);
76     genTypeInfo(t, sc);
77     return t.vtinfo.type;
78 }
79 
80 extern (C++) TypeInfoDeclaration getTypeInfoDeclaration(Type t)
81 {
82     //printf("Type::getTypeInfoDeclaration() %s\n", t->toChars());
83     switch (t.ty)
84     {
85     case Tpointer:
86         return TypeInfoPointerDeclaration.create(t);
87     case Tarray:
88         return TypeInfoArrayDeclaration.create(t);
89     case Tsarray:
90         return TypeInfoStaticArrayDeclaration.create(t);
91     case Taarray:
92         return TypeInfoAssociativeArrayDeclaration.create(t);
93     case Tstruct:
94         return TypeInfoStructDeclaration.create(t);
95     case Tvector:
96         return TypeInfoVectorDeclaration.create(t);
97     case Tenum:
98         return TypeInfoEnumDeclaration.create(t);
99     case Tfunction:
100         return TypeInfoFunctionDeclaration.create(t);
101     case Tdelegate:
102         return TypeInfoDelegateDeclaration.create(t);
103     case Ttuple:
104         return TypeInfoTupleDeclaration.create(t);
105     case Tclass:
106         if ((cast(TypeClass)t).sym.isInterfaceDeclaration())
107             return TypeInfoInterfaceDeclaration.create(t);
108         else
109             return TypeInfoClassDeclaration.create(t);
110 
111     default:
112         return TypeInfoDeclaration.create(t);
113     }
114 }
115 
116 extern (C++) bool isSpeculativeType(Type t)
117 {
118     extern (C++) final class SpeculativeTypeVisitor : Visitor
119     {
120         alias visit = super.visit;
121     public:
122         bool result;
123 
124         extern (D) this()
125         {
126         }
127 
128         override void visit(Type t)
129         {
130             Type tb = t.toBasetype();
131             if (tb != t)
132                 tb.accept(this);
133         }
134 
135         override void visit(TypeNext t)
136         {
137             if (t.next)
138                 t.next.accept(this);
139         }
140 
141         override void visit(TypeBasic t)
142         {
143         }
144 
145         override void visit(TypeVector t)
146         {
147             t.basetype.accept(this);
148         }
149 
150         override void visit(TypeAArray t)
151         {
152             t.index.accept(this);
153             visit(cast(TypeNext)t);
154         }
155 
156         override void visit(TypeFunction t)
157         {
158             visit(cast(TypeNext)t);
159             // Currently TypeInfo_Function doesn't store parameter types.
160         }
161 
162         override void visit(TypeStruct t)
163         {
164             StructDeclaration sd = t.sym;
165             if (auto ti = sd.isInstantiated())
166             {
167                 if (!ti.needsCodegen())
168                 {
169                     if (ti.minst || sd.requestTypeInfo)
170                         return;
171 
172                     /* Bugzilla 14425: TypeInfo_Struct would refer the members of
173                      * struct (e.g. opEquals via xopEquals field), so if it's instantiated
174                      * in speculative context, TypeInfo creation should also be
175                      * stopped to avoid 'unresolved symbol' linker errors.
176                      */
177                     /* When -debug/-unittest is specified, all of non-root instances are
178                      * automatically changed to speculative, and here is always reached
179                      * from those instantiated non-root structs.
180                      * Therefore, if the TypeInfo is not auctually requested,
181                      * we have to elide its codegen.
182                      */
183                     result |= true;
184                     return;
185                 }
186             }
187             else
188             {
189                 //assert(!sd.inNonRoot() || sd.requestTypeInfo);    // valid?
190             }
191         }
192 
193         override void visit(TypeClass t)
194         {
195         }
196 
197         override void visit(TypeTuple t)
198         {
199             if (t.arguments)
200             {
201                 for (size_t i = 0; i < t.arguments.dim; i++)
202                 {
203                     Type tprm = (*t.arguments)[i].type;
204                     if (tprm)
205                         tprm.accept(this);
206                     if (result)
207                         return;
208                 }
209             }
210         }
211     }
212 
213     scope SpeculativeTypeVisitor v = new SpeculativeTypeVisitor();
214     t.accept(v);
215     return v.result;
216 }
217 
218 /* ========================================================================= */
219 
220 /* These decide if there's an instance for them already in std.typeinfo,
221  * because then the compiler doesn't need to build one.
222  */
223 extern (C++) static bool builtinTypeInfo(Type t)
224 {
225     if (t.isTypeBasic() || t.ty == Tclass || t.ty == Tnull)
226         return !t.mod;
227     if (t.ty == Tarray)
228     {
229         Type next = t.nextOf();
230         // strings are so common, make them builtin
231         return !t.mod &&
232                (next.isTypeBasic() !is null && !next.mod ||
233                 next.ty == Tchar && next.mod == MODimmutable ||
234                 next.ty == Tchar && next.mod == MODconst);
235     }
236     return false;
237 }