2 * Generate `TypeInfo` objects, which are needed for run-time introspection of types.
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
15 import dmd
.declaration
;
21 import dmd
.expression
;
27 import core
.stdc
.stdio
;
29 /****************************************************
30 * Generates the `TypeInfo` object associated with `torig` if it
31 * hasn't already been generated
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
37 * genObjCode = if true, object code will be generated for the obtained TypeInfo
39 extern (C
++) void genTypeInfo(Expression e
, const ref Loc loc
, Type torig
, Scope
* sc
, bool genObjCode
= true)
41 // printf("genTypeInfo() %s\n", torig.toChars());
43 // Even when compiling without `useTypeInfo` (e.g. -betterC) we should
44 // still be able to evaluate `TypeInfo` at compile-time, just not at runtime.
45 // https://issues.dlang.org/show_bug.cgi?id=18472
46 if (!sc ||
!(sc
.flags
& SCOPE
.ctfe
))
48 if (!global
.params
.useTypeInfo
)
52 .error(loc
, "expression `%s` uses the GC and cannot be used with switch `-betterC`", e
.toChars());
54 .error(loc
, "`TypeInfo` cannot be used with -betterC");
57 sc
.tinst
.printInstantiationTrace(Classification
.error
, uint.max
);
65 .error(loc
, "`object.TypeInfo` could not be found, but is implicitly used");
69 Type t
= torig
.merge2(); // do this since not all Type's are merge'd
72 if (t
.isShared()) // does both 'shared' and 'shared const'
73 t
.vtinfo
= TypeInfoSharedDeclaration
.create(t
);
75 t
.vtinfo
= TypeInfoConstDeclaration
.create(t
);
76 else if (t
.isImmutable())
77 t
.vtinfo
= TypeInfoInvariantDeclaration
.create(t
);
79 t
.vtinfo
= TypeInfoWildDeclaration
.create(t
);
81 t
.vtinfo
= getTypeInfoDeclaration(t
);
84 // ClassInfos are generated as part of ClassDeclaration codegen
85 const isUnqualifiedClassInfo
= (t
.ty
== Tclass
&& !t
.mod
);
87 // generate a COMDAT for other TypeInfos not available as builtins in
89 if (!isUnqualifiedClassInfo
&& !builtinTypeInfo(t
) && genObjCode
)
91 if (sc
) // if in semantic() pass
93 // Find module that will go all the way to an object file
94 Module m
= sc
._module
.importedFrom
;
95 m
.members
.push(t
.vtinfo
);
97 else // if in obj generation pass
99 toObjFile(t
.vtinfo
, global
.params
.multiobj
);
104 torig
.vtinfo
= t
.vtinfo
; // Types aren't merged, but we can share the vtinfo's
105 assert(torig
.vtinfo
);
108 /****************************************************
109 * Gets the type of the `TypeInfo` object associated with `t`
111 * loc = the location for reporting line nunbers in errors
112 * t = the type to get the type of the `TypeInfo` object for
114 * genObjCode = if true, object code will be generated for the obtained TypeInfo
116 * The type of the `TypeInfo` object associated with `t`
118 extern (C
++) Type
getTypeInfoType(const ref Loc loc
, Type t
, Scope
* sc
, bool genObjCode
= true);
120 private TypeInfoDeclaration
getTypeInfoDeclaration(Type t
)
122 //printf("Type::getTypeInfoDeclaration() %s\n", t.toChars());
126 return TypeInfoPointerDeclaration
.create(t
);
128 return TypeInfoArrayDeclaration
.create(t
);
130 return TypeInfoStaticArrayDeclaration
.create(t
);
132 return TypeInfoAssociativeArrayDeclaration
.create(t
);
134 return TypeInfoStructDeclaration
.create(t
);
136 return TypeInfoVectorDeclaration
.create(t
);
138 return TypeInfoEnumDeclaration
.create(t
);
140 return TypeInfoFunctionDeclaration
.create(t
);
142 return TypeInfoDelegateDeclaration
.create(t
);
144 return TypeInfoTupleDeclaration
.create(t
);
146 if ((cast(TypeClass
)t
).sym
.isInterfaceDeclaration())
147 return TypeInfoInterfaceDeclaration
.create(t
);
149 return TypeInfoClassDeclaration
.create(t
);
152 return TypeInfoDeclaration
.create(t
);
156 /**************************************************
158 * true if any part of type t is speculative.
159 * if t is null, returns false.
161 bool isSpeculativeType(Type t
)
163 static bool visitVector(TypeVector t
)
165 return isSpeculativeType(t
.basetype
);
168 static bool visitAArray(TypeAArray t
)
170 return isSpeculativeType(t
.index
) ||
171 isSpeculativeType(t
.next
);
174 static bool visitStruct(TypeStruct t
)
176 StructDeclaration sd
= t
.sym
;
177 if (auto ti
= sd
.isInstantiated())
179 if (!ti
.needsCodegen())
181 if (ti
.minst || sd
.requestTypeInfo
)
184 /* https://issues.dlang.org/show_bug.cgi?id=14425
185 * TypeInfo_Struct would refer the members of
186 * struct (e.g. opEquals via xopEquals field), so if it's instantiated
187 * in speculative context, TypeInfo creation should also be
188 * stopped to avoid 'unresolved symbol' linker errors.
190 /* When -debug/-unittest is specified, all of non-root instances are
191 * automatically changed to speculative, and here is always reached
192 * from those instantiated non-root structs.
193 * Therefore, if the TypeInfo is not auctually requested,
194 * we have to elide its codegen.
201 //assert(!sd.inNonRoot() || sd.requestTypeInfo); // valid?
206 static bool visitClass(TypeClass t
)
208 ClassDeclaration sd
= t
.sym
;
209 if (auto ti
= sd
.isInstantiated())
211 if (!ti
.needsCodegen() && !ti
.minst
)
220 static bool visitTuple(TypeTuple t
)
224 foreach (arg
; *t
.arguments
)
226 if (isSpeculativeType(arg
.type
))
235 Type tb
= t
.toBasetype();
238 case Tvector
: return visitVector(tb
.isTypeVector());
239 case Taarray
: return visitAArray(tb
.isTypeAArray());
240 case Tstruct
: return visitStruct(tb
.isTypeStruct());
241 case Tclass
: return visitClass(tb
.isTypeClass());
242 case Ttuple
: return visitTuple(tb
.isTypeTuple());
243 case Tenum
: return false;
245 return isSpeculativeType(tb
.nextOf());
247 /* For TypeFunction, TypeInfo_Function doesn't store parameter types,
248 * so only the .next (the return type) is checked here.
253 /* ========================================================================= */
255 /* Indicates whether druntime already contains an appropriate TypeInfo instance
256 * for the specified type (in module rt.util.typeinfo).
258 extern (C
++) bool builtinTypeInfo(Type t
)
260 if (!t
.mod
) // unqualified types only
262 // unqualified basic types + typeof(null)
263 if (t
.isTypeBasic() || t
.ty
== Tnull
)
265 // some unqualified arrays
268 Type next
= t
.nextOf();
269 return (next
.isTypeBasic() && !next
.mod
) // of unqualified basic types
270 ||
(next
.ty
== Tchar
&& next
.mod
== MODFlags
.immutable_
) // string
271 ||
(next
.ty
== Tchar
&& next
.mod
== MODFlags
.const_
); // const(char)[]