Example #1
0
void ClassDeclaration::semantic(Scope *sc)
{
    //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
    //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
    //printf("sc->stc = %x\n", sc->stc);

    //{ static int n;  if (++n == 20) *(char*)0=0; }

    if (!ident)         // if anonymous class
    {   const char *id = "__anonclass";

        ident = Identifier::generateId(id);
    }

    if (!sc)
        sc = scope;
    if (!parent && sc->parent && !sc->parent->isModule())
        parent = sc->parent;

    type = type->semantic(loc, sc);

    if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
    {
        TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated();
        if (ti && ti->errors)
            ((TypeClass *)type)->sym = this;
    }

    if (!members)               // if opaque declaration
    {   //printf("\tclass '%s' is forward referenced\n", toChars());
        return;
    }
    if (symtab)
    {   if (sizeok == SIZEOKdone || !scope)
        {   //printf("\tsemantic for '%s' is already completed\n", toChars());
            return;             // semantic() already completed
        }
    }
    else
        symtab = new DsymbolTable();

    Scope *scx = NULL;
    if (scope)
    {
        sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }
    unsigned dprogress_save = Module::dprogress;
    int errors = global.errors;

    if (sc->stc & STCdeprecated)
    {
        isdeprecated = true;
    }
    userAttribDecl = sc->userAttribDecl;

    if (sc->linkage == LINKcpp)
        cpp = 1;

    // Expand any tuples in baseclasses[]
    for (size_t i = 0; i < baseclasses->dim; )
    {
        // Ungag errors when not speculative
        Ungag ungag = ungagSpeculative();

        BaseClass *b = (*baseclasses)[i];
        b->type = b->type->semantic(loc, sc);

        Type *tb = b->type->toBasetype();
        if (tb->ty == Ttuple)
        {   TypeTuple *tup = (TypeTuple *)tb;
            PROT protection = b->protection;
            baseclasses->remove(i);
            size_t dim = Parameter::dim(tup->arguments);
            for (size_t j = 0; j < dim; j++)
            {   Parameter *arg = Parameter::getNth(tup->arguments, j);
                b = new BaseClass(arg->type, protection);
                baseclasses->insert(i + j, b);
            }
        }
        else
            i++;
    }

    // See if there's a base class as first in baseclasses[]
    if (baseclasses->dim)
    {
        // Ungag errors when not speculative
        Ungag ungag = ungagSpeculative();

        BaseClass *b = (*baseclasses)[0];
        //b->type = b->type->semantic(loc, sc);

        Type *tb = b->type->toBasetype();
        if (tb->ty != Tclass)
        {
            if (b->type != Type::terror)
                error("base type must be class or interface, not %s", b->type->toChars());
            baseclasses->remove(0);
        }
        else
        {
            TypeClass *tc = (TypeClass *)(tb);

            if (tc->sym->isDeprecated())
            {
                if (!isDeprecated())
                {
                    // Deriving from deprecated class makes this one deprecated too
                    isdeprecated = true;

                    tc->checkDeprecated(loc, sc);
                }
            }

            if (tc->sym->isInterfaceDeclaration())
                ;
            else
            {
                for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
                {
                    if (cdb == this)
                    {
                        error("circular inheritance");
                        baseclasses->remove(0);
                        goto L7;
                    }
                }
                if (tc->sym->scope)
                {
                    // Try to resolve forward reference
                    tc->sym->semantic(NULL);
                }

                if (tc->sym->symtab && tc->sym->scope == NULL)
                {
                    /* Bugzilla 11034: Essentailly, class inheritance hierarchy
                     * and instance size of each classes are orthogonal information.
                     * Therefore, even if tc->sym->sizeof == SIZEOKnone,
                     * we need to set baseClass field for class covariance check.
                     */
                    baseClass = tc->sym;
                    b->base = baseClass;
                }
                if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == SIZEOKnone)
                {
                    //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars());
                    //error("forward reference of base class %s", baseClass->toChars());
                    // Forward reference of base class, try again later
                    //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
                    scope = scx ? scx : sc->copy();
                    scope->setNoFree();
                    if (tc->sym->scope)
                        tc->sym->scope->module->addDeferredSemantic(tc->sym);
                    scope->module->addDeferredSemantic(this);
                    return;
                }
             L7: ;
            }
        }
    }

    // Treat the remaining entries in baseclasses as interfaces
    // Check for errors, handle forward references
    for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; )
    {
        // Ungag errors when not speculative
        Ungag ungag = ungagSpeculative();

        BaseClass *b = (*baseclasses)[i];
        b->type = b->type->semantic(loc, sc);

        Type *tb = b->type->toBasetype();
        TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
        if (!tc || !tc->sym->isInterfaceDeclaration())
        {
            if (b->type != Type::terror)
                error("base type must be interface, not %s", b->type->toChars());
            baseclasses->remove(i);
            continue;
        }
        else
        {
            if (tc->sym->isDeprecated())
            {
                if (!isDeprecated())
                {
                    // Deriving from deprecated class makes this one deprecated too
                    isdeprecated = true;

                    tc->checkDeprecated(loc, sc);
                }
            }

            // Check for duplicate interfaces
            for (size_t j = (baseClass ? 1 : 0); j < i; j++)
            {
                BaseClass *b2 = (*baseclasses)[j];
                if (b2->base == tc->sym)
                    error("inherits from duplicate interface %s", b2->base->toChars());
            }

            if (tc->sym->scope)
            {
                // Try to resolve forward reference
                tc->sym->semantic(NULL);
            }

            b->base = tc->sym;
            if (!b->base->symtab || b->base->scope)
            {
                //error("forward reference of base class %s", baseClass->toChars());
                // Forward reference of base, try again later
                //printf("\ttry later, forward reference of base %s\n", baseClass->toChars());
                scope = scx ? scx : sc->copy();
                scope->setNoFree();
                if (tc->sym->scope)
                    tc->sym->scope->module->addDeferredSemantic(tc->sym);
                scope->module->addDeferredSemantic(this);
                return;
            }
        }
        i++;
    }
    if (doAncestorsSemantic == SemanticIn)
        doAncestorsSemantic = SemanticDone;


    if (sizeok == SIZEOKnone)
    {
        // If no base class, and this is not an Object, use Object as base class
        if (!baseClass && ident != Id::Object && !cpp)
        {
            if (!object)
            {
                error("missing or corrupt object.d");
                fatal();
            }

            Type *t = object->type;
            t = t->semantic(loc, sc)->toBasetype();
            assert(t->ty == Tclass);
            TypeClass *tc = (TypeClass *)t;

            BaseClass *b = new BaseClass(tc, PROTpublic);
            baseclasses->shift(b);

            baseClass = tc->sym;
            assert(!baseClass->isInterfaceDeclaration());
            b->base = baseClass;
        }

        interfaces_dim = baseclasses->dim;
        interfaces = baseclasses->tdata();

        if (baseClass)
        {
            if (baseClass->storage_class & STCfinal)
                error("cannot inherit from final class %s", baseClass->toChars());

            interfaces_dim--;
            interfaces++;

            // Copy vtbl[] from base class
            vtbl.setDim(baseClass->vtbl.dim);
            memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim);

            // Inherit properties from base class
            com = baseClass->isCOMclass();
            if (baseClass->isCPPclass())
                cpp = 1;
            isscope = baseClass->isscope;
            vthis = baseClass->vthis;
            enclosing = baseClass->enclosing;
            storage_class |= baseClass->storage_class & STC_TYPECTOR;
        }
        else
        {
            // No base class, so this is the root of the class hierarchy
            vtbl.setDim(0);
            if (vtblOffset())
                vtbl.push(this);            // leave room for classinfo as first member
        }

        protection = sc->protection;
        storage_class |= sc->stc;

        interfaceSemantic(sc);

        for (size_t i = 0; i < members->dim; i++)
        {
            Dsymbol *s = (*members)[i];
            s->addMember(sc, this, 1);
        }

        /* If this is a nested class, add the hidden 'this'
         * member which is a pointer to the enclosing scope.
         */
        if (vthis)              // if inheriting from nested class
        {
            // Use the base class's 'this' member
            if (storage_class & STCstatic)
                error("static class cannot inherit from nested class %s", baseClass->toChars());
            if (toParent2() != baseClass->toParent2() &&
                (!toParent2() ||
                 !baseClass->toParent2()->getType() ||
                 !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL)))
            {
                if (toParent2())
                {
                    error("is nested within %s, but super class %s is nested within %s",
                        toParent2()->toChars(),
                        baseClass->toChars(),
                        baseClass->toParent2()->toChars());
                }
                else
                {
                    error("is not nested, but super class %s is nested within %s",
                        baseClass->toChars(),
                        baseClass->toParent2()->toChars());
                }
                enclosing = NULL;
            }
        }
        else
            makeNested();

        if (storage_class & STCauto)
            error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?");
        if (storage_class & STCscope)
            isscope = true;
        if (storage_class & STCabstract)
            isabstract = 1;
    }

    sc = sc->push(this);
    //sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared);
    //sc->stc |= storage_class & STC_TYPECTOR;
    sc->stc &= STCsafe | STCtrusted | STCsystem;
    sc->parent = this;
    sc->inunion = 0;
    if (isCOMclass())
    {
        if (global.params.isWindows)
            sc->linkage = LINKwindows;
        else
            /* This enables us to use COM objects under Linux and
             * work with things like XPCOM
             */
            sc->linkage = LINKc;
    }
    sc->protection = PROTpublic;
    sc->explicitProtection = 0;
    sc->structalign = STRUCTALIGN_DEFAULT;
    if (baseClass)
    {
        sc->offset = baseClass->structsize;
        alignsize = baseClass->alignsize;
        sc->offset = (sc->offset + alignsize - 1) & ~(alignsize - 1);
//      if (enclosing)
//          sc->offset += Target::ptrsize;      // room for uplevel context pointer
    }
    else
    {
        if (cpp)
            sc->offset = Target::ptrsize;       // allow room for __vptr
        else
            sc->offset = Target::ptrsize * 2;   // allow room for __vptr and __monitor
        alignsize = Target::ptrsize;
    }
    sc->userAttribDecl = NULL;
    structsize = sc->offset;
    Scope scsave = *sc;
    size_t members_dim = members->dim;
    sizeok = SIZEOKnone;

    /* Set scope so if there are forward references, we still might be able to
     * resolve individual members like enums.
     */
    for (size_t i = 0; i < members_dim; i++)
    {
        Dsymbol *s = (*members)[i];
        //printf("[%d] setScope %s %s, sc = %p\n", i, s->kind(), s->toChars(), sc);
        s->setScope(sc);
    }

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->importAll(sc);
    }

    for (size_t i = 0; i < members_dim; i++)
    {
        Dsymbol *s = (*members)[i];

        // Ungag errors when not speculative
        Ungag ungag = ungagSpeculative();
        s->semantic(sc);
    }

    // Set the offsets of the fields and determine the size of the class

    unsigned offset = structsize;
    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->setFieldOffset(this, &offset, false);
    }
    sc->offset = structsize;

    if (global.errors != errors)
    {
        // The type is no good.
        type = Type::terror;
    }

    if (sizeok == SIZEOKfwd)            // failed due to forward references
    {
        // semantic() failed due to forward references
        // Unwind what we did, and defer it for later
        for (size_t i = 0; i < fields.dim; i++)
        {
            VarDeclaration *v = fields[i];
            v->offset = 0;
        }
        fields.setDim(0);
        structsize = 0;
        alignsize = 0;
//        structalign = 0;

        sc = sc->pop();

        scope = scx ? scx : sc->copy();
        scope->setNoFree();
        scope->module->addDeferredSemantic(this);

        Module::dprogress = dprogress_save;

        //printf("\tsemantic('%s') failed due to forward references\n", toChars());
        return;
    }

    //printf("\tsemantic('%s') successful\n", toChars());

    //members->print();

    /* Look for special member functions.
     * They must be in this class, not in a base class.
     */
    searchCtor();
    if (ctor && (ctor->toParent() != this || !(ctor->isCtorDeclaration() || ctor->isTemplateDeclaration())))
        ctor = NULL;    // search() looks through ancestor classes
    if (!ctor && noDefaultCtor)
    {
        // A class object is always created by constructor, so this check is legitimate.
        for (size_t i = 0; i < fields.dim; i++)
        {
            VarDeclaration *v = fields[i];
            if (v->storage_class & STCnodefaultctor)
                ::error(v->loc, "field %s must be initialized in constructor", v->toChars());
        }
    }

    inv = buildInv(this, sc);

    // Can be in base class
    aggNew    =    (NewDeclaration *)search(Loc(), Id::classNew);
    aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete);

    // If this class has no constructor, but base class has a default
    // ctor, create a constructor:
    //    this() { }
    if (!ctor && baseClass && baseClass->ctor)
    {
        FuncDeclaration *fd = resolveFuncCall(loc, sc, baseClass->ctor, NULL, NULL, NULL, 1);
        if (fd && !fd->errors)
        {
            //printf("Creating default this(){} for class %s\n", toChars());
            TypeFunction *btf = (TypeFunction *)fd->type;
            TypeFunction *tf = new TypeFunction(NULL, NULL, 0, LINKd, fd->storage_class);
            tf->purity = btf->purity;
            tf->isnothrow = btf->isnothrow;
            tf->trust = btf->trust;
            CtorDeclaration *ctor = new CtorDeclaration(loc, Loc(), 0, tf);
            ctor->fbody = new CompoundStatement(Loc(), new Statements());
            members->push(ctor);
            ctor->addMember(sc, this, 1);
            *sc = scsave;   // why? What about sc->nofree?
            ctor->semantic(sc);
            this->ctor = ctor;
            defaultCtor = ctor;
        }
        else
        {
            error("Cannot implicitly generate a default ctor when base class %s is missing a default ctor", baseClass->toPrettyChars());
        }
    }

