aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/dstruct.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/dstruct.c')
-rw-r--r--gcc/d/dmd/dstruct.c1303
1 files changed, 0 insertions, 1303 deletions
diff --git a/gcc/d/dmd/dstruct.c b/gcc/d/dmd/dstruct.c
deleted file mode 100644
index 9862159..0000000
--- a/gcc/d/dmd/dstruct.c
+++ /dev/null
@@ -1,1303 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/struct.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-
-#include "errors.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "mtype.h"
-#include "init.h"
-#include "declaration.h"
-#include "module.h"
-#include "id.h"
-#include "statement.h"
-#include "template.h"
-#include "tokens.h"
-#include "target.h"
-#include "utf.h"
-#include "root/ctfloat.h"
-
-Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
-void unSpeculative(Scope *sc, RootObject *o);
-bool MODimplicitConv(MOD modfrom, MOD modto);
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-
-FuncDeclaration *StructDeclaration::xerreq; // object.xopEquals
-FuncDeclaration *StructDeclaration::xerrcmp; // object.xopCmp
-
-/***************************************
- * Search toString member function for TypeInfo_Struct.
- * string toString();
- */
-FuncDeclaration *search_toString(StructDeclaration *sd)
-{
- Dsymbol *s = search_function(sd, Id::tostring);
- FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
- if (fd)
- {
- static TypeFunction *tftostring;
- if (!tftostring)
- {
- tftostring = new TypeFunction(ParameterList(), Type::tstring, LINKd);
- tftostring = tftostring->merge()->toTypeFunction();
- }
-
- fd = fd->overloadExactMatch(tftostring);
- }
- return fd;
-}
-
-/***************************************
- * Request additonal semantic analysis for TypeInfo generation.
- */
-void semanticTypeInfo(Scope *sc, Type *t)
-{
- class FullTypeInfoVisitor : public Visitor
- {
- public:
- Scope *sc;
-
- void visit(Type *t)
- {
- Type *tb = t->toBasetype();
- if (tb != t)
- tb->accept(this);
- }
- void visit(TypeNext *t)
- {
- if (t->next)
- t->next->accept(this);
- }
- void visit(TypeBasic *) { }
- void visit(TypeVector *t)
- {
- t->basetype->accept(this);
- }
- void visit(TypeAArray *t)
- {
- t->index->accept(this);
- visit((TypeNext *)t);
- }
- void visit(TypeFunction *t)
- {
- visit((TypeNext *)t);
- // Currently TypeInfo_Function doesn't store parameter types.
- }
- void visit(TypeStruct *t)
- {
- //printf("semanticTypeInfo::visit(TypeStruct = %s)\n", t->toChars());
- StructDeclaration *sd = t->sym;
-
- /* Step 1: create TypeInfoDeclaration
- */
- if (!sc) // inline may request TypeInfo.
- {
- Scope scx;
- scx._module = sd->getModule();
- getTypeInfoType(sd->loc, t, &scx);
- sd->requestTypeInfo = true;
- }
- else if (!sc->minst)
- {
- // don't yet have to generate TypeInfo instance if
- // the typeid(T) expression exists in speculative scope.
- }
- else
- {
- getTypeInfoType(sd->loc, t, sc);
- sd->requestTypeInfo = true;
-
- // Bugzilla 15149, if the typeid operand type comes from a
- // result of auto function, it may be yet speculative.
- // unSpeculative(sc, sd);
- }
-
- /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
- * This should be done even if typeid(T) exists in speculative scope.
- * Because it may appear later in non-speculative scope.
- */
- if (!sd->members)
- return; // opaque struct
- if (!sd->xeq && !sd->xcmp && !sd->postblit &&
- !sd->dtor && !sd->xhash && !search_toString(sd))
- return; // none of TypeInfo-specific members
-
- // If the struct is in a non-root module, run semantic3 to get
- // correct symbols for the member function.
- if (sd->semanticRun >= PASSsemantic3)
- {
- // semantic3 is already done
- }
- else if (TemplateInstance *ti = sd->isInstantiated())
- {
- if (ti->minst && !ti->minst->isRoot())
- Module::addDeferredSemantic3(sd);
- }
- else
- {
- if (sd->inNonRoot())
- {
- //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd->toChars(), sd->inNonRoot());
- Module::addDeferredSemantic3(sd);
- }
- }
- }
- void visit(TypeClass *) { }
- void visit(TypeTuple *t)
- {
- if (t->arguments)
- {
- for (size_t i = 0; i < t->arguments->length; i++)
- {
- Type *tprm = (*t->arguments)[i]->type;
- if (tprm)
- tprm->accept(this);
- }
- }
- }
- };
-
- if (sc)
- {
- if (!sc->func)
- return;
- if (sc->intypeof)
- return;
- if (sc->flags & (SCOPEctfe | SCOPEcompile))
- return;
- }
-
- FullTypeInfoVisitor v;
- v.sc = sc;
- t->accept(&v);
-}
-
-/********************************* AggregateDeclaration ****************************/
-
-AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
- : ScopeDsymbol(id)
-{
- this->loc = loc;
-
- storage_class = 0;
- protection = Prot(Prot::public_);
- type = NULL;
- structsize = 0; // size of struct
- alignsize = 0; // size of struct for alignment purposes
- sizeok = SIZEOKnone; // size not determined yet
- deferred = NULL;
- isdeprecated = false;
- classKind = ClassKind::d;
- inv = NULL;
- aggNew = NULL;
- aggDelete = NULL;
-
- stag = NULL;
- sinit = NULL;
- enclosing = NULL;
- vthis = NULL;
-
- ctor = NULL;
- defaultCtor = NULL;
- aliasthis = NULL;
- noDefaultCtor = false;
- dtor = NULL;
- getRTInfo = NULL;
-}
-
-Prot AggregateDeclaration::prot()
-{
- return protection;
-}
-
-/***************************************
- * Create a new scope from sc.
- * semantic, semantic2 and semantic3 will use this for aggregate members.
- */
-Scope *AggregateDeclaration::newScope(Scope *sc)
-{
- Scope *sc2 = sc->push(this);
- sc2->stc &= STCsafe | STCtrusted | STCsystem;
- sc2->parent = this;
- if (isUnionDeclaration())
- sc2->inunion = 1;
- sc2->protection = Prot(Prot::public_);
- sc2->explicitProtection = 0;
- sc2->aligndecl = NULL;
- sc2->userAttribDecl = NULL;
- return sc2;
-}
-
-void AggregateDeclaration::setScope(Scope *sc)
-{
- // Might need a scope to resolve forward references. The check for
- // semanticRun prevents unnecessary setting of _scope during deferred
- // setScope phases for aggregates which already finished semantic().
- // Also see https://issues.dlang.org/show_bug.cgi?id=16607
- if (semanticRun < PASSsemanticdone)
- ScopeDsymbol::setScope(sc);
-}
-
-/***************************************
- * Find all instance fields, then push them into `fields`.
- *
- * Runs semantic() for all instance field variables, but also
- * the field types can reamin yet not resolved forward references,
- * except direct recursive definitions.
- * After the process sizeok is set to SIZEOKfwd.
- *
- * Returns:
- * false if any errors occur.
- */
-bool AggregateDeclaration::determineFields()
-{
- if (_scope)
- dsymbolSemantic(this, NULL);
- if (sizeok != SIZEOKnone)
- return true;
-
- //printf("determineFields() %s, fields.length = %d\n", toChars(), fields.length);
- fields.setDim(0);
-
- struct SV
- {
- AggregateDeclaration *agg;
-
- static int func(Dsymbol *s, void *param)
- {
- VarDeclaration *v = s->isVarDeclaration();
- if (!v)
- return 0;
- if (v->storage_class & STCmanifest)
- return 0;
-
- AggregateDeclaration *ad = ((SV *)param)->agg;
-
- if (v->semanticRun < PASSsemanticdone)
- dsymbolSemantic(v, NULL);
- // Note: Aggregate fields or size could have determined during v->semantic.
- if (ad->sizeok != SIZEOKnone)
- return 1;
-
- if (v->aliassym)
- return 0; // If this variable was really a tuple, skip it.
-
- if (v->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter))
- return 0;
- if (!v->isField() || v->semanticRun < PASSsemanticdone)
- return 1; // unresolvable forward reference
-
- ad->fields.push(v);
-
- if (v->storage_class & STCref)
- return 0;
- Type *tv = v->type->baseElemOf();
- if (tv->ty != Tstruct)
- return 0;
- if (ad == ((TypeStruct *)tv)->sym)
- {
- const char *psz = (v->type->toBasetype()->ty == Tsarray) ? "static array of " : "";
- ad->error("cannot have field %s with %ssame struct type", v->toChars(), psz);
- ad->type = Type::terror;
- ad->errors = true;
- return 1;
- }
- return 0;
- }
- };
- SV sv;
- sv.agg = this;
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- if (s->apply(&SV::func, &sv))
- {
- if (sizeok != SIZEOKnone)
- return true;
- return false;
- }
- }
-
- if (sizeok != SIZEOKdone)
- sizeok = SIZEOKfwd;
-
- return true;
-}
-
-/***************************************
- * Collect all instance fields, then determine instance size.
- * Returns:
- * false if failed to determine the size.
- */
-bool AggregateDeclaration::determineSize(Loc loc)
-{
- //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
-
- // The previous instance size finalizing had:
- if (type->ty == Terror)
- return false; // failed already
- if (sizeok == SIZEOKdone)
- return true; // succeeded
-
- if (!members)
- {
- error(loc, "unknown size");
- return false;
- }
-
- if (_scope)
- dsymbolSemantic(this, NULL);
-
- // Determine the instance size of base class first.
- if (ClassDeclaration *cd = isClassDeclaration())
- {
- cd = cd->baseClass;
- if (cd && !cd->determineSize(loc))
- goto Lfail;
- }
-
- // Determine instance fields when sizeok == SIZEOKnone
- if (!determineFields())
- goto Lfail;
- if (sizeok != SIZEOKdone)
- finalizeSize();
-
- // this aggregate type has:
- if (type->ty == Terror)
- return false; // marked as invalid during the finalizing.
- if (sizeok == SIZEOKdone)
- return true; // succeeded to calculate instance size.
-
-Lfail:
- // There's unresolvable forward reference.
- if (type != Type::terror)
- error(loc, "no size because of forward reference");
- // Don't cache errors from speculative semantic, might be resolvable later.
- // https://issues.dlang.org/show_bug.cgi?id=16574
- if (!global.gag)
- {
- type = Type::terror;
- errors = true;
- }
- return false;
-}
-
-void StructDeclaration::semanticTypeInfoMembers()
-{
- if (xeq &&
- xeq->_scope &&
- xeq->semanticRun < PASSsemantic3done)
- {
- unsigned errors = global.startGagging();
- semantic3(xeq, xeq->_scope);
- if (global.endGagging(errors))
- xeq = xerreq;
- }
-
- if (xcmp &&
- xcmp->_scope &&
- xcmp->semanticRun < PASSsemantic3done)
- {
- unsigned errors = global.startGagging();
- semantic3(xcmp, xcmp->_scope);
- if (global.endGagging(errors))
- xcmp = xerrcmp;
- }
-
- FuncDeclaration *ftostr = search_toString(this);
- if (ftostr &&
- ftostr->_scope &&
- ftostr->semanticRun < PASSsemantic3done)
- {
- semantic3(ftostr, ftostr->_scope);
- }
-
- if (xhash &&
- xhash->_scope &&
- xhash->semanticRun < PASSsemantic3done)
- {
- semantic3(xhash, xhash->_scope);
- }
-
- if (postblit &&
- postblit->_scope &&
- postblit->semanticRun < PASSsemantic3done)
- {
- semantic3(postblit, postblit->_scope);
- }
-
- if (dtor &&
- dtor->_scope &&
- dtor->semanticRun < PASSsemantic3done)
- {
- semantic3(dtor, dtor->_scope);
- }
-}
-
-d_uns64 AggregateDeclaration::size(Loc loc)
-{
- //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
- bool ok = determineSize(loc);
- //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
- return ok ? structsize : SIZE_INVALID;
-}
-
-Type *AggregateDeclaration::getType()
-{
- return type;
-}
-
-bool AggregateDeclaration::isDeprecated()
-{
- return isdeprecated;
-}
-
-bool AggregateDeclaration::isExport() const
-{
- return protection.kind == Prot::export_;
-}
-
-/***************************************
- * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
- * field initializers have unique memory space on instance.
- * Returns:
- * true if any errors happen.
- */
-
-bool AggregateDeclaration::checkOverlappedFields()
-{
- //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
- assert(sizeok == SIZEOKdone);
- size_t nfields = fields.length;
- if (isNested())
- {
- ClassDeclaration *cd = isClassDeclaration();
- if (!cd || !cd->baseClass || !cd->baseClass->isNested())
- nfields--;
- }
- bool errors = false;
-
- // Fill in missing any elements with default initializers
- for (size_t i = 0; i < nfields; i++)
- {
- VarDeclaration *vd = fields[i];
- if (vd->errors)
- {
- errors = true;
- continue;
- }
-
- VarDeclaration *vx = vd;
- if (vd->_init && vd->_init->isVoidInitializer())
- vx = NULL;
-
- // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
- for (size_t j = 0; j < nfields; j++)
- {
- if (i == j)
- continue;
- VarDeclaration *v2 = fields[j];
- if (v2->errors)
- {
- errors = true;
- continue;
- }
- if (!vd->isOverlappedWith(v2))
- continue;
-
- // vd and v2 are overlapping.
- vd->overlapped = true;
- v2->overlapped = true;
-
- if (!MODimplicitConv(vd->type->mod, v2->type->mod))
- v2->overlapUnsafe = true;
- if (!MODimplicitConv(v2->type->mod, vd->type->mod))
- vd->overlapUnsafe = true;
-
- if (!vx)
- continue;
- if (v2->_init && v2->_init->isVoidInitializer())
- continue;
-
- if (vx->_init && v2->_init)
- {
- ::error(loc, "overlapping default initialization for field %s and %s", v2->toChars(), vd->toChars());
- errors = true;
- }
- }
- }
- return errors;
-}
-
-/***************************************
- * Fill out remainder of elements[] with default initializers for fields[].
- * Input:
- * loc: location
- * elements: explicit arguments which given to construct object.
- * ctorinit: true if the elements will be used for default initialization.
- * Returns:
- * false if any errors occur.
- * Otherwise, returns true and the missing arguments will be pushed in elements[].
- */
-bool AggregateDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit)
-{
- //printf("AggregateDeclaration::fill() %s\n", toChars());
- assert(sizeok == SIZEOKdone);
- assert(elements);
- size_t nfields = fields.length - isNested();
- bool errors = false;
-
- size_t dim = elements->length;
- elements->setDim(nfields);
- for (size_t i = dim; i < nfields; i++)
- (*elements)[i] = NULL;
-
- // Fill in missing any elements with default initializers
- for (size_t i = 0; i < nfields; i++)
- {
- if ((*elements)[i])
- continue;
-
- VarDeclaration *vd = fields[i];
- VarDeclaration *vx = vd;
- if (vd->_init && vd->_init->isVoidInitializer())
- vx = NULL;
-
- // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
- size_t fieldi = i;
- for (size_t j = 0; j < nfields; j++)
- {
- if (i == j)
- continue;
- VarDeclaration *v2 = fields[j];
- if (!vd->isOverlappedWith(v2))
- continue;
-
- if ((*elements)[j])
- {
- vx = NULL;
- break;
- }
- if (v2->_init && v2->_init->isVoidInitializer())
- continue;
-
- if (1)
- {
- /* Prefer first found non-void-initialized field
- * union U { int a; int b = 2; }
- * U u; // Error: overlapping initialization for field a and b
- */
- if (!vx)
- {
- vx = v2;
- fieldi = j;
- }
- else if (v2->_init)
- {
- ::error(loc, "overlapping initialization for field %s and %s",
- v2->toChars(), vd->toChars());
- errors = true;
- }
- }
- else
- {
- // Will fix Bugzilla 1432 by enabling this path always
-
- /* Prefer explicitly initialized field
- * union U { int a; int b = 2; }
- * U u; // OK (u.b == 2)
- */
- if (!vx || (!vx->_init && v2->_init))
- {
- vx = v2;
- fieldi = j;
- }
- else if (vx != vd && !vx->isOverlappedWith(v2))
- {
- // Both vx and v2 fills vd, but vx and v2 does not overlap
- }
- else if (vx->_init && v2->_init)
- {
- ::error(loc, "overlapping default initialization for field %s and %s",
- v2->toChars(), vd->toChars());
- errors = true;
- }
- else
- assert(vx->_init || (!vx->_init && !v2->_init));
- }
- }
- if (vx)
- {
- Expression *e;
- if (vx->type->size() == 0)
- {
- e = NULL;
- }
- else if (vx->_init)
- {
- assert(!vx->_init->isVoidInitializer());
- if (vx->inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
- {
- vx->error(loc, "recursive initialization of field");
- errors = true;
- e = NULL;
- }
- else
- e = vx->getConstInitializer(false);
- }
- else
- {
- if ((vx->storage_class & STCnodefaultctor) && !ctorinit)
- {
- ::error(loc, "field %s.%s must be initialized because it has no default constructor",
- type->toChars(), vx->toChars());
- errors = true;
- }
-
- /* Bugzilla 12509: Get the element of static array type.
- */
- Type *telem = vx->type;
- if (telem->ty == Tsarray)
- {
- /* We cannot use Type::baseElemOf() here.
- * If the bottom of the Tsarray is an enum type, baseElemOf()
- * will return the base of the enum, and its default initializer
- * would be different from the enum's.
- */
- while (telem->toBasetype()->ty == Tsarray)
- telem = ((TypeSArray *)telem->toBasetype())->next;
-
- if (telem->ty == Tvoid)
- telem = Type::tuns8->addMod(telem->mod);
- }
- if (telem->needsNested() && ctorinit)
- e = telem->defaultInit(loc);
- else
- e = telem->defaultInitLiteral(loc);
- }
- (*elements)[fieldi] = e;
- }
- }
-
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e = (*elements)[i];
- if (e && e->op == TOKerror)
- return false;
- }
-
- return !errors;
-}
-
-/****************************
- * Do byte or word alignment as necessary.
- * Align sizes of 0, as we may not know array sizes yet.
- *
- * alignment: struct alignment that is in effect
- * size: alignment requirement of field
- */
-
-void AggregateDeclaration::alignmember(
- structalign_t alignment,
- unsigned size,
- unsigned *poffset)
-{
- //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
- switch (alignment)
- {
- case (structalign_t) 1:
- // No alignment
- break;
-
- case (structalign_t) STRUCTALIGN_DEFAULT:
- // Alignment in target.fieldalignsize must match what the
- // corresponding C compiler's default alignment behavior is.
- assert(size > 0 && !(size & (size - 1)));
- *poffset = (*poffset + size - 1) & ~(size - 1);
- break;
-
- default:
- // Align on alignment boundary, which must be a positive power of 2
- assert(alignment > 0 && !(alignment & (alignment - 1)));
- *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
- break;
- }
-}
-
-/****************************************
- * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
- * Returns:
- * offset to place field at
- *
- * nextoffset: next location in aggregate
- * memsize: size of member
- * memalignsize: natural alignment of member
- * alignment: alignment in effect for this member
- * paggsize: size of aggregate (updated)
- * paggalignsize: alignment of aggregate (updated)
- * isunion: the aggregate is a union
- */
-unsigned AggregateDeclaration::placeField(
- unsigned *nextoffset,
- unsigned memsize,
- unsigned memalignsize,
- structalign_t alignment,
- unsigned *paggsize,
- unsigned *paggalignsize,
- bool isunion
- )
-{
- unsigned ofs = *nextoffset;
-
- const unsigned actualAlignment =
- alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
-
- alignmember(alignment, memalignsize, &ofs);
- unsigned memoffset = ofs;
- ofs += memsize;
- if (ofs > *paggsize)
- *paggsize = ofs;
- if (!isunion)
- *nextoffset = ofs;
-
- if (*paggalignsize < actualAlignment)
- *paggalignsize = actualAlignment;
-
- return memoffset;
-}
-
-
-/****************************************
- * Returns true if there's an extra member which is the 'this'
- * pointer to the enclosing context (enclosing aggregate or function)
- */
-
-bool AggregateDeclaration::isNested()
-{
- return enclosing != NULL;
-}
-
-/* Append vthis field (this->tupleof[$-1]) to make this aggregate type nested.
- */
-void AggregateDeclaration::makeNested()
-{
- if (enclosing) // if already nested
- return;
- if (sizeok == SIZEOKdone)
- return;
- if (isUnionDeclaration() || isInterfaceDeclaration())
- return;
- if (storage_class & STCstatic)
- return;
-
- // If nested struct, add in hidden 'this' pointer to outer scope
- Dsymbol *s = toParent2();
- if (!s)
- return;
- Type *t = NULL;
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- enclosing = fd;
-
- /* Bugzilla 14422: If a nested class parent is a function, its
- * context pointer (== `outer`) should be void* always.
- */
- t = Type::tvoidptr;
- }
- else if (AggregateDeclaration *ad = s->isAggregateDeclaration())
- {
- if (isClassDeclaration() && ad->isClassDeclaration())
- {
- enclosing = ad;
- }
- else if (isStructDeclaration())
- {
- if (TemplateInstance *ti = ad->parent->isTemplateInstance())
- {
- enclosing = ti->enclosing;
- }
- }
-
- t = ad->handleType();
- }
- if (enclosing)
- {
- //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing->toChars());
- assert(t);
- if (t->ty == Tstruct)
- t = Type::tvoidptr; // t should not be a ref type
- assert(!vthis);
- vthis = new ThisDeclaration(loc, t);
- //vthis->storage_class |= STCref;
-
- // Emulate vthis->addMember()
- members->push(vthis);
-
- // Emulate vthis->semantic()
- vthis->storage_class |= STCfield;
- vthis->parent = this;
- vthis->protection = Prot(Prot::public_);
- vthis->alignment = t->alignment();
- vthis->semanticRun = PASSsemanticdone;
-
- if (sizeok == SIZEOKfwd)
- fields.push(vthis);
- }
-}
-
-/*******************************************
- * Look for constructor declaration.
- */
-Dsymbol *AggregateDeclaration::searchCtor()
-{
- Dsymbol *s = search(Loc(), Id::ctor);
- if (s)
- {
- if (!(s->isCtorDeclaration() ||
- s->isTemplateDeclaration() ||
- s->isOverloadSet()))
- {
- s->error("is not a constructor; identifiers starting with __ are reserved for the implementation");
- errors = true;
- s = NULL;
- }
- }
- if (s && s->toParent() != this)
- s = NULL; // search() looks through ancestor classes
- if (s)
- {
- // Finish all constructors semantics to determine this->noDefaultCtor.
- struct SearchCtor
- {
- static int fp(Dsymbol *s, void *)
- {
- CtorDeclaration *f = s->isCtorDeclaration();
- if (f && f->semanticRun == PASSinit)
- dsymbolSemantic(f, NULL);
- return 0;
- }
- };
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *sm = (*members)[i];
- sm->apply(&SearchCtor::fp, NULL);
- }
- }
- return s;
-}
-
-/********************************* StructDeclaration ****************************/
-
-StructDeclaration::StructDeclaration(Loc loc, Identifier *id, bool inObject)
- : AggregateDeclaration(loc, id)
-{
- zeroInit = 0; // assume false until we do semantic processing
- hasIdentityAssign = false;
- hasIdentityEquals = false;
- postblit = NULL;
-
- xeq = NULL;
- xcmp = NULL;
- xhash = NULL;
- alignment = 0;
- ispod = ISPODfwd;
- arg1type = NULL;
- arg2type = NULL;
- requestTypeInfo = false;
-
- // For forward references
- type = new TypeStruct(this);
-
- if (inObject)
- {
- if (id == Id::ModuleInfo && !Module::moduleinfo)
- Module::moduleinfo = this;
- }
-}
-
-StructDeclaration *StructDeclaration::create(Loc loc, Identifier *id, bool inObject)
-{
- return new StructDeclaration(loc, id, inObject);
-}
-
-Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
-{
- StructDeclaration *sd =
- s ? (StructDeclaration *)s
- : new StructDeclaration(loc, ident, false);
- return ScopeDsymbol::syntaxCopy(sd);
-}
-
-Dsymbol *StructDeclaration::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
-
- if (_scope && !symtab)
- dsymbolSemantic(this, _scope);
-
- if (!members || !symtab) // opaque or semantic() is not yet called
- {
- error("is forward referenced when looking for `%s`", ident->toChars());
- return NULL;
- }
-
- return ScopeDsymbol::search(loc, ident, flags);
-}
-
-/**********************************
- * Determine if exp is all binary zeros.
- * Params:
- * exp = expression to check
- * Returns:
- * true if it's all binary 0
- */
-static bool isZeroInit(Expression *exp)
-{
- switch (exp->op)
- {
- case TOKint64:
- return exp->toInteger() == 0;
-
- case TOKnull:
- case TOKfalse:
- return true;
-
- case TOKstructliteral:
- {
- StructLiteralExp *sle = (StructLiteralExp *) exp;
- for (size_t i = 0; i < sle->sd->fields.length; i++)
- {
- VarDeclaration *field = sle->sd->fields[i];
- if (field->type->size(field->loc))
- {
- Expression *e = (*sle->elements)[i];
- if (e ? !isZeroInit(e)
- : !field->type->isZeroInit(field->loc))
- return false;
- }
- }
- return true;
- }
-
- case TOKarrayliteral:
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *) exp;
-
- const size_t dim = ale->elements ? ale->elements->length : 0;
-
- if (ale->type->toBasetype()->ty == Tarray) // if initializing a dynamic array
- return dim == 0;
-
- for (size_t i = 0; i < dim; i++)
- {
- if (!isZeroInit(ale->getElement(i)))
- return false;
- }
- /* Note that true is returned for all T[0]
- */
- return true;
- }
-
- case TOKstring:
- {
- StringExp *se = exp->toStringExp();
-
- if (se->type->toBasetype()->ty == Tarray) // if initializing a dynamic array
- return se->len == 0;
-
- void *s = se->string;
- for (size_t i = 0; i < se->len; i++)
- {
- dinteger_t val;
- switch (se->sz)
- {
- case 1: val = (( utf8_t *)s)[i]; break;
- case 2: val = ((utf16_t *)s)[i]; break;
- case 4: val = ((utf32_t *)s)[i]; break;
- default: assert(0); break;
- }
- if (val)
- return false;
- }
- return true;
- }
-
- case TOKvector:
- {
- VectorExp *ve = (VectorExp *) exp;
- return isZeroInit(ve->e1);
- }
-
- case TOKfloat64:
- case TOKcomplex80:
- {
- return (exp->toReal() == CTFloat::zero) &&
- (exp->toImaginary() == CTFloat::zero);
- }
-
- default:
- return false;
- }
-}
-
-void StructDeclaration::finalizeSize()
-{
- //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
- assert(sizeok != SIZEOKdone);
-
- //printf("+StructDeclaration::finalizeSize() %s, fields.length = %d, sizeok = %d\n", toChars(), fields.length, sizeok);
-
- fields.setDim(0); // workaround
-
- // Set the offsets of the fields and determine the size of the struct
- unsigned offset = 0;
- bool isunion = isUnionDeclaration() != NULL;
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->setFieldOffset(this, &offset, isunion);
- }
- if (type->ty == Terror)
- return;
-
- // 0 sized struct's are set to 1 byte
- if (structsize == 0)
- {
- structsize = 1;
- alignsize = 1;
- }
-
- // Round struct size up to next alignsize boundary.
- // This will ensure that arrays of structs will get their internals
- // aligned properly.
- if (alignment == STRUCTALIGN_DEFAULT)
- structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
- else
- structsize = (structsize + alignment - 1) & ~(alignment - 1);
-
- sizeok = SIZEOKdone;
-
- //printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), fields.length, structsize);
-
- if (errors)
- return;
-
- // Calculate fields[i]->overlapped
- if (checkOverlappedFields())
- {
- errors = true;
- return;
- }
-
- // Determine if struct is all zeros or not
- zeroInit = 1;
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration *vd = fields[i];
- if (vd->_init)
- {
- if (vd->_init->isVoidInitializer())
- /* Treat as 0 for the purposes of putting the initializer
- * in the BSS segment, or doing a mass set to 0
- */
- continue;
-
- // Zero size fields are zero initialized
- if (vd->type->size(vd->loc) == 0)
- continue;
-
- // Examine init to see if it is all 0s.
- Expression *exp = vd->getConstInitializer();
- if (!exp || !isZeroInit(exp))
- {
- zeroInit = 0;
- break;
- }
- }
- else if (!vd->type->isZeroInit(loc))
- {
- zeroInit = 0;
- break;
- }
- }
-
- TypeTuple *tt = target.toArgTypes(type);
- size_t dim = tt ? tt->arguments->length : 0;
- if (dim >= 1)
- {
- assert(dim <= 2);
- arg1type = (*tt->arguments)[0]->type;
- if (dim == 2)
- arg2type = (*tt->arguments)[1]->type;
- }
-}
-
-/***************************************
- * Fit elements[] to the corresponding type of field[].
- * Input:
- * loc
- * sc
- * elements The explicit arguments that given to construct object.
- * stype The constructed object type.
- * Returns false if any errors occur.
- * Otherwise, returns true and elements[] are rewritten for the output.
- */
-bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *stype)
-{
- if (!elements)
- return true;
-
- size_t nfields = fields.length - isNested();
- size_t offset = 0;
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e = (*elements)[i];
- if (!e)
- continue;
-
- e = resolveProperties(sc, e);
- if (i >= nfields)
- {
- if (i == fields.length - 1 && isNested() && e->op == TOKnull)
- {
- // CTFE sometimes creates null as hidden pointer; we'll allow this.
- continue;
- }
- ::error(loc, "more initializers than fields (%d) of %s", (int)nfields, toChars());
- return false;
- }
- VarDeclaration *v = fields[i];
- if (v->offset < offset)
- {
- ::error(loc, "overlapping initialization for %s", v->toChars());
- return false;
- }
- offset = (unsigned)(v->offset + v->type->size());
-
- Type *t = v->type;
- if (stype)
- t = t->addMod(stype->mod);
- Type *origType = t;
- Type *tb = t->toBasetype();
-
- /* Look for case of initializing a static array with a too-short
- * string literal, such as:
- * char[5] foo = "abc";
- * Allow this by doing an explicit cast, which will lengthen the string
- * literal.
- */
- if (e->op == TOKstring && tb->ty == Tsarray)
- {
- StringExp *se = (StringExp *)e;
- Type *typeb = se->type->toBasetype();
- TY tynto = tb->nextOf()->ty;
- if (!se->committed &&
- (typeb->ty == Tarray || typeb->ty == Tsarray) &&
- (tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
- se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
- {
- e = se->castTo(sc, t);
- goto L1;
- }
- }
-
- while (!e->implicitConvTo(t) && tb->ty == Tsarray)
- {
- /* Static array initialization, as in:
- * T[3][5] = e;
- */
- t = tb->nextOf();
- tb = t->toBasetype();
- }
- if (!e->implicitConvTo(t))
- t = origType; // restore type for better diagnostic
-
- e = e->implicitCastTo(sc, t);
- L1:
- if (e->op == TOKerror)
- return false;
-
- (*elements)[i] = doCopyOrMove(sc, e);
- }
- return true;
-}
-
-/***************************************
- * Return true if struct is POD (Plain Old Data).
- * This is defined as:
- * not nested
- * no postblits, destructors, or assignment operators
- * no 'ref' fields or fields that are themselves non-POD
- * The idea being these are compatible with C structs.
- */
-bool StructDeclaration::isPOD()
-{
- // If we've already determined whether this struct is POD.
- if (ispod != ISPODfwd)
- return (ispod == ISPODyes);
-
- ispod = ISPODyes;
-
- if (enclosing || postblit || dtor)
- ispod = ISPODno;
-
- // Recursively check all fields are POD.
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration *v = fields[i];
- if (v->storage_class & STCref)
- {
- ispod = ISPODno;
- break;
- }
-
- Type *tv = v->type->baseElemOf();
- if (tv->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tv;
- StructDeclaration *sd = ts->sym;
- if (!sd->isPOD())
- {
- ispod = ISPODno;
- break;
- }
- }
- }
-
- return (ispod == ISPODyes);
-}
-
-const char *StructDeclaration::kind() const
-{
- return "struct";
-}
-
-/********************************* UnionDeclaration ****************************/
-
-UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
- : StructDeclaration(loc, id, false)
-{
-}
-
-Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- UnionDeclaration *ud = new UnionDeclaration(loc, ident);
- return StructDeclaration::syntaxCopy(ud);
-}
-
-const char *UnionDeclaration::kind() const
-{
- return "union";
-}