1
/**
2
 * Defines a `class` declaration.
3
 *
4
 * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes)
5
 *
6
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
7
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d)
10
 * Documentation:  https://dlang.org/phobos/dmd_dclass.html
11
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dclass.d
12
 */
13

14
module dmd.dclass;
15

16
import core.stdc.stdio;
17
import core.stdc.string;
18

19
import dmd.aggregate;
20
import dmd.apply;
21
import dmd.arraytypes;
22
import dmd.gluelayer;
23
import dmd.declaration;
24
import dmd.dscope;
25
import dmd.dsymbol;
26
import dmd.dsymbolsem;
27
import dmd.func;
28
import dmd.globals;
29
import dmd.id;
30
import dmd.identifier;
31
import dmd.mtype;
32
import dmd.objc;
33
import dmd.root.rmem;
34
import dmd.target;
35
import dmd.visitor;
36

37
enum Abstract : int
38
{
39
    fwdref = 0,      // whether an abstract class is not yet computed
40
    yes,             // is abstract class
41
    no,              // is not abstract class
42
}
43

44
/***********************************************************
45
 */
46
extern (C++) struct BaseClass
47
{
48
    Type type;          // (before semantic processing)
49

50
    ClassDeclaration sym;
51
    uint offset;        // 'this' pointer offset
52

53
    // for interfaces: Array of FuncDeclaration's making up the vtbl[]
54
    FuncDeclarations vtbl;
55

56
    // if BaseClass is an interface, these
57
    // are a copy of the InterfaceDeclaration.interfaces
58
    BaseClass[] baseInterfaces;
59

60 1
    extern (D) this(Type type)
61
    {
62
        //printf("BaseClass(this = %p, '%s')\n", this, type.toChars());
63 1
        this.type = type;
64
    }
65

66
    /****************************************
67
     * Fill in vtbl[] for base class based on member functions of class cd.
68
     * Input:
69
     *      vtbl            if !=NULL, fill it in
70
     *      newinstance     !=0 means all entries must be filled in by members
71
     *                      of cd, not members of any base classes of cd.
72
     * Returns:
73
     *      true if any entries were filled in by members of cd (not exclusively
74
     *      by base classes)
75
     */
76
    extern (C++) bool fillVtbl(ClassDeclaration cd, FuncDeclarations* vtbl, int newinstance)
77
    {
78 1
        bool result = false;
79

80
        //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", sym.toChars(), cd.toChars());
81 1
        if (vtbl)
82 1
            vtbl.setDim(sym.vtbl.dim);
83

84
        // first entry is ClassInfo reference
85 1
        for (size_t j = sym.vtblOffset(); j < sym.vtbl.dim; j++)
86
        {
87 1
            FuncDeclaration ifd = sym.vtbl[j].isFuncDeclaration();
88

89
            //printf("        vtbl[%d] is '%s'\n", j, ifd ? ifd.toChars() : "null");
90 1
            assert(ifd);
91

92
            // Find corresponding function in this class
93 1
            auto tf = ifd.type.toTypeFunction();
94 1
            auto fd = cd.findFunc(ifd.ident, tf);
95 1
            if (fd && !fd.isAbstract())
96
            {
97 1
                if (fd.toParent() == cd)
98 1
                    result = true;
99
            }
100
            else
101 1
                fd = null;
102 1
            if (vtbl)
103 1
                (*vtbl)[j] = fd;
104
        }
105 1
        return result;
106
    }
107

108
    extern (D) void copyBaseInterfaces(BaseClasses* vtblInterfaces)
109
    {
110
        //printf("+copyBaseInterfaces(), %s\n", sym.toChars());
111
        //    if (baseInterfaces.length)
112
        //      return;
113 1
        auto bc = cast(BaseClass*)mem.xcalloc(sym.interfaces.length, BaseClass.sizeof);
114 1
        baseInterfaces = bc[0 .. sym.interfaces.length];
115
        //printf("%s.copyBaseInterfaces()\n", sym.toChars());
116 1
        for (size_t i = 0; i < baseInterfaces.length; i++)
117
        {
118 1
            BaseClass* b = &baseInterfaces[i];
119 1
            BaseClass* b2 = sym.interfaces[i];
120

121 1
            assert(b2.vtbl.dim == 0); // should not be filled yet
122 1
            memcpy(b, b2, BaseClass.sizeof);
123

124 1
            if (i) // single inheritance is i==0
125 1
                vtblInterfaces.push(b); // only need for M.I.
126 1
            b.copyBaseInterfaces(vtblInterfaces);
127
        }
128
        //printf("-copyBaseInterfaces\n");
129
    }
130
}
131