#if 0
    if (baseClass)
    {   if (!aggDelete)
            aggDelete = baseClass->aggDelete;
        if (!aggNew)
            aggNew = baseClass->aggNew;
    }
#endif

    // Allocate instance of each new interface
    sc->offset = structsize;
    for (size_t i = 0; i < vtblInterfaces->dim; i++)
    {
        BaseClass *b = (*vtblInterfaces)[i];
        unsigned thissize = Target::ptrsize;

        alignmember(STRUCTALIGN_DEFAULT, thissize, &sc->offset);
        assert(b->offset == 0);
        b->offset = sc->offset;

        // Take care of single inheritance offsets
        while (b->baseInterfaces_dim)
        {
            b = &b->baseInterfaces[0];
            b->offset = sc->offset;
        }

        sc->offset += thissize;
        if (alignsize < thissize)
            alignsize = thissize;
    }
    structsize = sc->offset;
    sizeok = SIZEOKdone;
    Module::dprogress++;

    dtor = buildDtor(this, sc);
    if (FuncDeclaration *f = hasIdentityOpAssign(this, sc))
    {
        if (!(f->storage_class & STCdisable))
            error(f->loc, "identity assignment operator overload is illegal");
    }
    sc->pop();

#if 0 // Do not call until toObjfile() because of forward references
    // Fill in base class vtbl[]s
    for (i = 0; i < vtblInterfaces->dim; i++)
    {
        BaseClass *b = (*vtblInterfaces)[i];

        //b->fillVtbl(this, &b->vtbl, 1);
    }
