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