132
enum ClassFlags : int
133
{
134
    none          = 0x0,
135
    isCOMclass    = 0x1,
136
    noPointers    = 0x2,
137
    hasOffTi      = 0x4,
138
    hasCtor       = 0x8,
139
    hasGetMembers = 0x10,
140
    hasTypeInfo   = 0x20,
141
    isAbstract    = 0x40,
142
    isCPPclass    = 0x80,
143
    hasDtor       = 0x100,
144
}
145

146
/***********************************************************
147
 */
148
extern (C++) class ClassDeclaration : AggregateDeclaration
149
{
150
    extern (C++) __gshared
151
    {
152
        // Names found by reading object.d in druntime
153
        ClassDeclaration object;
154
        ClassDeclaration throwable;
155
        ClassDeclaration exception;
156
        ClassDeclaration errorException;
157
        ClassDeclaration cpp_type_info_ptr;   // Object.__cpp_type_info_ptr
158
    }
159

160
    ClassDeclaration baseClass; // NULL only if this is Object
161
    FuncDeclaration staticCtor;
162
    FuncDeclaration staticDtor;
163
    Dsymbols vtbl;              // Array of FuncDeclaration's making up the vtbl[]
164
    Dsymbols vtblFinal;         // More FuncDeclaration's that aren't in vtbl[]
165

166
    // Array of BaseClass's; first is super, rest are Interface's
167
    BaseClasses* baseclasses;
168

169
    /* Slice of baseclasses[] that does not include baseClass
170
     */
171
    BaseClass*[] interfaces;
172

173
    // array of base interfaces that have their own vtbl[]
174
    BaseClasses* vtblInterfaces;
175

176
    // the ClassInfo object for this ClassDeclaration
177
    TypeInfoClassDeclaration vclassinfo;
178

179
    // true if this is a COM class
180
    bool com;
181

182
    /// true if this is a scope class
183
    bool stack;
184

185
    /// if this is a C++ class, this is the slot reserved for the virtual destructor
186
    int cppDtorVtblIndex = -1;
187

188
    /// to prevent recursive attempts
189
    private bool inuse;
190

191
    /// true if this class has an identifier, but was originally declared anonymous
192
    /// used in support of https://issues.dlang.org/show_bug.cgi?id=17371
193
    private bool isActuallyAnonymous;
194

195
    Abstract isabstract;
196

197
    /// set the progress of base classes resolving
198
    Baseok baseok;
199

200
    /**
201
     * Data for a class declaration that is needed for the Objective-C
202
     * integration.
203
     */
204
    ObjcClassDeclaration objc;
205

206
    Symbol* cpp_type_info_ptr_sym;      // cached instance of class Id.cpp_type_info_ptr
207

208 1
    final extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
209
    {
210 1
        objc = ObjcClassDeclaration(this);
211

212 1
        if (!id)
213
        {
214 1
            isActuallyAnonymous = true;
215
        }
216

217 1
        super(loc, id ? id : Identifier.generateId("__anonclass"));
218

219 1
        __gshared const(char)* msg = "only object.d can define this reserved class name";
220

221 1
        if (baseclasses)
222
        {
223
            // Actually, this is a transfer
224 1
            this.baseclasses = baseclasses;
225
        }
226
        else
227 1
            this.baseclasses = new BaseClasses();
228

229 1
        this.members = members;
230

231
        //printf("ClassDeclaration(%s), dim = %d\n", ident.toChars(), this.baseclasses.dim);
232

233
        // For forward references
234 1
        type = new TypeClass(this);
235

236 1
        if (id)
237
        {
238
            // Look for special class names
239 1
            if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof)
240 0
                error("illegal class name");
241

242
            // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
243 1
            if (id.toChars()[0] == 'T')
244
            {
245 1
                if (id == Id.TypeInfo)
246
                {
247 1
                    if (!inObject)
248 1
                        error("%s", msg);
249 1
                    Type.dtypeinfo = this;
250
                }
251 1
                if (id == Id.TypeInfo_Class)
252
                {
253 1
                    if (!inObject)
254 1
                        error("%s", msg);
255 1
                    Type.typeinfoclass = this;
256
                }
257 1
                if (id == Id.TypeInfo_Interface)
258
                {
259 1
                    if (!inObject)
260 1
                        error("%s", msg);
261 1
                    Type.typeinfointerface = this;
262
                }
263 1
                if (id == Id.TypeInfo_Struct)
264
                {
265 1
                    if (!inObject)
266 1
                        error("%s", msg);
267 1
                    Type.typeinfostruct = this;
268
                }
269 1
                if (id == Id.TypeInfo_Pointer)
270
                {
271 1
                    if (!inObject)
272 1
                        error("%s", msg);
273 1
                    Type.typeinfopointer = this;
274
                }
275 1
                if (id == Id.TypeInfo_Array)
276
                {
277 1
                    if (!inObject)
278 1
                        error("%s", msg);
279 1
                    Type.typeinfoarray = this;
280
                }
281 1
                if (id == Id.TypeInfo_StaticArray)
282
                {
283
                    //if (!inObject)
284
                    //    Type.typeinfostaticarray.error("%s", msg);
285 1
                    Type.typeinfostaticarray = this;
286
                }
287 1
                if (id == Id.TypeInfo_AssociativeArray)
288
                {
289 1
                    if (!inObject)
290 1
                        error("%s", msg);
291 1
                    Type.typeinfoassociativearray = this;
292
                }
293 1
                if (id == Id.TypeInfo_Enum)
294
                {
295 1
                    if (!inObject)
296 1
                        error("%s", msg);
297 1
                    Type.typeinfoenum = this;
298
                }
299 1
                if (id == Id.TypeInfo_Function)
300
                {
301 1
                    if (!inObject)
302 1
                        error("%s", msg);
303 1
                    Type.typeinfofunction = this;
304
                }
305 1
                if (id == Id.TypeInfo_Delegate)
306
                {
307 1
                    if (!inObject)
308 1
                        error("%s", msg);
309 1
                    Type.typeinfodelegate = this;
310
                }
311 1
                if (id == Id.TypeInfo_Tuple)
312
                {
313 1
                    if (!inObject)
314 1
                        error("%s", msg);
315 1
                    Type.typeinfotypelist = this;
316
                }
317 1
                if (id == Id.TypeInfo_Const)
318
                {
319 1
                    if (!inObject)
320 1
                        error("%s", msg);
321 1
                    Type.typeinfoconst = this;
322
                }
323 1
                if (id == Id.TypeInfo_Invariant)
324
                {
325 1
                    if (!inObject)
326 1
                        error("%s", msg);
327 1
                    Type.typeinfoinvariant = this;
328
                }
329 1
                if (id == Id.TypeInfo_Shared)
330
                {
331 1
                    if (!inObject)
332 1
                        error("%s", msg);
333 1
                    Type.typeinfoshared = this;
334
                }
335 1
                if (id == Id.TypeInfo_Wild)
336
                {
337 1
                    if (!inObject)
338 1
                        error("%s", msg);
339 1
                    Type.typeinfowild = this;
340
                }
341 1
                if (id == Id.TypeInfo_Vector)
342
                {
343 1
                    if (!inObject)
344 1
                        error("%s", msg);
345 1
                    Type.typeinfovector = this;
346
                }
347
            }
348

349 1
            if (id == Id.Object)
350
            {
351 1
                if (!inObject)
352 1
                    error("%s", msg);
353 1
                object = this;
354
            }
355

356 1
            if (id == Id.Throwable)
357
            {
358 1
                if (!inObject)
359 1
                    error("%s", msg);
360 1
                throwable = this;
361
            }
362 1
            if (id == Id.Exception)
363
            {
364 1
                if (!inObject)
365 1
                    error("%s", msg);
366 1
                exception = this;
367
            }
368 1
            if (id == Id.Error)
369
            {
370 1
                if (!inObject)
371 1
                    error("%s", msg);
372 1
                errorException = this;
373
            }
374 1
            if (id == Id.cpp_type_info_ptr)
375
            {
376 1
                if (!inObject)
377 0
                    error("%s", msg);
378 1
                cpp_type_info_ptr = this;
379
            }
380
        }
381 1
        baseok = Baseok.none;
382
    }
