1*f0fbc68bSmrg /**
2*f0fbc68bSmrg * Generate `TypeInfo` objects, which are needed for run-time introspection of types.
3*f0fbc68bSmrg *
4*f0fbc68bSmrg * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
5*f0fbc68bSmrg * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6*f0fbc68bSmrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7*f0fbc68bSmrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typeinf.d, _typeinf.d)
8*f0fbc68bSmrg * Documentation: https://dlang.org/phobos/dmd_typinf.html
9*f0fbc68bSmrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typinf.d
10*f0fbc68bSmrg */
11*f0fbc68bSmrg
12*f0fbc68bSmrg module dmd.typinf;
13*f0fbc68bSmrg
14*f0fbc68bSmrg import dmd.astenums;
15*f0fbc68bSmrg import dmd.declaration;
16*f0fbc68bSmrg import dmd.dmodule;
17*f0fbc68bSmrg import dmd.dscope;
18*f0fbc68bSmrg import dmd.dclass;
19*f0fbc68bSmrg import dmd.dstruct;
20*f0fbc68bSmrg import dmd.errors;
21*f0fbc68bSmrg import dmd.globals;
22*f0fbc68bSmrg import dmd.gluelayer;
23*f0fbc68bSmrg import dmd.mtype;
24*f0fbc68bSmrg import dmd.visitor;
25*f0fbc68bSmrg import core.stdc.stdio;
26*f0fbc68bSmrg
27*f0fbc68bSmrg /****************************************************
28*f0fbc68bSmrg * Generates the `TypeInfo` object associated with `torig` if it
29*f0fbc68bSmrg * hasn't already been generated
30*f0fbc68bSmrg * Params:
31*f0fbc68bSmrg * loc = the location for reporting line numbers in errors
32*f0fbc68bSmrg * torig = the type to generate the `TypeInfo` object for
33*f0fbc68bSmrg * sc = the scope
34*f0fbc68bSmrg */
genTypeInfo(const ref Loc loc,Type torig,Scope * sc)35*f0fbc68bSmrg extern (C++) void genTypeInfo(const ref Loc loc, Type torig, Scope* sc)
36*f0fbc68bSmrg {
37*f0fbc68bSmrg // printf("genTypeInfo() %s\n", torig.toChars());
38*f0fbc68bSmrg
39*f0fbc68bSmrg // Even when compiling without `useTypeInfo` (e.g. -betterC) we should
40*f0fbc68bSmrg // still be able to evaluate `TypeInfo` at compile-time, just not at runtime.
41*f0fbc68bSmrg // https://issues.dlang.org/show_bug.cgi?id=18472
42*f0fbc68bSmrg if (!sc || !(sc.flags & SCOPE.ctfe))
43*f0fbc68bSmrg {
44*f0fbc68bSmrg if (!global.params.useTypeInfo)
45*f0fbc68bSmrg {
46*f0fbc68bSmrg .error(loc, "`TypeInfo` cannot be used with -betterC");
47*f0fbc68bSmrg fatal();
48*f0fbc68bSmrg }
49*f0fbc68bSmrg }
50*f0fbc68bSmrg
51*f0fbc68bSmrg if (!Type.dtypeinfo)
52*f0fbc68bSmrg {
53*f0fbc68bSmrg .error(loc, "`object.TypeInfo` could not be found, but is implicitly used");
54*f0fbc68bSmrg fatal();
55*f0fbc68bSmrg }
56*f0fbc68bSmrg
57*f0fbc68bSmrg Type t = torig.merge2(); // do this since not all Type's are merge'd
58*f0fbc68bSmrg if (!t.vtinfo)
59*f0fbc68bSmrg {
60*f0fbc68bSmrg if (t.isShared()) // does both 'shared' and 'shared const'
61*f0fbc68bSmrg t.vtinfo = TypeInfoSharedDeclaration.create(t);
62*f0fbc68bSmrg else if (t.isConst())
63*f0fbc68bSmrg t.vtinfo = TypeInfoConstDeclaration.create(t);
64*f0fbc68bSmrg else if (t.isImmutable())
65*f0fbc68bSmrg t.vtinfo = TypeInfoInvariantDeclaration.create(t);
66*f0fbc68bSmrg else if (t.isWild())
67*f0fbc68bSmrg t.vtinfo = TypeInfoWildDeclaration.create(t);
68*f0fbc68bSmrg else
69*f0fbc68bSmrg t.vtinfo = getTypeInfoDeclaration(t);
70*f0fbc68bSmrg assert(t.vtinfo);
71*f0fbc68bSmrg
72*f0fbc68bSmrg // ClassInfos are generated as part of ClassDeclaration codegen
73*f0fbc68bSmrg const isUnqualifiedClassInfo = (t.ty == Tclass && !t.mod);
74*f0fbc68bSmrg
75*f0fbc68bSmrg // generate a COMDAT for other TypeInfos not available as builtins in
76*f0fbc68bSmrg // druntime
77*f0fbc68bSmrg if (!isUnqualifiedClassInfo && !builtinTypeInfo(t))
78*f0fbc68bSmrg {
79*f0fbc68bSmrg if (sc) // if in semantic() pass
80*f0fbc68bSmrg {
81*f0fbc68bSmrg // Find module that will go all the way to an object file
82*f0fbc68bSmrg Module m = sc._module.importedFrom;
83*f0fbc68bSmrg m.members.push(t.vtinfo);
84*f0fbc68bSmrg }
85*f0fbc68bSmrg else // if in obj generation pass
86*f0fbc68bSmrg {
87*f0fbc68bSmrg toObjFile(t.vtinfo, global.params.multiobj);
88*f0fbc68bSmrg }
89*f0fbc68bSmrg }
90*f0fbc68bSmrg }
91*f0fbc68bSmrg if (!torig.vtinfo)
92*f0fbc68bSmrg torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
93*f0fbc68bSmrg assert(torig.vtinfo);
94*f0fbc68bSmrg }
95*f0fbc68bSmrg
96*f0fbc68bSmrg /****************************************************
97*f0fbc68bSmrg * Gets the type of the `TypeInfo` object associated with `t`
98*f0fbc68bSmrg * Params:
99*f0fbc68bSmrg * loc = the location for reporting line nunbers in errors
100*f0fbc68bSmrg * t = the type to get the type of the `TypeInfo` object for
101*f0fbc68bSmrg * sc = the scope
102*f0fbc68bSmrg * Returns:
103*f0fbc68bSmrg * The type of the `TypeInfo` object associated with `t`
104*f0fbc68bSmrg */
105*f0fbc68bSmrg extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc);
106*f0fbc68bSmrg
getTypeInfoDeclaration(Type t)107*f0fbc68bSmrg private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
108*f0fbc68bSmrg {
109*f0fbc68bSmrg //printf("Type::getTypeInfoDeclaration() %s\n", t.toChars());
110*f0fbc68bSmrg switch (t.ty)
111*f0fbc68bSmrg {
112*f0fbc68bSmrg case Tpointer:
113*f0fbc68bSmrg return TypeInfoPointerDeclaration.create(t);
114*f0fbc68bSmrg case Tarray:
115*f0fbc68bSmrg return TypeInfoArrayDeclaration.create(t);
116*f0fbc68bSmrg case Tsarray:
117*f0fbc68bSmrg return TypeInfoStaticArrayDeclaration.create(t);
118*f0fbc68bSmrg case Taarray:
119*f0fbc68bSmrg return TypeInfoAssociativeArrayDeclaration.create(t);
120*f0fbc68bSmrg case Tstruct:
121*f0fbc68bSmrg return TypeInfoStructDeclaration.create(t);
122*f0fbc68bSmrg case Tvector:
123*f0fbc68bSmrg return TypeInfoVectorDeclaration.create(t);
124*f0fbc68bSmrg case Tenum:
125*f0fbc68bSmrg return TypeInfoEnumDeclaration.create(t);
126*f0fbc68bSmrg case Tfunction:
127*f0fbc68bSmrg return TypeInfoFunctionDeclaration.create(t);
128*f0fbc68bSmrg case Tdelegate:
129*f0fbc68bSmrg return TypeInfoDelegateDeclaration.create(t);
130*f0fbc68bSmrg case Ttuple:
131*f0fbc68bSmrg return TypeInfoTupleDeclaration.create(t);
132*f0fbc68bSmrg case Tclass:
133*f0fbc68bSmrg if ((cast(TypeClass)t).sym.isInterfaceDeclaration())
134*f0fbc68bSmrg return TypeInfoInterfaceDeclaration.create(t);
135*f0fbc68bSmrg else
136*f0fbc68bSmrg return TypeInfoClassDeclaration.create(t);
137*f0fbc68bSmrg
138*f0fbc68bSmrg default:
139*f0fbc68bSmrg return TypeInfoDeclaration.create(t);
140*f0fbc68bSmrg }
141*f0fbc68bSmrg }
142*f0fbc68bSmrg
143*f0fbc68bSmrg /**************************************************
144*f0fbc68bSmrg * Returns:
145*f0fbc68bSmrg * true if any part of type t is speculative.
146*f0fbc68bSmrg * if t is null, returns false.
147*f0fbc68bSmrg */
isSpeculativeType(Type t)148*f0fbc68bSmrg bool isSpeculativeType(Type t)
149*f0fbc68bSmrg {
150*f0fbc68bSmrg static bool visitVector(TypeVector t)
151*f0fbc68bSmrg {
152*f0fbc68bSmrg return isSpeculativeType(t.basetype);
153*f0fbc68bSmrg }
154*f0fbc68bSmrg
155*f0fbc68bSmrg static bool visitAArray(TypeAArray t)
156*f0fbc68bSmrg {
157*f0fbc68bSmrg return isSpeculativeType(t.index) ||
158*f0fbc68bSmrg isSpeculativeType(t.next);
159*f0fbc68bSmrg }
160*f0fbc68bSmrg
161*f0fbc68bSmrg static bool visitStruct(TypeStruct t)
162*f0fbc68bSmrg {
163*f0fbc68bSmrg StructDeclaration sd = t.sym;
164*f0fbc68bSmrg if (auto ti = sd.isInstantiated())
165*f0fbc68bSmrg {
166*f0fbc68bSmrg if (!ti.needsCodegen())
167*f0fbc68bSmrg {
168*f0fbc68bSmrg if (ti.minst || sd.requestTypeInfo)
169*f0fbc68bSmrg return false;
170*f0fbc68bSmrg
171*f0fbc68bSmrg /* https://issues.dlang.org/show_bug.cgi?id=14425
172*f0fbc68bSmrg * TypeInfo_Struct would refer the members of
173*f0fbc68bSmrg * struct (e.g. opEquals via xopEquals field), so if it's instantiated
174*f0fbc68bSmrg * in speculative context, TypeInfo creation should also be
175*f0fbc68bSmrg * stopped to avoid 'unresolved symbol' linker errors.
176*f0fbc68bSmrg */
177*f0fbc68bSmrg /* When -debug/-unittest is specified, all of non-root instances are
178*f0fbc68bSmrg * automatically changed to speculative, and here is always reached
179*f0fbc68bSmrg * from those instantiated non-root structs.
180*f0fbc68bSmrg * Therefore, if the TypeInfo is not auctually requested,
181*f0fbc68bSmrg * we have to elide its codegen.
182*f0fbc68bSmrg */
183*f0fbc68bSmrg return true;
184*f0fbc68bSmrg }
185*f0fbc68bSmrg }
186*f0fbc68bSmrg else
187*f0fbc68bSmrg {
188*f0fbc68bSmrg //assert(!sd.inNonRoot() || sd.requestTypeInfo); // valid?
189*f0fbc68bSmrg }
190*f0fbc68bSmrg return false;
191*f0fbc68bSmrg }
192*f0fbc68bSmrg
193*f0fbc68bSmrg static bool visitClass(TypeClass t)
194*f0fbc68bSmrg {
195*f0fbc68bSmrg ClassDeclaration sd = t.sym;
196*f0fbc68bSmrg if (auto ti = sd.isInstantiated())
197*f0fbc68bSmrg {
198*f0fbc68bSmrg if (!ti.needsCodegen() && !ti.minst)
199*f0fbc68bSmrg {
200*f0fbc68bSmrg return true;
201*f0fbc68bSmrg }
202*f0fbc68bSmrg }
203*f0fbc68bSmrg return false;
204*f0fbc68bSmrg }
205*f0fbc68bSmrg
206*f0fbc68bSmrg
207*f0fbc68bSmrg static bool visitTuple(TypeTuple t)
208*f0fbc68bSmrg {
209*f0fbc68bSmrg if (t.arguments)
210*f0fbc68bSmrg {
211*f0fbc68bSmrg foreach (arg; *t.arguments)
212*f0fbc68bSmrg {
213*f0fbc68bSmrg if (isSpeculativeType(arg.type))
214*f0fbc68bSmrg return true;
215*f0fbc68bSmrg }
216*f0fbc68bSmrg }
217*f0fbc68bSmrg return false;
218*f0fbc68bSmrg }
219*f0fbc68bSmrg
220*f0fbc68bSmrg if (!t)
221*f0fbc68bSmrg return false;
222*f0fbc68bSmrg Type tb = t.toBasetype();
223*f0fbc68bSmrg switch (tb.ty)
224*f0fbc68bSmrg {
225*f0fbc68bSmrg case Tvector: return visitVector(tb.isTypeVector());
226*f0fbc68bSmrg case Taarray: return visitAArray(tb.isTypeAArray());
227*f0fbc68bSmrg case Tstruct: return visitStruct(tb.isTypeStruct());
228*f0fbc68bSmrg case Tclass: return visitClass(tb.isTypeClass());
229*f0fbc68bSmrg case Ttuple: return visitTuple(tb.isTypeTuple());
230*f0fbc68bSmrg case Tenum: return false;
231*f0fbc68bSmrg default:
232*f0fbc68bSmrg return isSpeculativeType(tb.nextOf());
233*f0fbc68bSmrg
234*f0fbc68bSmrg /* For TypeFunction, TypeInfo_Function doesn't store parameter types,
235*f0fbc68bSmrg * so only the .next (the return type) is checked here.
236*f0fbc68bSmrg */
237*f0fbc68bSmrg }
238*f0fbc68bSmrg }
239*f0fbc68bSmrg
240*f0fbc68bSmrg /* ========================================================================= */
241*f0fbc68bSmrg
242*f0fbc68bSmrg /* Indicates whether druntime already contains an appropriate TypeInfo instance
243*f0fbc68bSmrg * for the specified type (in module rt.util.typeinfo).
244*f0fbc68bSmrg */
builtinTypeInfo(Type t)245*f0fbc68bSmrg extern (C++) bool builtinTypeInfo(Type t)
246*f0fbc68bSmrg {
247*f0fbc68bSmrg if (!t.mod) // unqualified types only
248*f0fbc68bSmrg {
249*f0fbc68bSmrg // unqualified basic types + typeof(null)
250*f0fbc68bSmrg if (t.isTypeBasic() || t.ty == Tnull)
251*f0fbc68bSmrg return true;
252*f0fbc68bSmrg // some unqualified arrays
253*f0fbc68bSmrg if (t.ty == Tarray)
254*f0fbc68bSmrg {
255*f0fbc68bSmrg Type next = t.nextOf();
256*f0fbc68bSmrg return (next.isTypeBasic() && !next.mod) // of unqualified basic types
257*f0fbc68bSmrg || (next.ty == Tchar && next.mod == MODFlags.immutable_) // string
258*f0fbc68bSmrg || (next.ty == Tchar && next.mod == MODFlags.const_); // const(char)[]
259*f0fbc68bSmrg }
260*f0fbc68bSmrg }
261*f0fbc68bSmrg return false;
262*f0fbc68bSmrg }
263