#endif
    //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);

    if (deferred && !global.gag)
    {
        deferred->semantic2(sc);
        deferred->semantic3(sc);
    }

#if 0
    if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
    {
        printf("this = %p %s\n", this, this->toChars());
        printf("type = %d sym = %p\n", type->ty, ((TypeClass *)type)->sym);
      }
#endif
    assert(type->ty != Tclass || ((TypeClass *)type)->sym == this);
}
Example #2
0
void InterfaceDeclaration::semantic(Scope *sc)
{
    //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
    if (inuse)
        return;

    if (!sc)
        sc = scope;
    if (!parent && sc->parent && !sc->parent->isModule())
        parent = sc->parent;

    type = type->semantic(loc, sc);
    handle = type;

    if (!members)                       // if forward reference
    {   //printf("\tinterface '%s' is forward referenced\n", toChars());
        return;
    }
    if (symtab)                 // if already done
    {   if (!scope)
            return;
    }
    else
        symtab = new DsymbolTable();

    Scope *scx = NULL;
    if (scope)
    {   sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }

#if IN_GCC
    if (attributes)
        attributes->append(sc->attributes);
    else
        attributes = sc->attributes;
#endif

    if (sc->stc & STCdeprecated)
    {
        isdeprecated = 1;
    }

    // Expand any tuples in baseclasses[]
    for (size_t i = 0; i < baseclasses->dim; )
    {   BaseClass *b = baseclasses->tdata()[0];
        b->type = b->type->semantic(loc, sc);
        Type *tb = b->type->toBasetype();

        if (tb->ty == Ttuple)
        {   TypeTuple *tup = (TypeTuple *)tb;
            enum PROT protection = b->protection;
            baseclasses->remove(i);
            size_t dim = Parameter::dim(tup->arguments);
            for (size_t j = 0; j < dim; j++)
            {   Parameter *arg = Parameter::getNth(tup->arguments, j);
                b = new BaseClass(arg->type, protection);
                baseclasses->insert(i + j, b);
            }
        }
        else
            i++;
    }

    if (!baseclasses->dim && sc->linkage == LINKcpp)
        cpp = 1;

    // Check for errors, handle forward references
    for (size_t i = 0; i < baseclasses->dim; )
    {   TypeClass *tc;
        BaseClass *b;
        Type *tb;

        b = baseclasses->tdata()[i];
        b->type = b->type->semantic(loc, sc);
        tb = b->type->toBasetype();
        if (tb->ty == Tclass)
            tc = (TypeClass *)tb;
        else
            tc = NULL;
        if (!tc || !tc->sym->isInterfaceDeclaration())
        {
            error("base type must be interface, not %s", b->type->toChars());
            baseclasses->remove(i);
            continue;
        }
        else
        {
            // Check for duplicate interfaces
            for (size_t j = 0; j < i; j++)
            {
                BaseClass *b2 = baseclasses->tdata()[j];
                if (b2->base == tc->sym)
                    error("inherits from duplicate interface %s", b2->base->toChars());
            }

            b->base = tc->sym;
            if (b->base == this || isBaseOf2(b->base))
            {
                error("circular inheritance of interface");
                baseclasses->remove(i);
                continue;
            }
            if (!b->base->symtab)
            {   // Try to resolve forward reference
                if (sc->mustsemantic && b->base->scope)
                    b->base->semantic(NULL);
            }
            if (!b->base->symtab || b->base->scope || b->base->inuse)
            {
                //error("forward reference of base class %s", baseClass->toChars());
                // Forward reference of base, try again later
                //printf("\ttry later, forward reference of base %s\n", b->base->toChars());
                scope = scx ? scx : new Scope(*sc);
                scope->setNoFree();
                scope->module->addDeferredSemantic(this);
                return;
            }
        }
#if 0
        // Inherit const/invariant from base class
        storage_class |= b->base->storage_class & STC_TYPECTOR;
#endif
        i++;
    }

    interfaces_dim = baseclasses->dim;
    interfaces = baseclasses->tdata();

    interfaceSemantic(sc);

    if (vtblOffset())
        vtbl.push(this);                // leave room at vtbl[0] for classinfo

    // Cat together the vtbl[]'s from base interfaces
    for (size_t i = 0; i < interfaces_dim; i++)
    {   BaseClass *b = interfaces[i];

        // Skip if b has already appeared
        for (int k = 0; k < i; k++)
        {
            if (b == interfaces[k])
                goto Lcontinue;
        }

        // Copy vtbl[] from base class
        if (b->base->vtblOffset())
        {   int d = b->base->vtbl.dim;
            if (d > 1)
            {
                vtbl.reserve(d - 1);
                for (int j = 1; j < d; j++)
                    vtbl.push(b->base->vtbl.tdata()[j]);
            }
        }
        else
        {
            vtbl.append(&b->base->vtbl);
        }

      Lcontinue:
        ;
    }

    protection = sc->protection;
    storage_class |= sc->stc & STC_TYPECTOR;

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = members->tdata()[i];
        s->addMember(sc, this, 1);
    }

    sc = sc->push(this);
    sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
                 STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared);
    sc->stc |= storage_class & STC_TYPECTOR;