383

384
    static ClassDeclaration create(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
385
    {
386 0
        return new ClassDeclaration(loc, id, baseclasses, members, inObject);
387
    }
388

389
    override Dsymbol syntaxCopy(Dsymbol s)
390
    {
391
        //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars());
392 1
        ClassDeclaration cd =
393 1
            s ? cast(ClassDeclaration)s
394 1
              : new ClassDeclaration(loc, ident, null, null, false);
395

396 1
        cd.storage_class |= storage_class;
397

398 1
        cd.baseclasses.setDim(this.baseclasses.dim);
399 1
        for (size_t i = 0; i < cd.baseclasses.dim; i++)
400
        {
401 1
            BaseClass* b = (*this.baseclasses)[i];
402 1
            auto b2 = new BaseClass(b.type.syntaxCopy());
403 1
            (*cd.baseclasses)[i] = b2;
404
        }
405

406 1
        return ScopeDsymbol.syntaxCopy(cd);
407
    }
408

409
    override Scope* newScope(Scope* sc)
410
    {
411 1
        auto sc2 = super.newScope(sc);
412 1
        if (isCOMclass())
413
        {
414
            /* This enables us to use COM objects under Linux and
415
             * work with things like XPCOM
416
             */
417 1
            sc2.linkage = target.systemLinkage();
418
        }
419 1
        return sc2;
420
    }
421

422
    /*********************************************
423
     * Determine if 'this' is a base class of cd.
424
     * This is used to detect circular inheritance only.
425
     */
426
    final bool isBaseOf2(ClassDeclaration cd)
427
    {
428 1
        if (!cd)
429 1
            return false;
430
        //printf("ClassDeclaration.isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
431 1
        for (size_t i = 0; i < cd.baseclasses.dim; i++)
432
        {
433 1
            BaseClass* b = (*cd.baseclasses)[i];
434 1
            if (b.sym == this || isBaseOf2(b.sym))
435 1
                return true;
436
        }
437 1
        return false;
438
    }
439

440
    enum OFFSET_RUNTIME = 0x76543210;
441
    enum OFFSET_FWDREF = 0x76543211;
442

443
    /*******************************************
444
     * Determine if 'this' is a base class of cd.
445
     */
446
    bool isBaseOf(ClassDeclaration cd, int* poffset)
447
    {
448
        //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
449 1
        if (poffset)
450 1
            *poffset = 0;
451 1
        while (cd)
452
        {
453
            /* cd.baseClass might not be set if cd is forward referenced.
454
             */
455 1
            if (!cd.baseClass && cd.semanticRun < PASS.semanticdone && !cd.isInterfaceDeclaration())
456
            {
457 1
                cd.dsymbolSemantic(null);
458 1
                if (!cd.baseClass && cd.semanticRun < PASS.semanticdone)
459 0
                    cd.error("base class is forward referenced by `%s`", toChars());
460
            }
461

462 1
            if (this == cd.baseClass)
463 1
                return true;
464

465 1
            cd = cd.baseClass;
466
        }
467 1
        return false;
468
    }
469

470
    /*********************************************
471
     * Determine if 'this' has complete base class information.
472
     * This is used to detect forward references in covariant overloads.
473
     */
474
    final bool isBaseInfoComplete() const
475
    {
476 1
        return baseok >= Baseok.done;
477
    }
478

479
    override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
480
    {
481
        //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
482
        //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
483 1
        if (_scope && baseok < Baseok.done)
484
        {
485 1
            if (!inuse)
486
            {
487
                // must semantic on base class/interfaces
488 1
                inuse = true;
489 1
                dsymbolSemantic(this, null);
490 1
                inuse = false;
491
            }
492
        }
493

494 1
        if (!members || !symtab) // opaque or addMember is not yet done
495
        {
496
            // .stringof is always defined (but may be hidden by some other symbol)
497 1
            if (ident != Id.stringof)
498 1
                error("is forward referenced when looking for `%s`", ident.toChars());
499
            //*(char*)0=0;
500 1
            return null;
501
        }
502

503 1
        auto s = ScopeDsymbol.search(loc, ident, flags);
504

505
        // don't search imports of base classes
506 1
        if (flags & SearchImportsOnly)
507 1
            return s;
508

509 1
        if (!s)
510
        {
511
            // Search bases classes in depth-first, left to right order
512 1
            for (size_t i = 0; i < baseclasses.dim; i++)
513
            {
514 1
                BaseClass* b = (*baseclasses)[i];
515 1
                if (b.sym)
516
                {
517 1
                    if (!b.sym.symtab)
518 0
                        error("base `%s` is forward referenced", b.sym.ident.toChars());
519
                    else
520
                    {
521
                        import dmd.access : symbolIsVisible;
522

523 1
                        s = b.sym.search(loc, ident, flags);
524 1
                        if (!s)
525 1
                            continue;
526 1
                        else if (s == this) // happens if s is nested in this and derives from this
527 1
                            s = null;
528 1
                        else if (!(flags & IgnoreSymbolVisibility) && !(s.prot().kind == Prot.Kind.protected_) && !symbolIsVisible(this, s))
529 1
                            s = null;
530
                        else
531 1
                            break;
532
                    }
533
                }
534
            }
535
        }
536 1
        return s;
537
    }
538

539
    /************************************
540
     * Search base classes in depth-first, left-to-right order for
541
     * a class or interface named 'ident'.
542
     * Stops at first found. Does not look for additional matches.
543
     * Params:
544
     *  ident = identifier to search for
545
     * Returns:
546
     *  ClassDeclaration if found, null if not
547
     */
548
    final ClassDeclaration searchBase(Identifier ident)
549
    {
550 1
        foreach (b; *baseclasses)
551
        {
552 1
            auto cdb = b.type.isClassHandle();
553 1
            if (!cdb) // https://issues.dlang.org/show_bug.cgi?id=10616
554 0
                return null;
555 1
            if (cdb.ident.equals(ident))
556 1
                return cdb;
557 1
            auto result = cdb.searchBase(ident);
558 1
            if (result)
559 1
                return result;
560
        }
561 1
        return null;
562
    }
563

564
    final override void finalizeSize()
565
    {
566 1
        assert(sizeok != Sizeok.done);
567

568
        // Set the offsets of the fields and determine the size of the class
569 1
        if (baseClass)
570
        {
571 1
            assert(baseClass.sizeok == Sizeok.done);
572

573 1
            alignsize = baseClass.alignsize;
574 1
            structsize = baseClass.structsize;
575 1
            if (classKind == ClassKind.cpp && global.params.isWindows)
576 0
                structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
577
        }
578 1
        else if (isInterfaceDeclaration())
579
        {
580 1
            if (interfaces.length == 0)
581
            {
582 1
                alignsize = target.ptrsize;
583 1
                structsize = target.ptrsize;      // allow room for __vptr
584
            }
585
        }
586
        else
587
        {
588 1
            alignsize = target.ptrsize;
589 1
            structsize = target.ptrsize;      // allow room for __vptr
590 1
            if (hasMonitor())
591 1
                structsize += target.ptrsize; // allow room for __monitor
592
        }
593

594
        //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
595 1
        size_t bi = 0;                  // index into vtblInterfaces[]
596

597
        /****
598
         * Runs through the inheritance graph to set the BaseClass.offset fields.
599
         * Recursive in order to account for the size of the interface classes, if they are
600
         * more than just interfaces.
601
         * Params:
602
         *      cd = interface to look at
603
         *      baseOffset = offset of where cd will be placed
604
         * Returns:
605
         *      subset of instantiated size used by cd for interfaces
606
         */
607
        uint membersPlace(ClassDeclaration cd, uint baseOffset)
608
        {
609
            //printf("    membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
610 1
            uint offset = baseOffset;
611

612 1
            foreach (BaseClass* b; cd.interfaces)
613
            {
614 1
                if (b.sym.sizeok != Sizeok.done)
615 1
                    b.sym.finalizeSize();
616 1
                assert(b.sym.sizeok == Sizeok.done);
617

618 1
                if (!b.sym.alignsize)
619 0
                    b.sym.alignsize = target.ptrsize;
620 1
                alignmember(b.sym.alignsize, b.sym.alignsize, &offset);
621 1
                assert(bi < vtblInterfaces.dim);
622

623 1
                BaseClass* bv = (*vtblInterfaces)[bi];
624 1
                if (b.sym.interfaces.length == 0)
625
                {
626
                    //printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
627 1
                    bv.offset = offset;
628 1
                    ++bi;
629
                    // All the base interfaces down the left side share the same offset
630 1
                    for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
631
                    {
632 1
                        b2 = &b2.baseInterfaces[0];
633 1
                        b2.offset = offset;
634
                        //printf("\tvtblInterfaces[%d] b=%p   sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
635
                    }
636
                }
637 1
                membersPlace(b.sym, offset);
638
                //printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
639 1
                offset += b.sym.structsize;
640 1
                if (alignsize < b.sym.alignsize)
641 1
                    alignsize = b.sym.alignsize;
642
            }
643 1
            return offset - baseOffset;
644
        }
645

646 1
        structsize += membersPlace(this, structsize);
647

648 1
        if (isInterfaceDeclaration())
649
        {
650 1
            sizeok = Sizeok.done;
651 1
            return;
652
        }
653

654
        // FIXME: Currently setFieldOffset functions need to increase fields
655
        // to calculate each variable offsets. It can be improved later.
656 1
        fields.setDim(0);
657

658 1
        uint offset = structsize;
659 1
        foreach (s; *members)
660
        {
661 1
            s.setFieldOffset(this, &offset, false);
662
        }
663

664 1
        sizeok = Sizeok.done;
665

666
        // Calculate fields[i].overlapped
667 1
        checkOverlappedFields();
668
    }
669

670
    /**************
671
     * Returns: true if there's a __monitor field
672
     */
673
    final bool hasMonitor()
674
    {
675 1
        return classKind == ClassKind.d;
676
    }
677

678
    override bool isAnonymous()
679
    {
680 1
        return isActuallyAnonymous;
681
    }
682

683
    final bool isFuncHidden(FuncDeclaration fd)
684
    {
685
        //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
686 1
        Dsymbol s = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
687 1
        if (!s)
688
        {
689
            //printf("not found\n");
690
            /* Because, due to a hack, if there are multiple definitions
691
             * of fd.ident, NULL is returned.
692
             */
693 1
            return false;
694
        }
695 1
        s = s.toAlias();
696 1
        if (auto os = s.isOverloadSet())
697
        {
698 1
            foreach (sm; os.a)
699
            {
700 1
                auto fm = sm.isFuncDeclaration();
701 1
                if (overloadApply(fm, s => fd == s.isFuncDeclaration()))
702 1
                    return false;
703
            }
704 0
            return true;
705
        }
706
        else
707
        {
708 1
            auto f = s.isFuncDeclaration();
709
            //printf("%s fdstart = %p\n", s.kind(), fdstart);
710 1
            if (overloadApply(f, s => fd == s.isFuncDeclaration()))
711 1
                return false;
712 1
            return !fd.parent.isTemplateMixin();
713
        }
714
    }
715

716
    /****************
717
     * Find virtual function matching identifier and type.
718
     * Used to build virtual function tables for interface implementations.
719
     * Params:
720
     *  ident = function's identifier
721
     *  tf = function's type
722
     * Returns:
723
     *  function symbol if found, null if not
724
     * Errors:
725
     *  prints error message if more than one match
726
     */
727
    final FuncDeclaration findFunc(Identifier ident, TypeFunction tf)
728
    {
729
        //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars());
730 1
        FuncDeclaration fdmatch = null;
731 1
        FuncDeclaration fdambig = null;
732

733
        void updateBestMatch(FuncDeclaration fd)
734
        {
735 1
            fdmatch = fd;
736 1
            fdambig = null;
737
            //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch.toChars(), fdmatch.type.toChars(), fdmatch.loc.toChars());
738
        }
739

740
        void searchVtbl(ref Dsymbols vtbl)
741
        {
742 1
            foreach (s; vtbl)
743
            {
744 1
                auto fd = s.isFuncDeclaration();
745 1
                if (!fd)
746 1
                    continue;
747

748
                // the first entry might be a ClassInfo
749
                //printf("\t[%d] = %s\n", i, fd.toChars());
750 1
                if (ident == fd.ident && fd.type.covariant(tf) == 1)
751
                {
752
                    //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
753 1
                    if (!fdmatch)
754
                    {
755 1
                        updateBestMatch(fd);
756 1
                        continue;
757
                    }
758 1
                    if (fd == fdmatch)
759 0
                        continue;
760

761
                    {
762
                    // Function type matching: exact > covariant
763 1
                    MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
764 1
                    MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch;
765 1
                    if (m1 > m2)
766
                    {
767 0
                        updateBestMatch(fd);
768 0
                        continue;
769
                    }
770 1
                    else if (m1 < m2)
771 1
                        continue;
772
                    }
773
                    {
774 1
                    MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch;
775 1
                    MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch;
776 1
                    if (m1 > m2)
777
                    {
778 0
                        updateBestMatch(fd);
779 0
                        continue;
780
                    }
781 1
                    else if (m1 < m2)
782 0
                        continue;
783
                    }
784
                    {
785
                    // The way of definition: non-mixin > mixin
786 1
                    MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
787 1
                    MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
788 1
                    if (m1 > m2)
789
                    {
790 1
                        updateBestMatch(fd);
791 1
                        continue;
792
                    }
793 1
                    else if (m1 < m2)
794 1
                        continue;
795
                    }
796

797 1
                    fdambig = fd;
798
                    //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
799
                }
800
                //else printf("\t\t%d\n", fd.type.covariant(tf));
801
            }
802
        }
803

804 1
        searchVtbl(vtbl);
805 1
        for (auto cd = this; cd; cd = cd.baseClass)
806
        {
807 1
            searchVtbl(cd.vtblFinal);
808
        }
809

810 1
        if (fdambig)
811 1
            error("ambiguous virtual function `%s`", fdambig.toChars());
812

813 1
        return fdmatch;
814
    }
815

816
    /****************************************
817
     */
818
    final bool isCOMclass() const
819
    {
820 1
        return com;
821
    }
822

823
    bool isCOMinterface() const
824
    {
825 1
        return false;
826
    }
827

828
    final bool isCPPclass() const
829
    {
830 1
        return classKind == ClassKind.cpp;
831
    }
832

833
    bool isCPPinterface() const
834
    {
835 1
        return false;
836
    }
837

838
    /****************************************
839
     */
840
    final bool isAbstract()
841
    {
842
        enum log = false;
843 1
        if (isabstract != Abstract.fwdref)
844 1
            return isabstract == Abstract.yes;
845

846 1
        if (log) printf("isAbstract(%s)\n", toChars());
847

848 1
        bool no()  { if (log) printf("no\n");  isabstract = Abstract.no;  return false; }
849 1
        bool yes() { if (log) printf("yes\n"); isabstract = Abstract.yes; return true;  }
850

851 1
        if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_)
852 1
            return yes();
853

854 1
        if (errors)
855 1
            return no();
856

857
        /* https://issues.dlang.org/show_bug.cgi?id=11169
858
         * Resolve forward references to all class member functions,
859
         * and determine whether this class is abstract.
860
         */
861
        static int func(Dsymbol s)
862
        {
863 1
            auto fd = s.isFuncDeclaration();
864 1
            if (!fd)
865 1
                return 0;
866 1
            if (fd.storage_class & STC.static_)
867 1
                return 0;
868

869 1
            if (fd.isAbstract())
870 1
                return 1;
871 1
            return 0;
872
        }
873

874 1
        for (size_t i = 0; i < members.dim; i++)
875
        {
876 1
            auto s = (*members)[i];
877 1
            if (s.apply(&func))
878
            {
879 1
                return yes();
880
            }
881
        }
882

883
        /* If the base class is not abstract, then this class cannot
884
         * be abstract.
885
         */
886 1
        if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract()))
