d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / gcc / d / dmd / typinf.d
blob6ae6df0e9b5a9bb54ec98718e07118435564e4d2
1 /**
2 * Generate `TypeInfo` objects, which are needed for run-time introspection of types.
4 * Copyright: Copyright (C) 1999-2024 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/typinf.d, _typinf.d)
8 * Documentation: https://dlang.org/phobos/dmd_typinf.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typinf.d
12 module dmd.typinf;
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.location;
24 import dmd.mtype;
25 import core.stdc.stdio;
27 /****************************************************
28 * Generates the `TypeInfo` object associated with `torig` if it
29 * hasn't already been generated
30 * Params:
31 * e = if not null, then expression for pretty-printing errors
32 * loc = the location for reporting line numbers in errors
33 * torig = the type to generate the `TypeInfo` object for
34 * sc = the scope
35 * Returns:
36 * true if `TypeInfo` was generated and needs compiling to object file
38 extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
40 // printf("genTypeInfo() %s\n", torig.toChars());
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))
47 if (!global.params.useTypeInfo)
49 global.gag = 0;
50 if (e)
51 .error(loc, "expression `%s` uses the GC and cannot be used with switch `-betterC`", e.toChars());
52 else
53 .error(loc, "`TypeInfo` cannot be used with -betterC");
55 if (sc && sc.tinst)
56 sc.tinst.printInstantiationTrace(Classification.error, uint.max);
58 fatal();
62 if (!Type.dtypeinfo)
64 .error(loc, "`object.TypeInfo` could not be found, but is implicitly used");
65 fatal();
68 import dmd.typesem : merge2;
69 Type t = torig.merge2(); // do this since not all Type's are merge'd
70 bool needsCodegen = false;
71 if (!t.vtinfo)
73 if (t.isShared()) // does both 'shared' and 'shared const'
74 t.vtinfo = TypeInfoSharedDeclaration.create(t);
75 else if (t.isConst())
76 t.vtinfo = TypeInfoConstDeclaration.create(t);
77 else if (t.isImmutable())
78 t.vtinfo = TypeInfoInvariantDeclaration.create(t);
79 else if (t.isWild())
80 t.vtinfo = TypeInfoWildDeclaration.create(t);
81 else
82 t.vtinfo = getTypeInfoDeclaration(t);
83 assert(t.vtinfo);
85 // ClassInfos are generated as part of ClassDeclaration codegen
86 const isUnqualifiedClassInfo = (t.ty == Tclass && !t.mod);
88 if (!isUnqualifiedClassInfo && !builtinTypeInfo(t))
89 needsCodegen = true;
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 return needsCodegen;
97 /****************************************************
98 * Gets the type of the `TypeInfo` object associated with `t`
99 * Params:
100 * loc = the location for reporting line nunbers in errors
101 * t = the type to get the type of the `TypeInfo` object for
102 * sc = the scope
103 * genObjCode = if true, object code will be generated for the obtained TypeInfo
104 * Returns:
105 * The type of the `TypeInfo` object associated with `t`
107 extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc, bool genObjCode = true);
109 private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
111 //printf("Type::getTypeInfoDeclaration() %s\n", t.toChars());
112 switch (t.ty)
114 case Tpointer:
115 return TypeInfoPointerDeclaration.create(t);
116 case Tarray:
117 return TypeInfoArrayDeclaration.create(t);
118 case Tsarray:
119 return TypeInfoStaticArrayDeclaration.create(t);
120 case Taarray:
121 return TypeInfoAssociativeArrayDeclaration.create(t);
122 case Tstruct:
123 return TypeInfoStructDeclaration.create(t);
124 case Tvector:
125 return TypeInfoVectorDeclaration.create(t);
126 case Tenum:
127 return TypeInfoEnumDeclaration.create(t);
128 case Tfunction:
129 return TypeInfoFunctionDeclaration.create(t);
130 case Tdelegate:
131 return TypeInfoDelegateDeclaration.create(t);
132 case Ttuple:
133 return TypeInfoTupleDeclaration.create(t);
134 case Tclass:
135 if ((cast(TypeClass)t).sym.isInterfaceDeclaration())
136 return TypeInfoInterfaceDeclaration.create(t);
137 else
138 return TypeInfoClassDeclaration.create(t);
140 default:
141 return TypeInfoDeclaration.create(t);
145 /**************************************************
146 * Returns:
147 * true if any part of type t is speculative.
148 * if t is null, returns false.
150 extern (C++) bool isSpeculativeType(Type t)
152 static bool visitVector(TypeVector t)
154 return isSpeculativeType(t.basetype);
157 static bool visitAArray(TypeAArray t)
159 return isSpeculativeType(t.index) ||
160 isSpeculativeType(t.next);
163 static bool visitStruct(TypeStruct t)
165 StructDeclaration sd = t.sym;
166 if (auto ti = sd.isInstantiated())
168 if (!ti.needsCodegen())
170 if (ti.minst || sd.requestTypeInfo)
171 return false;
173 /* https://issues.dlang.org/show_bug.cgi?id=14425
174 * TypeInfo_Struct would refer the members of
175 * struct (e.g. opEquals via xopEquals field), so if it's instantiated
176 * in speculative context, TypeInfo creation should also be
177 * stopped to avoid 'unresolved symbol' linker errors.
179 /* When -debug/-unittest is specified, all of non-root instances are
180 * automatically changed to speculative, and here is always reached
181 * from those instantiated non-root structs.
182 * Therefore, if the TypeInfo is not auctually requested,
183 * we have to elide its codegen.
185 return true;
188 else
190 //assert(!sd.inNonRoot() || sd.requestTypeInfo); // valid?
192 return false;
195 static bool visitClass(TypeClass t)
197 ClassDeclaration sd = t.sym;
198 if (auto ti = sd.isInstantiated())
200 if (!ti.needsCodegen() && !ti.minst)
202 return true;
205 return false;
209 static bool visitTuple(TypeTuple t)
211 if (t.arguments)
213 foreach (arg; *t.arguments)
215 if (isSpeculativeType(arg.type))
216 return true;
219 return false;
222 if (!t)
223 return false;
224 Type tb = t.toBasetype();
225 switch (tb.ty)
227 case Tvector: return visitVector(tb.isTypeVector());
228 case Taarray: return visitAArray(tb.isTypeAArray());
229 case Tstruct: return visitStruct(tb.isTypeStruct());
230 case Tclass: return visitClass(tb.isTypeClass());
231 case Ttuple: return visitTuple(tb.isTypeTuple());
232 case Tenum: return false;
233 default:
234 return isSpeculativeType(tb.nextOf());
236 /* For TypeFunction, TypeInfo_Function doesn't store parameter types,
237 * so only the .next (the return type) is checked here.
242 /* ========================================================================= */
244 /* Indicates whether druntime already contains an appropriate TypeInfo instance
245 * for the specified type (in module rt.util.typeinfo).
247 extern (C++) bool builtinTypeInfo(Type t)
249 if (!t.mod) // unqualified types only
251 // unqualified basic types + typeof(null)
252 if (t.isTypeBasic() || t.ty == Tnull)
253 return true;
254 // some unqualified arrays
255 if (t.ty == Tarray)
257 Type next = t.nextOf();
258 return (next.isTypeBasic() && !next.mod) // of unqualified basic types
259 || (next.ty == Tchar && next.mod == MODFlags.immutable_) // string
260 || (next.ty == Tchar && next.mod == MODFlags.const_); // const(char)[]
263 return false;