diff mbox

Go patch committed: Error for qualified ID in struct composite lit

Message ID mcrtxgrco92.fsf@iant-glaptop.roam.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Oct. 8, 2013, 11:54 p.m. UTC
This patch to the Go frontend gives an error if a qualified identifier
is used as a field name in a struct composite literal.  This is trickier
than one might expect since qualified identifiers are fine as keys in a
slice or map composite literal.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline and 4.8 branch.

Ian
diff mbox

Patch

diff -r 29fef9fa5a41 go/expressions.cc
--- a/go/expressions.cc	Mon Oct 07 08:31:41 2013 -0700
+++ b/go/expressions.cc	Tue Oct 08 16:48:26 2013 -0700
@@ -11293,7 +11293,7 @@ 
     }
 
   Expression* e = Expression::make_composite_literal(array_type, 0, false,
-						     bytes, loc);
+						     bytes, false, loc);
 
   Variable* var = new Variable(array_type, e, true, false, false, loc);
 
@@ -13236,9 +13236,11 @@ 
 {
  public:
   Composite_literal_expression(Type* type, int depth, bool has_keys,
-			       Expression_list* vals, Location location)
+			       Expression_list* vals, bool all_are_names,
+			       Location location)
     : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location),
-      type_(type), depth_(depth), vals_(vals), has_keys_(has_keys)
+      type_(type), depth_(depth), vals_(vals), has_keys_(has_keys),
+      all_are_names_(all_are_names)
   { }
 
  protected:
@@ -13256,6 +13258,7 @@ 
 					    (this->vals_ == NULL
 					     ? NULL
 					     : this->vals_->copy()),
+					    this->all_are_names_,
 					    this->location());
   }
 
@@ -13285,6 +13288,9 @@ 
   // If this is true, then VALS_ is a list of pairs: a key and a
   // value.  In an array initializer, a missing key will be NULL.
   bool has_keys_;
+  // If this is true, then HAS_KEYS_ is true, and every key is a
+  // simple identifier.
+  bool all_are_names_;
 };
 
 // Traversal.
@@ -13387,6 +13393,8 @@ 
   std::vector<Expression*> vals(field_count);
   std::vector<int>* traverse_order = new(std::vector<int>);
   Expression_list::const_iterator p = this->vals_->begin();
+  Expression* external_expr = NULL;
+  const Named_object* external_no = NULL;
   while (p != this->vals_->end())
     {
       Expression* name_expr = *p;
@@ -13492,6 +13500,12 @@ 
 
       if (no != NULL)
 	{
+	  if (no->package() != NULL && external_expr == NULL)
+	    {
+	      external_expr = name_expr;
+	      external_no = no;
+	    }
+
 	  name = no->name();
 
 	  // A predefined name won't be packed.  If it starts with a
@@ -13541,6 +13555,23 @@ 
       traverse_order->push_back(index);
     }
 
+  if (!this->all_are_names_)
+    {
+      // This is a weird case like bug462 in the testsuite.
+      if (external_expr == NULL)
+	error_at(this->location(), "unknown field in %qs literal",
+		 (type->named_type() != NULL
+		  ? type->named_type()->message_name().c_str()
+		  : "unnamed struct"));
+      else
+	error_at(external_expr->location(), "unknown field %qs in %qs",
+		 external_no->message_name().c_str(),
+		 (type->named_type() != NULL
+		  ? type->named_type()->message_name().c_str()
+		  : "unnamed struct"));
+      return Expression::make_error(location);
+    }
+
   Expression_list* list = new Expression_list;
   list->reserve(field_count);
   for (size_t i = 0; i < field_count; ++i)
@@ -13830,11 +13861,11 @@ 
 
 Expression*
 Expression::make_composite_literal(Type* type, int depth, bool has_keys,
-				   Expression_list* vals,
+				   Expression_list* vals, bool all_are_names,
 				   Location location)
 {
   return new Composite_literal_expression(type, depth, has_keys, vals,
-					  location);
+					  all_are_names, location);
 }
 
 // Return whether this expression is a composite literal.
diff -r 29fef9fa5a41 go/expressions.h
--- a/go/expressions.h	Mon Oct 07 08:31:41 2013 -0700
+++ b/go/expressions.h	Tue Oct 08 16:48:26 2013 -0700
@@ -291,10 +291,13 @@ 
   make_unsafe_cast(Type*, Expression*, Location);
 
   // Make a composite literal.  The DEPTH parameter is how far down we
-  // are in a list of composite literals with omitted types.
+  // are in a list of composite literals with omitted types.  HAS_KEYS
+  // is true if the expression list has keys alternating with values.
+  // ALL_ARE_NAMES is true if all the keys could be struct field
+  // names.
   static Expression*
   make_composite_literal(Type*, int depth, bool has_keys, Expression_list*,
-			 Location);
+			 bool all_are_names, Location);
 
   // Make a struct composite literal.
   static Expression*
diff -r 29fef9fa5a41 go/parse.cc
--- a/go/parse.cc	Mon Oct 07 08:31:41 2013 -0700
+++ b/go/parse.cc	Tue Oct 08 16:48:26 2013 -0700
@@ -2690,15 +2690,17 @@ 
     {
       this->advance_token();
       return Expression::make_composite_literal(type, depth, false, NULL,
-						location);
+						false, location);
     }
 
   bool has_keys = false;
+  bool all_are_names = true;
   Expression_list* vals = new Expression_list;
   while (true)
     {
       Expression* val;
       bool is_type_omitted = false;
+      bool is_name = false;
 
       const Token* token = this->peek_token();
 
@@ -2719,6 +2721,7 @@ 
 	      val = this->id_to_expression(gogo->pack_hidden_name(identifier,
 								  is_exported),
 					   location);
+	      is_name = true;
 	    }
 	  else
 	    {
@@ -2744,6 +2747,7 @@ 
 	{
 	  if (has_keys)
 	    vals->push_back(NULL);
+	  is_name = false;
 	}
       else
 	{
@@ -2790,6 +2794,9 @@ 
 
       vals->push_back(val);
 
+      if (!is_name)
+	all_are_names = false;
+
       if (token->is_op(OPERATOR_COMMA))
 	{
 	  if (this->advance_token()->is_op(OPERATOR_RCURLY))
@@ -2830,7 +2837,7 @@ 
     }
 
   return Expression::make_composite_literal(type, depth, has_keys, vals,
-					    location);
+					    all_are_names, location);
 }
 
 // FunctionLit = "func" Signature Block .