887 1
            return no();
888

889
        /* If any abstract functions are inherited, but not overridden,
890
         * then the class is abstract. Do this by checking the vtbl[].
891
         * Need to do semantic() on class to fill the vtbl[].
892
         */
893 1
        this.dsymbolSemantic(null);
894

895
        /* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic()
896
         * is called recursively it can set PASS.semanticdone without finishing it.
897
         */
898
        //if (semanticRun < PASS.semanticdone)
899
        {
900
            /* Could not complete semantic(). Try running semantic() on
901
             * each of the virtual functions,
902
             * which will fill in the vtbl[] overrides.
903
             */
904
            static int virtualSemantic(Dsymbol s)
905
            {
906 1
                auto fd = s.isFuncDeclaration();
907 1
                if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
908 1
                    fd.dsymbolSemantic(null);
909 1
                return 0;
910
            }
911

912 1
            for (size_t i = 0; i < members.dim; i++)
913
            {
914 1
                auto s = (*members)[i];
915 1
                s.apply(&virtualSemantic);
916
            }
917
        }
918

919
        /* Finally, check the vtbl[]
920
         */
921 1
        foreach (i; 1 .. vtbl.dim)
922
        {
923 1
            auto fd = vtbl[i].isFuncDeclaration();
924
            //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars());
925 1
            if (!fd || fd.isAbstract())
926
            {
927 1
                return yes();
928
            }
929
        }