#if IN_GCC
    sc->attributes = NULL;
#endif
    sc->parent = this;
    if (isCOMinterface())
        sc->linkage = LINKwindows;
    else if (isCPPinterface())
        sc->linkage = LINKcpp;
    sc->structalign = 8;
    structalign = sc->structalign;
    sc->offset = PTRSIZE * 2;
    inuse++;
    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = members->tdata()[i];
        s->semantic(sc);
    }
    inuse--;
    //members->print();
    sc->pop();
    //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
}
Example #3
0
void InterfaceDeclaration::semantic(Scope *sc)
{
    //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
    if (inuse)
        return;

    if (!sc)
        sc = scope;
    if (!parent && sc->parent && !sc->parent->isModule())
        parent = sc->parent;

    type = type->semantic(loc, sc);

    if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
    {
        TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated();
        if (ti && ti->errors)
            ((TypeClass *)type)->sym = this;
    }

    if (!members)                       // if forward reference
    {   //printf("\tinterface '%s' is forward referenced\n", toChars());
        return;
    }
    if (symtab)                 // if already done
    {   if (!scope)
            return;
    }
    else
        symtab = new DsymbolTable();

    Scope *scx = NULL;
    if (scope)
    {
        sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }

    int errors = global.errors;

    if (sc->stc & STCdeprecated)
    {
        isdeprecated = true;
    }
    userAttribDecl = sc->userAttribDecl;

    // Expand any tuples in baseclasses[]
    for (size_t i = 0; i < baseclasses->dim; )
    {
        // Ungag errors when not speculative
        Ungag ungag = ungagSpeculative();

        BaseClass *b = (*baseclasses)[i];
        b->type = b->type->semantic(loc, sc);

        Type *tb = b->type->toBasetype();
        if (tb->ty == Ttuple)
        {   TypeTuple *tup = (TypeTuple *)tb;
            PROT protection = b->protection;
            baseclasses->remove(i);
            size_t dim = Parameter::dim(tup->arguments);
            for (size_t j = 0; j < dim; j++)
            {   Parameter *arg = Parameter::getNth(tup->arguments, j);
                b = new BaseClass(arg->type, protection);
                baseclasses->insert(i + j, b);
            }
        }
        else
            i++;
    }

    if (!baseclasses->dim && sc->linkage == LINKcpp)
        cpp = 1;

    // Check for errors, handle forward references
    for (size_t i = 0; i < baseclasses->dim; )
    {
        // Ungag errors when not speculative
        Ungag ungag = ungagSpeculative();

        BaseClass *b = (*baseclasses)[i];
        b->type = b->type->semantic(loc, sc);

        Type *tb = b->type->toBasetype();
        TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
        if (!tc || !tc->sym->isInterfaceDeclaration())
        {
            if (b->type != Type::terror)
                error("base type must be interface, not %s", b->type->toChars());
            baseclasses->remove(i);
            continue;
        }
        else
        {
            // Check for duplicate interfaces
            for (size_t j = 0; j < i; j++)
            {
                BaseClass *b2 = (*baseclasses)[j];
                if (b2->base == tc->sym)
                    error("inherits from duplicate interface %s", b2->base->toChars());
            }

            b->base = tc->sym;
            if (b->base == this || isBaseOf2(b->base))
            {
                error("circular inheritance of interface");
                baseclasses->remove(i);
                continue;
            }
            if (b->base->scope)
            {
                // Try to resolve forward reference
                b->base->semantic(NULL);
            }
            if (!b->base->symtab || b->base->scope || b->base->inuse)
            {
                //error("forward reference of base class %s", baseClass->toChars());
                // Forward reference of base, try again later
                //printf("\ttry later, forward reference of base %s\n", b->base->toChars());
                scope = scx ? scx : sc->copy();
                scope->setNoFree();
                scope->module->addDeferredSemantic(this);
                return;
            }
        }
#if 0
        // Inherit const/invariant from base class
        storage_class |= b->base->storage_class & STC_TYPECTOR;
#endif
        i++;
    }
    if (doAncestorsSemantic == SemanticIn)
        doAncestorsSemantic = SemanticDone;

    interfaces_dim = baseclasses->dim;
    interfaces = baseclasses->tdata();

    interfaceSemantic(sc);

    if (vtblOffset())
        vtbl.push(this);                // leave room at vtbl[0] for classinfo

    // Cat together the vtbl[]'s from base interfaces
    for (size_t i = 0; i < interfaces_dim; i++)
    {   BaseClass *b = interfaces[i];

        // Skip if b has already appeared
        for (size_t k = 0; k < i; k++)
        {
            if (b == interfaces[k])
                goto Lcontinue;
        }

        // Copy vtbl[] from base class
        if (b->base->vtblOffset())
        {   size_t d = b->base->vtbl.dim;
            if (d > 1)
            {
                vtbl.reserve(d - 1);
                for (size_t j = 1; j < d; j++)
                    vtbl.push(b->base->vtbl[j]);
            }
        }
        else
        {
            vtbl.append(&b->base->vtbl);
        }

      Lcontinue:
        ;
    }

    protection = sc->protection;
    storage_class |= sc->stc & STC_TYPECTOR;

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->addMember(sc, this, 1);
    }

    sc = sc->push(this);
    sc->stc &= STCsafe | STCtrusted | STCsystem;
    sc->parent = this;
    if (com)
        sc->linkage = LINKwindows;
    else if (cpp)
        sc->linkage = LINKcpp;
    sc->structalign = STRUCTALIGN_DEFAULT;
    sc->protection = PROTpublic;
    sc->explicitProtection = 0;
