xref: /netbsd/external/gpl3/gcc/dist/gcc/d/dmd/typinf.d (revision f0fbc68b)
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