1
/**
2
 * Generate `TypeInfo` objects, which are needed for run-time introspection of classes.
3
 *
4
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6
 * License:     $(LINK2 http://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.declaration;
15
import dmd.dmodule;
16
import dmd.dscope;
17
import dmd.dclass;
18
import dmd.dstruct;
19
import dmd.errors;
20
import dmd.globals;
21
import dmd.gluelayer;
22
import dmd.mtype;
23
import dmd.visitor;
24
import core.stdc.stdio;
25

26
/****************************************************
27
 * Generates the `TypeInfo` object associated with `torig` if it
28
 * hasn't already been generated
29
 * Params:
30
 *      loc   = the location for reporting line numbers in errors
31
 *      torig = the type to generate the `TypeInfo` object for
32
 *      sc    = the scope
33
 */
34
void genTypeInfo(Loc loc, Type torig, Scope* sc)
35
{
36
    // printf("genTypeInfo() %s\n", torig.toChars());
37

38
    // Even when compiling without `useTypeInfo` (e.g. -betterC) we should
39
    // still be able to evaluate `TypeInfo` at compile-time, just not at runtime.
40
    // https://issues.dlang.org/show_bug.cgi?id=18472
41 1
    if (!sc || !(sc.flags & SCOPE.ctfe))
42
    {
43 1
        if (!global.params.useTypeInfo)
44
        {
45 1
            .error(loc, "`TypeInfo` cannot be used with -betterC");
46 1
            fatal();
47
        }
48
    }
49

50 1
    if (!Type.dtypeinfo)
51
    {
52 1
        .error(loc, "`object.TypeInfo` could not be found, but is implicitly used");
53 1
        fatal();
54
    }
55

56 1
    Type t = torig.merge2(); // do this since not all Type's are merge'd
57 1
    if (!t.vtinfo)
58
    {
59 1
        if (t.isShared()) // does both 'shared' and 'shared const'
60 1
            t.vtinfo = TypeInfoSharedDeclaration.create(t);
61 1
        else if (t.isConst())
62 1
            t.vtinfo = TypeInfoConstDeclaration.create(t);
63 1
        else if (t.isImmutable())
64 1
            t.vtinfo = TypeInfoInvariantDeclaration.create(t);
65 1
        else if (t.isWild())
66 1
            t.vtinfo = TypeInfoWildDeclaration.create(t);
67
        else
68 1
            t.vtinfo = getTypeInfoDeclaration(t);
69 1
        assert(t.vtinfo);
70

71
        /* If this has a custom implementation in std/typeinfo, then
72
         * do not generate a COMDAT for it.
73
         */
74 1
        if (!builtinTypeInfo(t))
75
        {
76
            // Generate COMDAT
77 1
            if (sc) // if in semantic() pass
78
            {
79
                // Find module that will go all the way to an object file
80 1
                Module m = sc._module.importedFrom;
81 1
                m.members.push(t.vtinfo);
82
            }
83
            else // if in obj generation pass
84
            {
85 1
                toObjFile(t.vtinfo, global.params.multiobj);
86
            }
87
        }
88
    }
89 1
    if (!torig.vtinfo)
90 1
        torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
91 1
    assert(torig.vtinfo);
92
}
93

94
/****************************************************
95
 * Gets the type of the `TypeInfo` object associated with `t`
96
 * Params:
97
 *      loc = the location for reporting line nunbers in errors
98
 *      t   = the type to get the type of the `TypeInfo` object for
99
 *      sc  = the scope
100
 * Returns:
101
 *      The type of the `TypeInfo` object associated with `t`
102
 */
103
extern (C++) Type getTypeInfoType(Loc loc, Type t, Scope* sc)
104
{
105 1
    assert(t.ty != Terror);
106 1
    genTypeInfo(loc, t, sc);
107 1
    return t.vtinfo.type;
108
}
109

110
private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
111
{
112
    //printf("Type::getTypeInfoDeclaration() %s\n", t.toChars());
113 1
    switch (t.ty)
114
    {
115 1
    case Tpointer:
116 1
        return TypeInfoPointerDeclaration.create(t);
117 1
    case Tarray:
118 1
        return TypeInfoArrayDeclaration.create(t);
119 1
    case Tsarray:
120 1
        return TypeInfoStaticArrayDeclaration.create(t);
121 1
    case Taarray:
122 1
        return TypeInfoAssociativeArrayDeclaration.create(t);
123 1
    case Tstruct:
124 1
        return TypeInfoStructDeclaration.create(t);
125 1
    case Tvector:
126 1
        return TypeInfoVectorDeclaration.create(t);
127 1
    case Tenum:
128 1
        return TypeInfoEnumDeclaration.create(t);
129 1
    case Tfunction:
130 1
        return TypeInfoFunctionDeclaration.create(t);
131 1
    case Tdelegate:
132 1
        return TypeInfoDelegateDeclaration.create(t);
133 1
    case Ttuple:
134 1
        return TypeInfoTupleDeclaration.create(t);
135 1
    case Tclass:
136 1
        if ((cast(TypeClass)t).sym.isInterfaceDeclaration())
137 1
            return TypeInfoInterfaceDeclaration.create(t);
138
        else
139 1
            return TypeInfoClassDeclaration.create(t);
140

141 1
    default:
142 1
        return TypeInfoDeclaration.create(t);
143
    }
144
}
145

