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