930

931 1
        return no();
932
    }
933

934
    /****************************************
935
     * Determine if slot 0 of the vtbl[] is reserved for something else.
936
     * For class objects, yes, this is where the classinfo ptr goes.
937
     * For COM interfaces, no.
938
     * For non-COM interfaces, yes, this is where the Interface ptr goes.
939
     * Returns:
940
     *      0       vtbl[0] is first virtual function pointer
941
     *      1       vtbl[0] is classinfo/interfaceinfo pointer
942
     */
943
    int vtblOffset() const
944
    {
945 1
        return classKind == ClassKind.cpp ? 0 : 1;
946
    }
947

948
    /****************************************
949
     */
950
    override const(char)* kind() const
951
    {
952 1
        return "class";
953
    }
954

955
    /****************************************
956
     */
957
    override final void addLocalClass(ClassDeclarations* aclasses)
958
    {
959 1
        if (classKind != ClassKind.objc)
960 1
            aclasses.push(this);
961
    }
962

963
    override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
964
    {
965 0
        .objc.addSymbols(this, classes, categories);
966
    }
967

968
    // Back end
969
    Dsymbol vtblsym;
970

971
    final Dsymbol vtblSymbol()
972
    {
973 1
        if (!vtblsym)
974
        {
975 1
            auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.dim);
976 1
            auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_);
