compiler: fix computation of Offsetof.
The implied offsets must be taken into account when the selector involves anonymous fields. From-SVN: r200098
This commit is contained in:
parent
24244e4deb
commit
51b08adabf
3 changed files with 37 additions and 12 deletions
|
@ -7279,19 +7279,31 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
|
|||
Field_reference_expression* farg = arg->field_reference_expression();
|
||||
if (farg == NULL)
|
||||
return false;
|
||||
Expression* struct_expr = farg->expr();
|
||||
Type* st = struct_expr->type();
|
||||
if (st->struct_type() == NULL)
|
||||
return false;
|
||||
if (st->named_type() != NULL)
|
||||
st->named_type()->convert(this->gogo_);
|
||||
unsigned int offset;
|
||||
if (!st->struct_type()->backend_field_offset(this->gogo_,
|
||||
farg->field_index(),
|
||||
&offset))
|
||||
return false;
|
||||
unsigned int total_offset = 0;
|
||||
while (true)
|
||||
{
|
||||
Expression* struct_expr = farg->expr();
|
||||
Type* st = struct_expr->type();
|
||||
if (st->struct_type() == NULL)
|
||||
return false;
|
||||
if (st->named_type() != NULL)
|
||||
st->named_type()->convert(this->gogo_);
|
||||
unsigned int offset;
|
||||
if (!st->struct_type()->backend_field_offset(this->gogo_,
|
||||
farg->field_index(),
|
||||
&offset))
|
||||
return false;
|
||||
total_offset += offset;
|
||||
if (farg->implicit() && struct_expr->field_reference_expression() != NULL)
|
||||
{
|
||||
// Go up until we reach the original base.
|
||||
farg = struct_expr->field_reference_expression();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
nc->set_unsigned_long(Type::lookup_integer_type("uintptr"),
|
||||
static_cast<unsigned long>(offset));
|
||||
static_cast<unsigned long>(total_offset));
|
||||
return true;
|
||||
}
|
||||
else if (this->code_ == BUILTIN_REAL || this->code_ == BUILTIN_IMAG)
|
||||
|
|
|
@ -1860,6 +1860,15 @@ class Field_reference_expression : public Expression
|
|||
field_index() const
|
||||
{ return this->field_index_; }
|
||||
|
||||
// Return whether this node was implied by an anonymous field.
|
||||
bool
|
||||
implicit() const
|
||||
{ return this->implicit_; }
|
||||
|
||||
void
|
||||
set_implicit(bool implicit)
|
||||
{ this->implicit_ = implicit; }
|
||||
|
||||
// Set the struct expression. This is used when parsing.
|
||||
void
|
||||
set_struct_expression(Expression* expr)
|
||||
|
@ -1914,6 +1923,9 @@ class Field_reference_expression : public Expression
|
|||
Expression* expr_;
|
||||
// The zero-based index of the field we are retrieving.
|
||||
unsigned int field_index_;
|
||||
// Whether this node was emitted implicitly for an embedded field,
|
||||
// that is, expr_ is not the expr_ of the original user node.
|
||||
bool implicit_;
|
||||
// Whether we have already emitted a fieldtrack call.
|
||||
bool called_fieldtrack_;
|
||||
};
|
||||
|
|
|
@ -4532,6 +4532,7 @@ Struct_type::field_reference_depth(Expression* struct_expr,
|
|||
go_assert(sub != NULL);
|
||||
}
|
||||
sub->set_struct_expression(here);
|
||||
sub->set_implicit(true);
|
||||
}
|
||||
else if (subdepth > found_depth)
|
||||
delete sub;
|
||||
|
|
Loading…
Add table
Reference in a new issue