/*************************************** * Fill out remainder of elements[] with default initializers for fields[]. * Input: * loc * 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 StructDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit) { assert(sizeok == SIZEOKdone); size_t nfields = fields.dim - isNested(); if (elements) { size_t dim = elements->dim; 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 && (*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]; bool overlap = (vd->offset < v2->offset + v2->type->size() && v2->offset < vd->offset + vd->type->size()); if (!overlap) continue; if (elements) { if ((*elements)[j]) { vx = NULL; break; } } else { vd->overlapped = true; } if (v2->init && v2->init->isVoidInitializer()) continue; if (elements) { /* 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()); } } 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->offset < v2->offset + v2->type->size() && v2->offset < vx->offset + vx->type->size())) { // 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()); } else assert(vx->init || !vx->init && !v2->init); } } if (elements && vx) { Expression *e; if (vx->init) { assert(!vx->init->isVoidInitializer()); 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()); } /* Bugzilla 12509: Get the element of static array type. */ Type *telem = vx->type; if (telem->ty == Tsarray) { telem = telem->baseElemOf(); 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; } } if (elements) { for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; if (e && e->op == TOKerror) return false; } } return true; }
/*************************************** * Fill out remainder of elements[] with default initializers for fields[]. * Input: * loc * 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 StructDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit) { //printf("StructDeclaration::fill() %s\n", toChars()); assert(sizeok == SIZEOKdone); size_t nfields = fields.dim - isNested(); bool errors = false; if (elements) { size_t dim = elements->dim; 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 && (*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]; bool overlap = (vd->offset < v2->offset + v2->type->size() && v2->offset < vd->offset + vd->type->size()); if (!overlap) continue; // vd and v2 are overlapping. If either has destructors, postblits, etc., then error //printf("overlapping fields %s and %s\n", vd->toChars(), v2->toChars()); VarDeclaration *v = vd; for (int k = 0; k < 2; ++k, v = v2) { Type *tv = v->type->baseElemOf(); Dsymbol *sv = tv->toDsymbol(NULL); if (sv && !errors) { StructDeclaration *sd = sv->isStructDeclaration(); if (sd && (sd->dtor || sd->inv || sd->postblit)) { error("destructors, postblits and invariants are not allowed in overlapping fields %s and %s", vd->toChars(), v2->toChars()); errors = true; break; } } } if (elements) { if ((*elements)[j]) { vx = NULL; break; } } else { vd->overlapped = true; } if (v2->init && v2->init->isVoidInitializer()) continue; if (elements) { /* 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()); } } 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->offset < v2->offset + v2->type->size() && v2->offset < vx->offset + vx->type->size())) { // 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()); } else assert(vx->init || !vx->init && !v2->init); } } if (elements && vx) { Expression *e; if (vx->type->size() == 0) { e = NULL; } else if (vx->init) { assert(!vx->init->isVoidInitializer()); 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()); } /* 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; } } if (elements) { for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; if (e && e->op == TOKerror) return false; } } return !errors; }