977 1
            var.addMember(null, this);
978 1
            var.isdataseg = 1;
979 1
            var.linkage = LINK.d;
980 1
            var.semanticRun = PASS.semanticdone; // no more semantic wanted
981 1
            vtblsym = var;
982
        }
983 1
        return vtblsym;
984
    }
985

986
    override final inout(ClassDeclaration) isClassDeclaration() inout
987
    {
988 1
        return this;
989
    }
990

991
    override void accept(Visitor v)
992
    {
993 1
        v.visit(this);
994
    }
995
}
996

997
/***********************************************************
998
 */
999
extern (C++) final class InterfaceDeclaration : ClassDeclaration
1000
{
1001 1
    extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses)
1002
    {
1003 1
        super(loc, id, baseclasses, null, false);
1004 1
        if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces
1005
        {
1006 1
            com = true;
1007 1
            classKind = ClassKind.cpp; // IUnknown is also a C++ interface
1008
        }
1009
    }
1010

1011
    override Dsymbol syntaxCopy(Dsymbol s)
1012
    {
1013 1
        InterfaceDeclaration id =
1014 0
            s ? cast(InterfaceDeclaration)s
1015 1
              : new InterfaceDeclaration(loc, ident, null);
1016 1
        return ClassDeclaration.syntaxCopy(id);
1017
    }
