aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2013-06-14 17:59:48 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2013-06-14 17:59:48 +0000
commit51b08adabf40a7922771ff4e0c36c8680c082825 (patch)
tree0578244ff530b3ebc00aed42fca943c03feb3d58
parent24244e4debd3261c8237d15d940fd10df5b0005a (diff)
downloadgcc-51b08adabf40a7922771ff4e0c36c8680c082825.zip
gcc-51b08adabf40a7922771ff4e0c36c8680c082825.tar.gz
gcc-51b08adabf40a7922771ff4e0c36c8680c082825.tar.bz2
compiler: fix computation of Offsetof.
The implied offsets must be taken into account when the selector involves anonymous fields. From-SVN: r200098
-rw-r--r--gcc/go/gofrontend/expressions.cc36
-rw-r--r--gcc/go/gofrontend/expressions.h12
-rw-r--r--gcc/go/gofrontend/types.cc1
3 files changed, 37 insertions, 12 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 9abd224..afc1832 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -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)
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index af178de..36f4c0d 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -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_;
};
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 7694982..4fbb162 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -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;