Patchwork Go patch committed: Fix unsafe.Offsetof

login
register
mail settings
Submitter Ian Taylor
Date June 14, 2013, 6 p.m.
Message ID <mcrzjusmv2w.fsf@iant-glaptop.roam.corp.google.com>
Download mbox | patch
Permalink /patch/251479/
State New
Headers show

Comments

Ian Taylor - June 14, 2013, 6 p.m.
This gccgo patch from Rémy Oudompheng fixes unsafe.Offsetof applied to a
field in an embedded struct.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline and 4.8 branch.

Ian

Patch

diff -r ea256b8b5c75 go/expressions.cc
--- a/go/expressions.cc	Wed Jun 12 15:27:10 2013 -0700
+++ b/go/expressions.cc	Fri Jun 14 10:56:49 2013 -0700
@@ -7279,19 +7279,31 @@ 
       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 -r ea256b8b5c75 go/expressions.h
--- a/go/expressions.h	Wed Jun 12 15:27:10 2013 -0700
+++ b/go/expressions.h	Fri Jun 14 10:56:49 2013 -0700
@@ -1860,6 +1860,15 @@ 
   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 @@ 
   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 -r ea256b8b5c75 go/types.cc
--- a/go/types.cc	Wed Jun 12 15:27:10 2013 -0700
+++ b/go/types.cc	Fri Jun 14 10:56:49 2013 -0700
@@ -4532,6 +4532,7 @@ 
 	      go_assert(sub != NULL);
 	    }
 	  sub->set_struct_expression(here);
+          sub->set_implicit(true);
 	}
       else if (subdepth > found_depth)
 	delete sub;