1018

1019

1020
    override Scope* newScope(Scope* sc)
1021
    {
1022 1
        auto sc2 = super.newScope(sc);
1023 1
        if (com)
1024 1
            sc2.linkage = LINK.windows;
1025 1
        else if (classKind == ClassKind.cpp)
1026 1
            sc2.linkage = LINK.cpp;
1027 1
        else if (classKind == ClassKind.objc)
1028 0
            sc2.linkage = LINK.objc;
1029 1
        return sc2;
1030
    }
1031

1032
    /*******************************************
1033
     * Determine if 'this' is a base class of cd.
1034
     * (Actually, if it is an interface supported by cd)
1035
     * Output:
1036
     *      *poffset        offset to start of class
1037
     *                      OFFSET_RUNTIME  must determine offset at runtime
1038
     * Returns:
1039
     *      false   not a base
1040
     *      true    is a base
1041
     */
1042
    override bool isBaseOf(ClassDeclaration cd, int* poffset)
1043
    {
1044
        //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
1045 1
        assert(!baseClass);
1046 1
        foreach (b; cd.interfaces)
1047
        {
1048
            //printf("\tX base %s\n", b.sym.toChars());
1049 1
            if (this == b.sym)
1050
            {
1051
                //printf("\tfound at offset %d\n", b.offset);
1052 1
                if (poffset)
1053
                {
1054
                    // don't return incorrect offsets
1055
                    // https://issues.dlang.org/show_bug.cgi?id=16980
1056 1
                    *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF;
1057
                }
1058
                // printf("\tfound at offset %d\n", b.offset);
1059 1
                return true;
1060
            }
1061 1
            if (isBaseOf(b, poffset))
1062 1
                return true;
1063
        }
1064 1
        if (cd.baseClass && isBaseOf(cd.baseClass, poffset))
1065 1
            return true;
1066

1067 1
        if (poffset)
1068 1
            *poffset = 0;
1069 1
        return false;
1070
    }