//    structalign = sc->structalign;
    sc->offset = Target::ptrsize * 2;
    sc->userAttribDecl = NULL;
    structsize = sc->offset;
    inuse++;

    /* Set scope so if there are forward references, we still might be able to
     * resolve individual members like enums.
     */
    for (size_t i = 0; i < members->dim; i++)
    {   Dsymbol *s = (*members)[i];
        /* There are problems doing this in the general case because
         * Scope keeps track of things like 'offset'
         */
        if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident))
        {
            //printf("setScope %s %s\n", s->kind(), s->toChars());
            s->setScope(sc);
        }
    }

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->importAll(sc);
    }

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];

        // Ungag errors when not speculative
        Ungag ungag = ungagSpeculative();
        s->semantic(sc);
    }

    if (global.errors != errors)
    {   // The type is no good.
        type = Type::terror;
    }

    inuse--;
    //members->print();
    sc->pop();
    //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);

#if 0
    if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
    {
        printf("this = %p %s\n", this, this->toChars());
        printf("type = %d sym = %p\n", type->ty, ((TypeClass *)type)->sym);
      }
#endif
    assert(type->ty != Tclass || ((TypeClass *)type)->sym == this);
}
Example #4
0
void ClassDeclaration::toObjFile(int multiobj)
{
    unsigned offset;
    Symbol *sinit;
    enum_SC scclass;

    //printf("ClassDeclaration::toObjFile('%s')\n", toChars());

    if (type->ty == Terror)
    {   error("had semantic errors when compiling");
        return;
    }

    if (!members)
        return;

    if (multiobj && !hasStaticCtorOrDtor())
    {   obj_append(this);
        return;
    }

    if (global.params.symdebug)
        toDebug(this);

    assert(!scope);     // semantic() should have been run to completion

    scclass = SCglobal;
    if (isInstantiated())
        scclass = SCcomdat;

    // Put out the members
    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *member = (*members)[i];
        /* There might be static ctors in the members, and they cannot
         * be put in separate obj files.
         */
        member->toObjFile(multiobj);
    }

    // Generate C symbols
    toSymbol(this);
    toVtblSymbol();
    sinit = toInitializer();

    //////////////////////////////////////////////

    // Generate static initializer
    sinit->Sclass = scclass;
    sinit->Sfl = FLdata;
    ClassDeclaration_toDt(this, &sinit->Sdt);
    out_readonly(sinit);
    outdata(sinit);

    //////////////////////////////////////////////

    // Put out the TypeInfo
    type->genTypeInfo(NULL);
    //type->vtinfo->toObjFile(multiobj);

    //////////////////////////////////////////////

    // Put out the ClassInfo
    csym->Sclass = scclass;
    csym->Sfl = FLdata;

    /* The layout is:
       {
            void **vptr;
            monitor_t monitor;
            byte[] initializer;         // static initialization data
            char[] name;                // class name
            void *[] vtbl;
            Interface[] interfaces;
            ClassInfo *base;            // base class
            void *destructor;
            void *invariant;            // class invariant
            ClassFlags flags;
            void *deallocator;
            OffsetTypeInfo[] offTi;
            void *defaultConstructor;
            //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
            void *xgetRTInfo;
            //TypeInfo typeinfo;
       }
     */
    dt_t *dt = NULL;
    unsigned classinfo_size = global.params.isLP64 ? CLASSINFO_SIZE_64 : CLASSINFO_SIZE;    // must be ClassInfo.size
    offset = classinfo_size;
    if (Type::typeinfoclass)
    {
        if (Type::typeinfoclass->structsize != classinfo_size)
        {
#ifdef DEBUG
            printf("CLASSINFO_SIZE = x%x, Type::typeinfoclass->structsize = x%x\n", offset, Type::typeinfoclass->structsize);
#endif
            error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
            fatal();
        }
    }

    if (Type::typeinfoclass)
        dtxoff(&dt, Type::typeinfoclass->toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo
    else
        dtsize_t(&dt, 0);                // BUG: should be an assert()
    dtsize_t(&dt, 0);                    // monitor

    // initializer[]
    assert(structsize >= 8 || (cpp && structsize >= 4));
    dtsize_t(&dt, structsize);           // size
    dtxoff(&dt, sinit, 0, TYnptr);      // initializer

    // name[]
    const char *name = ident->toChars();
    size_t namelen = strlen(name);
    if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0))
    {   name = toPrettyChars();
        namelen = strlen(name);
    }
    dtsize_t(&dt, namelen);
    dtabytes(&dt, TYnptr, 0, namelen + 1, name);

    // vtbl[]
    dtsize_t(&dt, vtbl.dim);
    dtxoff(&dt, vtblsym, 0, TYnptr);

    // interfaces[]
    dtsize_t(&dt, vtblInterfaces->dim);
    if (vtblInterfaces->dim)
        dtxoff(&dt, csym, offset, TYnptr);      // (*)
    else
        dtsize_t(&dt, 0);

    // base
    if (baseClass)
        dtxoff(&dt, toSymbol(baseClass), 0, TYnptr);
    else
        dtsize_t(&dt, 0);

    // destructor
    if (dtor)
        dtxoff(&dt, toSymbol(dtor), 0, TYnptr);
    else
        dtsize_t(&dt, 0);

    // invariant
    if (inv)
        dtxoff(&dt, toSymbol(inv), 0, TYnptr);
    else
        dtsize_t(&dt, 0);

    // flags
    ClassFlags::Type flags = ClassFlags::hasOffTi;
    if (isCOMclass()) flags |= ClassFlags::isCOMclass;
    if (isCPPclass()) flags |= ClassFlags::isCPPclass;
    flags |= ClassFlags::hasGetMembers;
    flags |= ClassFlags::hasTypeInfo;
    if (ctor)
        flags |= ClassFlags::hasCtor;
    if (isabstract)
        flags |= ClassFlags::isAbstract;
    for (ClassDeclaration *cd = this; cd; cd = cd->baseClass)
    {
        if (cd->members)
        {
            for (size_t i = 0; i < cd->members->dim; i++)
            {
                Dsymbol *sm = (*cd->members)[i];
                //printf("sm = %s %s\n", sm->kind(), sm->toChars());
                if (sm->hasPointers())
                    goto L2;
            }
        }
    }
    flags |= ClassFlags::noPointers;