146
/**************************************************
147
 * Returns:
148
 *      true if any part of type t is speculative.
149
 *      if t is null, returns false.
150
 */
151
bool isSpeculativeType(Type t)
152
{
153
    static bool visitVector(TypeVector t)
154
    {
155 1
        return isSpeculativeType(t.basetype);
156
    }
157

158
    static bool visitAArray(TypeAArray t)
159
    {
160 1
        return isSpeculativeType(t.index) ||
161 1
               isSpeculativeType(t.next);
162
    }
163

164
    static bool visitStruct(TypeStruct t)
165
    {
166 1
        StructDeclaration sd = t.sym;
167 1
        if (auto ti = sd.isInstantiated())
168
        {
169 1
            if (!ti.needsCodegen())
170
            {
171 1
                if (ti.minst || sd.requestTypeInfo)
172 1
                    return false;
173

174
                /* https://issues.dlang.org/show_bug.cgi?id=14425
175
                 * TypeInfo_Struct would refer the members of
176
                 * struct (e.g. opEquals via xopEquals field), so if it's instantiated
177
                 * in speculative context, TypeInfo creation should also be
178
                 * stopped to avoid 'unresolved symbol' linker errors.
179
                 */
180
                /* When -debug/-unittest is specified, all of non-root instances are
181
                 * automatically changed to speculative, and here is always reached
182
                 * from those instantiated non-root structs.
183
                 * Therefore, if the TypeInfo is not auctually requested,
184
                 * we have to elide its codegen.
185
                 */
186 1
                return true;
187
            }
188
        }
189
        else
190
        {
191
            //assert(!sd.inNonRoot() || sd.requestTypeInfo);    // valid?
192
        }
193 1
        return false;
194
    }
195

196
    static bool visitClass(TypeClass t)
197
    {
198 1
        ClassDeclaration sd = t.sym;
199 1
        if (auto ti = sd.isInstantiated())
200
        {
201 1
            if (!ti.needsCodegen() && !ti.minst)
202
            {
203 1
                return true;
204
            }
205
        }
206 1
        return false;
207
    }
208

209

210
    static bool visitTuple(TypeTuple t)
211
    {
212 1
        if (t.arguments)
213
        {
214 1
            foreach (arg; *t.arguments)
215
            {
216 1
                if (isSpeculativeType(arg.type))
217 0
                    return true;
218
            }
219
        }
220 1
        return false;
221
    }
222

223 1
    if (!t)
224 1
        return false;
225 1
    Type tb = t.toBasetype();
226 1
    switch (tb.ty)
227
    {
228 1
        case Tvector:   return visitVector(tb.isTypeVector());
229 1
        case Taarray:   return visitAArray(tb.isTypeAArray());
230 1
        case Tstruct:   return visitStruct(tb.isTypeStruct());
231 1
        case Tclass:    return visitClass(tb.isTypeClass());
232 1
        case Ttuple:    return visitTuple(tb.isTypeTuple());
233 1
        case Tenum:     return false;
234 1
        default:
235 1
        return isSpeculativeType(tb.nextOf());
236

237
        /* For TypeFunction, TypeInfo_Function doesn't store parameter types,
238
         * so only the .next (the return type) is checked here.
239
         */
240
    }
241
}
242

243
/* ========================================================================= */
244

245
/* These decide if there's an instance for them already in std.typeinfo,
246
 * because then the compiler doesn't need to build one.
247
 */
248
private bool builtinTypeInfo(Type t)
249
{
250 1
    if (t.isTypeBasic() || t.ty == Tclass || t.ty == Tnull)
251 1
        return !t.mod;
252 1
    if (t.ty == Tarray)
253
    {
254 1
        Type next = t.nextOf();
255
        // strings are so common, make them builtin
256 1
        return !t.mod &&
257 1
               (next.isTypeBasic() !is null && !next.mod ||
258 1
                next.ty == Tchar && next.mod == MODFlags.immutable_ ||
259 1
                next.ty == Tchar && next.mod == MODFlags.const_);
260
    }
261 1
    return false;
262
}

Read our documentation on viewing source code .

Loading