diff options
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 36 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 12 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 1 |
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; |