L2:
    dtsize_t(&dt, flags);


    // deallocator
    if (aggDelete)
        dtxoff(&dt, toSymbol(aggDelete), 0, TYnptr);
    else
        dtsize_t(&dt, 0);

    // offTi[]
    dtsize_t(&dt, 0);
    dtsize_t(&dt, 0);            // null for now, fix later

    // defaultConstructor
    if (defaultCtor)
        dtxoff(&dt, toSymbol(defaultCtor), 0, TYnptr);
    else
        dtsize_t(&dt, 0);

    // xgetRTInfo
    if (getRTInfo)
        getRTInfo->toDt(&dt);
    else if (flags & ClassFlags::noPointers)
        dtsize_t(&dt, 0);
    else
        dtsize_t(&dt, 1);

    //dtxoff(&dt, toSymbol(type->vtinfo), 0, TYnptr); // typeinfo

    //////////////////////////////////////////////

    // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
    // of the fixup (*)

    offset += vtblInterfaces->dim * (4 * Target::ptrsize);
    for (size_t i = 0; i < vtblInterfaces->dim; i++)
    {   BaseClass *b = (*vtblInterfaces)[i];
        ClassDeclaration *id = b->base;

        /* The layout is:
         *  struct Interface
         *  {
         *      ClassInfo *interface;
         *      void *[] vtbl;
         *      size_t offset;
         *  }
         */

        // Fill in vtbl[]
        b->fillVtbl(this, &b->vtbl, 1);

        dtxoff(&dt, toSymbol(id), 0, TYnptr);         // ClassInfo

        // vtbl[]
        dtsize_t(&dt, id->vtbl.dim);
        dtxoff(&dt, csym, offset, TYnptr);

        dtsize_t(&dt, b->offset);                        // this offset

        offset += id->vtbl.dim * Target::ptrsize;
    }

    // Put out the (*vtblInterfaces)[].vtbl[]
    // This must be mirrored with ClassDeclaration::baseVtblOffset()
    //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces->dim, toChars());
    for (size_t i = 0; i < vtblInterfaces->dim; i++)
    {   BaseClass *b = (*vtblInterfaces)[i];
        ClassDeclaration *id = b->base;

        //printf("    interface[%d] is '%s'\n", i, id->toChars());
        size_t j = 0;
        if (id->vtblOffset())
        {
            // First entry is ClassInfo reference
            //dtxoff(&dt, toSymbol(id), 0, TYnptr);

            // First entry is struct Interface reference
            dtxoff(&dt, csym, classinfo_size + i * (4 * Target::ptrsize), TYnptr);
            j = 1;
        }
        assert(id->vtbl.dim == b->vtbl.dim);
        for (; j < id->vtbl.dim; j++)
        {
            assert(j < b->vtbl.dim);
#if 0
            RootObject *o = b->vtbl[j];
            if (o)
            {
                printf("o = %p\n", o);
                assert(o->dyncast() == DYNCAST_DSYMBOL);
                Dsymbol *s = (Dsymbol *)o;
                printf("s->kind() = '%s'\n", s->kind());
            }
#endif
            FuncDeclaration *fd = b->vtbl[j];
            if (fd)
                dtxoff(&dt, fd->toThunkSymbol(b->offset), 0, TYnptr);
            else
                dtsize_t(&dt, 0);
        }
    }

    // Put out the overriding interface vtbl[]s.
    // This must be mirrored with ClassDeclaration::baseVtblOffset()
    //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
    ClassDeclaration *cd;
    FuncDeclarations bvtbl;

    for (cd = this->baseClass; cd; cd = cd->baseClass)
    {
        for (size_t k = 0; k < cd->vtblInterfaces->dim; k++)
        {   BaseClass *bs = (*cd->vtblInterfaces)[k];

            if (bs->fillVtbl(this, &bvtbl, 0))
            {
                //printf("\toverriding vtbl[] for %s\n", bs->base->toChars());
                ClassDeclaration *id = bs->base;

                size_t j = 0;
                if (id->vtblOffset())
                {
                    // First entry is ClassInfo reference
                    //dtxoff(&dt, toSymbol(id), 0, TYnptr);

                    // First entry is struct Interface reference
                    dtxoff(&dt, toSymbol(cd), classinfo_size + k * (4 * Target::ptrsize), TYnptr);
                    j = 1;
                }

                for (; j < id->vtbl.dim; j++)
                {
                    FuncDeclaration *fd;

                    assert(j < bvtbl.dim);
                    fd = bvtbl[j];
                    if (fd)
                        dtxoff(&dt, fd->toThunkSymbol(bs->offset), 0, TYnptr);
                    else
                        dtsize_t(&dt, 0);
                }
            }
        }
    }

    csym->Sdt = dt;
    // ClassInfo cannot be const data, because we use the monitor on it
    outdata(csym);
    if (isExport())
        objmod->export_symbol(csym,0);

    //////////////////////////////////////////////

    // Put out the vtbl[]
    //printf("putting out %s.vtbl[]\n", toChars());
    dt = NULL;
    if (vtblOffset())
        dtxoff(&dt, csym, 0, TYnptr);           // first entry is ClassInfo reference
    for (size_t i = vtblOffset(); i < vtbl.dim; i++)
    {
        FuncDeclaration *fd = vtbl[i]->isFuncDeclaration();

        //printf("\tvtbl[%d] = %p\n", i, fd);
        if (fd && (fd->fbody || !isAbstract()))
        {
            // Ensure function has a return value (Bugzilla 4869)
            fd->functionSemantic();

            Symbol *s = toSymbol(fd);

            if (isFuncHidden(fd))
            {   /* fd is hidden from the view of this class.
                 * If fd overlaps with any function in the vtbl[], then
                 * issue 'hidden' error.
                 */
                for (size_t j = 1; j < vtbl.dim; j++)
                {   if (j == i)
                        continue;
                    FuncDeclaration *fd2 = vtbl[j]->isFuncDeclaration();
                    if (!fd2->ident->equals(fd->ident))
                        continue;
                    if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd))
                    {
                        TypeFunction *tf = (TypeFunction *)fd->type;
                        if (tf->ty == Tfunction)
                            deprecation("use of %s%s hidden by %s is deprecated. Use 'alias %s.%s %s;' to introduce base class overload set.", fd->toPrettyChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), toChars(), fd->parent->toChars(), fd->toChars(), fd->toChars());
                        else
                            deprecation("use of %s hidden by %s is deprecated", fd->toPrettyChars(), toChars());
                        s = rtlsym[RTLSYM_DHIDDENFUNC];
                        break;
                    }
                }
            }

            dtxoff(&dt, s, 0, TYnptr);
        }
        else
            dtsize_t(&dt, 0);
    }
    vtblsym->Sdt = dt;
    vtblsym->Sclass = scclass;
    vtblsym->Sfl = FLdata;
    out_readonly(vtblsym);
    outdata(vtblsym);
    if (isExport())
        objmod->export_symbol(vtblsym,0);
}