1071

1072
    bool isBaseOf(BaseClass* bc, int* poffset)
1073
    {
1074
        //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", toChars(), bc.sym.toChars());
1075 1
        for (size_t j = 0; j < bc.baseInterfaces.length; j++)
1076
        {
1077 1
            BaseClass* b = &bc.baseInterfaces[j];
1078
            //printf("\tY base %s\n", b.sym.toChars());
1079 1
            if (this == b.sym)
1080
            {
1081
                //printf("\tfound at offset %d\n", b.offset);
1082 1
                if (poffset)
1083
                {
1084 1
                    *poffset = b.offset;
1085
                }
1086 1
                return true;
1087
            }
1088 1
            if (isBaseOf(b, poffset))
1089
            {
1090 1
                return true;
1091
            }
1092
        }
1093

1094 1
        if (poffset)
1095 1
            *poffset = 0;
1096 1
        return false;
1097
    }
1098

1099
    /*******************************************
1100
     */
1101
    override const(char)* kind() const
1102
    {
1103 1
        return "interface";
1104
    }
1105

1106
    /****************************************
1107
     * Determine if slot 0 of the vtbl[] is reserved for something else.
1108
     * For class objects, yes, this is where the ClassInfo ptr goes.
1109
     * For COM interfaces, no.
1110
     * For non-COM interfaces, yes, this is where the Interface ptr goes.
1111
     */
1112
    override int vtblOffset() const
1113
    {
1114 1
        if (isCOMinterface() || isCPPinterface())
1115 1
            return 0;
1116 1
        return 1;
1117
    }
1118

1119
    override bool isCPPinterface() const
1120
    {
1121 1
        return classKind == ClassKind.cpp;
1122
    }
1123

1124
    override bool isCOMinterface() const
1125
    {
1126 1
        return com;
1127
    }
1128

1129
    override inout(InterfaceDeclaration) isInterfaceDeclaration() inout
1130
    {
1131 1
        return this;
1132
    }
1133

1134
    override void accept(Visitor v)
1135
    {
1136 1
        v.visit(this);
1137
    }
1138
}

Read our documentation on viewing source code .

Loading