Mercurial > projects > ldc
diff ir/irtypestruct.cpp @ 1262:ec1d9dc1d32a
Fixed struct default initializers.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail com> |
---|---|
date | Sat, 25 Apr 2009 18:26:54 +0200 |
parents | 465a77c904d4 |
children | b8a51aa44d4c |
line wrap: on
line diff
--- a/ir/irtypestruct.cpp Wed Apr 22 14:49:49 2009 -0600 +++ b/ir/irtypestruct.cpp Sat Apr 25 18:26:54 2009 +0200 @@ -62,18 +62,103 @@ return defaultTypes.size() - n; } +bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2) +{ + if (v1 && v2) return v1->offset < v2->offset; + else return false; +} + const llvm::Type* IrTypeStruct::buildType() { - IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->locToChars()); + IF_LOG Logger::println("Building struct type %s @ %s", + sd->toPrettyChars(), sd->locToChars()); LOG_SCOPE; // if it's a forward declaration, all bets are off, stick with the opaque if (sd->sizeok != 1) return pa.get(); - // find the fields that contribute to the default initializer. - // these will define the default type. + // mirror the sd->fields array but only fill in contributors + size_t n = sd->fields.dim; + LLSmallVector<VarDeclaration*, 16> data(n, NULL); + default_fields.reserve(n); + + // first fill in the fields with explicit initializers + VarDeclarationIter field_it(sd->fields); + for (; field_it.more(); field_it.next()) + { + // init is !null for explicit inits + if (field_it->init != NULL) + { + IF_LOG Logger::println("adding explicit initializer for struct field %s", + field_it->toChars()); + + data[field_it.index] = *field_it; + + size_t f_begin = field_it->offset; + size_t f_end = f_begin + field_it->type->size(); + + // make sure there is no overlap + for (size_t i = 0; i < field_it.index; i++) + { + if (data[i] != NULL) + { + VarDeclaration* vd = data[i]; + size_t v_begin = vd->offset; + size_t v_end = v_begin + vd->type->size(); + + if (v_begin >= f_end || v_end <= f_begin) + continue; + + sd->error(vd->loc, "overlapping initialization for %s and %s", + field_it->toChars(), vd->toChars()); + } + } + } + } + if (global.errors) + { + fatal(); + } + + // fill in default initializers + field_it = VarDeclarationIter(sd->fields); + for (;field_it.more(); field_it.next()) + { + if (data[field_it.index]) + continue; + + size_t f_begin = field_it->offset; + size_t f_end = f_begin + field_it->type->size(); + + // make sure it doesn't overlap anything explicit + bool overlaps = false; + for (size_t i = 0; i < n; i++) + { + if (data[i]) + { + size_t v_begin = data[i]->offset; + size_t v_end = v_begin + data[i]->type->size(); + + if (v_begin >= f_end || v_end <= f_begin) + continue; + + overlaps = true; + break; + } + } + + // if no overlap was found, add the default initializer + if (!overlaps) + { + IF_LOG Logger::println("adding default initializer for struct field %s", + field_it->toChars()); + data[field_it.index] = *field_it; + } + } + + // ok. now we can build a list of llvm types. and make sure zeros are inserted if necessary. std::vector<const llvm::Type*> defaultTypes; defaultTypes.reserve(16); @@ -82,24 +167,21 @@ bool packed = (sd->type->alignsize() == 1); - ArrayIter<VarDeclaration> it(sd->fields); - for (; !it.done(); it.next()) + // first we sort the list by offset + std::sort(data.begin(), data.end(), var_offset_sort_cb); + + // add types to list + for (size_t i = 0; i < n; i++) { - VarDeclaration* vd = it.get(); - //Logger::println("vd: %s", vd->toPrettyChars()); - - //assert(vd->ir.irField == NULL && "struct inheritance is not allowed, how can this happen?"); + VarDeclaration* vd = data[i]; - // skip if offset moved backwards - if (vd->offset < offset) - { - IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); - if (vd->ir.irField == NULL) - new IrField(vd, 0, vd->offset); + if (vd == NULL) continue; - } + + assert(vd->offset >= offset); - IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + // add to default field list + default_fields.push_back(vd); // get next aligned offset for this type size_t alignedoffset = offset; @@ -121,12 +203,13 @@ // advance offset to right past this field offset = vd->offset + vd->type->size(); - // give field index - // the IrField creation doesn't really belong here, but it's a trivial operation - // and it save yet another of these loops. - IF_LOG Logger::println("Field index: %zu", field_index); + // create ir field if (vd->ir.irField == NULL) new IrField(vd, field_index); + else + assert(vd->ir.irField->index == field_index && + vd->ir.irField->unionOffset == 0 && + "inconsistent field data"); field_index++; } @@ -136,6 +219,15 @@ add_zeros(defaultTypes, sd->structsize - offset); } + // make sure all fields really get their ir field + ArrayIter<VarDeclaration> it(sd->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + if (vd->ir.irField == NULL) + new IrField(vd, 0, vd->offset); + } + // build the llvm type const llvm::Type* st = llvm::StructType::get(defaultTypes, packed);