Commit 0581e6ba by Ian Lance Taylor

compiler: don't add composite literal keys to package bindings

    
    Adding composite literal keys to package bindings gets confusing when
    it is combined with dot imports.  The test case showing the resulting
    compilation failure is https://golang.org/cl/213899.
    
    Fix this by adding a new expression type to hold composite literal keys.
    We shouldn't see it during lowering if it is a struct field name,
    because Composite_literal_expression::do_traverse skips struct field names.
    Or, it should, but that didn't quite work with pointer types so it had to
    be tweaked.
    
    This lets us remove the code that recorded whether an Unknown_expression
    is a composite literal key.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/214017

From-SVN: r280056
parent d6491d15
e0790a756e9ba77e2d3d6ef5d0abbb11dd71211b 8ad32fb3e1e8b19ac125d03db24a73a800abdfa6
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -1761,8 +1761,6 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) ...@@ -1761,8 +1761,6 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
real = no->unknown_value()->real_named_object(); real = no->unknown_value()->real_named_object();
if (real == NULL) if (real == NULL)
{ {
if (this->is_composite_literal_key_)
return this;
if (!this->no_error_message_) if (!this->no_error_message_)
go_error_at(location, "reference to undefined name %qs", go_error_at(location, "reference to undefined name %qs",
this->named_object_->message_name().c_str()); this->named_object_->message_name().c_str());
...@@ -1776,8 +1774,6 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) ...@@ -1776,8 +1774,6 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
case Named_object::NAMED_OBJECT_TYPE: case Named_object::NAMED_OBJECT_TYPE:
return Expression::make_type(real->type_value(), location); return Expression::make_type(real->type_value(), location);
case Named_object::NAMED_OBJECT_TYPE_DECLARATION: case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
if (this->is_composite_literal_key_)
return this;
if (!this->no_error_message_) if (!this->no_error_message_)
go_error_at(location, "reference to undefined type %qs", go_error_at(location, "reference to undefined type %qs",
real->message_name().c_str()); real->message_name().c_str());
...@@ -1789,8 +1785,6 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) ...@@ -1789,8 +1785,6 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
case Named_object::NAMED_OBJECT_FUNC_DECLARATION: case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
return Expression::make_func_reference(real, NULL, location); return Expression::make_func_reference(real, NULL, location);
case Named_object::NAMED_OBJECT_PACKAGE: case Named_object::NAMED_OBJECT_PACKAGE:
if (this->is_composite_literal_key_)
return this;
if (!this->no_error_message_) if (!this->no_error_message_)
go_error_at(location, "unexpected reference to package"); go_error_at(location, "unexpected reference to package");
return Expression::make_error(location); return Expression::make_error(location);
...@@ -15992,6 +15986,77 @@ Map_construction_expression::do_dump_expression( ...@@ -15992,6 +15986,77 @@ Map_construction_expression::do_dump_expression(
ast_dump_context->ostream() << "}"; ast_dump_context->ostream() << "}";
} }
// A composite literal key. This is seen during parsing, but is not
// resolved to a named_object in case this is a composite literal of
// struct type.
class Composite_literal_key_expression : public Parser_expression
{
public:
Composite_literal_key_expression(const std::string& name, Location location)
: Parser_expression(EXPRESSION_COMPOSITE_LITERAL_KEY, location),
name_(name)
{ }
const std::string&
name() const
{ return this->name_; }
protected:
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Expression*
do_copy()
{
return new Composite_literal_key_expression(this->name_, this->location());
}
void
do_dump_expression(Ast_dump_context*) const;
private:
// The name.
std::string name_;
};
// Lower a composite literal key. We will never get here for keys in
// composite literals of struct types, because that is prevented by
// Composite_literal_expression::do_traverse. So if we do get here,
// this must be a regular name reference after all.
Expression*
Composite_literal_key_expression::do_lower(Gogo* gogo, Named_object*,
Statement_inserter*, int)
{
Named_object* no = gogo->lookup(this->name_, NULL);
if (no == NULL)
{
go_error_at(this->location(), "reference to undefined name %qs",
Gogo::message_name(this->name_).c_str());
return Expression::make_error(this->location());
}
return Expression::make_unknown_reference(no, this->location());
}
// Dump a composite literal key.
void
Composite_literal_key_expression::do_dump_expression(
Ast_dump_context* ast_dump_context) const
{
ast_dump_context->ostream() << "_UnknownName_(" << this->name_ << ")";
}
// Make a composite literal key.
Expression*
Expression::make_composite_literal_key(const std::string& name,
Location location)
{
return new Composite_literal_key_expression(name, location);
}
// Class Composite_literal_expression. // Class Composite_literal_expression.
// Traversal. // Traversal.
...@@ -16013,6 +16078,7 @@ Composite_literal_expression::do_traverse(Traverse* traverse) ...@@ -16013,6 +16078,7 @@ Composite_literal_expression::do_traverse(Traverse* traverse)
for (int depth = 0; depth < this->depth_; ++depth) for (int depth = 0; depth < this->depth_; ++depth)
{ {
type = type->deref();
if (type->array_type() != NULL) if (type->array_type() != NULL)
type = type->array_type()->element_type(); type = type->array_type()->element_type();
else if (type->map_type() != NULL) else if (type->map_type() != NULL)
...@@ -16028,6 +16094,7 @@ Composite_literal_expression::do_traverse(Traverse* traverse) ...@@ -16028,6 +16094,7 @@ Composite_literal_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE; return TRAVERSE_CONTINUE;
} }
} }
type = type->deref();
while (true) while (true)
{ {
...@@ -16186,6 +16253,11 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) ...@@ -16186,6 +16253,11 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
const Named_object* no = NULL; const Named_object* no = NULL;
switch (name_expr->classification()) switch (name_expr->classification())
{ {
case EXPRESSION_COMPOSITE_LITERAL_KEY:
name =
static_cast<Composite_literal_key_expression*>(name_expr)->name();
break;
case EXPRESSION_UNKNOWN_REFERENCE: case EXPRESSION_UNKNOWN_REFERENCE:
name = name_expr->unknown_expression()->name(); name = name_expr->unknown_expression()->name();
if (type->named_type() != NULL) if (type->named_type() != NULL)
...@@ -16593,7 +16665,6 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, ...@@ -16593,7 +16665,6 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
// literals. Lower it now to get the right error message. // literals. Lower it now to get the right error message.
if ((*p)->unknown_expression() != NULL) if ((*p)->unknown_expression() != NULL)
{ {
(*p)->unknown_expression()->clear_is_composite_literal_key();
gogo->lower_expression(function, inserter, &*p); gogo->lower_expression(function, inserter, &*p);
go_assert((*p)->is_error_expression()); go_assert((*p)->is_error_expression());
return Expression::make_error(location); return Expression::make_error(location);
......
...@@ -127,6 +127,7 @@ class Expression ...@@ -127,6 +127,7 @@ class Expression
EXPRESSION_SLICE_CONSTRUCTION, EXPRESSION_SLICE_CONSTRUCTION,
EXPRESSION_MAP_CONSTRUCTION, EXPRESSION_MAP_CONSTRUCTION,
EXPRESSION_COMPOSITE_LITERAL, EXPRESSION_COMPOSITE_LITERAL,
EXPRESSION_COMPOSITE_LITERAL_KEY,
EXPRESSION_HEAP, EXPRESSION_HEAP,
EXPRESSION_RECEIVE, EXPRESSION_RECEIVE,
EXPRESSION_TYPE_DESCRIPTOR, EXPRESSION_TYPE_DESCRIPTOR,
...@@ -384,6 +385,10 @@ class Expression ...@@ -384,6 +385,10 @@ class Expression
make_composite_literal(Type*, int depth, bool has_keys, Expression_list*, make_composite_literal(Type*, int depth, bool has_keys, Expression_list*,
bool all_are_names, Location); bool all_are_names, Location);
// Make a composite literal key.
static Expression*
make_composite_literal_key(const std::string& name, Location);
// Make a struct composite literal. // Make a struct composite literal.
static Expression* static Expression*
make_struct_composite_literal(Type*, Expression_list*, Location); make_struct_composite_literal(Type*, Expression_list*, Location);
...@@ -2881,8 +2886,7 @@ class Unknown_expression : public Parser_expression ...@@ -2881,8 +2886,7 @@ class Unknown_expression : public Parser_expression
public: public:
Unknown_expression(Named_object* named_object, Location location) Unknown_expression(Named_object* named_object, Location location)
: Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location), : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location),
named_object_(named_object), no_error_message_(false), named_object_(named_object), no_error_message_(false)
is_composite_literal_key_(false)
{ } { }
// The associated named object. // The associated named object.
...@@ -2901,18 +2905,6 @@ class Unknown_expression : public Parser_expression ...@@ -2901,18 +2905,6 @@ class Unknown_expression : public Parser_expression
set_no_error_message() set_no_error_message()
{ this->no_error_message_ = true; } { this->no_error_message_ = true; }
// Note that this expression is being used as the key in a composite
// literal, so it may be OK if it is not resolved.
void
set_is_composite_literal_key()
{ this->is_composite_literal_key_ = true; }
// Note that this expression should no longer be treated as a
// composite literal key.
void
clear_is_composite_literal_key()
{ this->is_composite_literal_key_ = false; }
protected: protected:
Expression* Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int); do_lower(Gogo*, Named_object*, Statement_inserter*, int);
...@@ -2930,8 +2922,6 @@ class Unknown_expression : public Parser_expression ...@@ -2930,8 +2922,6 @@ class Unknown_expression : public Parser_expression
// True if we should not give errors if this is undefined. This is // True if we should not give errors if this is undefined. This is
// used if there was a parse failure. // used if there was a parse failure.
bool no_error_message_; bool no_error_message_;
// True if this is the key in a composite literal.
bool is_composite_literal_key_;
}; };
// An index expression. This is lowered to an array index, a string // An index expression. This is lowered to an array index, a string
......
...@@ -2200,7 +2200,7 @@ Parse::simple_var_decl_or_assignment(const std::string& name, ...@@ -2200,7 +2200,7 @@ Parse::simple_var_decl_or_assignment(const std::string& name,
p != til.end(); p != til.end();
++p) ++p)
exprs->push_back(this->id_to_expression(p->name(), p->location(), exprs->push_back(this->id_to_expression(p->name(), p->location(),
true)); true, false));
Expression_list* more_exprs = Expression_list* more_exprs =
this->expression_list(NULL, true, may_be_composite_lit); this->expression_list(NULL, true, may_be_composite_lit);
...@@ -2820,7 +2820,7 @@ Parse::composite_lit(Type* type, int depth, Location location) ...@@ -2820,7 +2820,7 @@ Parse::composite_lit(Type* type, int depth, Location location)
Gogo* gogo = this->gogo_; Gogo* gogo = this->gogo_;
val = this->id_to_expression(gogo->pack_hidden_name(identifier, val = this->id_to_expression(gogo->pack_hidden_name(identifier,
is_exported), is_exported),
id_location, false); id_location, false, true);
is_name = true; is_name = true;
} }
else else
...@@ -2877,9 +2877,6 @@ Parse::composite_lit(Type* type, int depth, Location location) ...@@ -2877,9 +2877,6 @@ Parse::composite_lit(Type* type, int depth, Location location)
} }
has_keys = true; has_keys = true;
if (val->unknown_expression() != NULL)
val->unknown_expression()->set_is_composite_literal_key();
vals->push_back(val); vals->push_back(val);
if (!token->is_op(OPERATOR_LCURLY)) if (!token->is_op(OPERATOR_LCURLY))
...@@ -3345,12 +3342,22 @@ Parse::call(Expression* func) ...@@ -3345,12 +3342,22 @@ Parse::call(Expression* func)
Expression* Expression*
Parse::id_to_expression(const std::string& name, Location location, Parse::id_to_expression(const std::string& name, Location location,
bool is_lhs) bool is_lhs, bool is_composite_literal_key)
{ {
Named_object* in_function; Named_object* in_function;
Named_object* named_object = this->gogo_->lookup(name, &in_function); Named_object* named_object = this->gogo_->lookup(name, &in_function);
if (named_object == NULL) if (named_object == NULL)
named_object = this->gogo_->add_unknown_name(name, location); {
if (is_composite_literal_key)
{
// This is a composite literal key, which means that it
// could just be a struct field name, so avoid confusiong by
// not adding it to the bindings. We'll look up the name
// later during the lowering phase if necessary.
return Expression::make_composite_literal_key(name, location);
}
named_object = this->gogo_->add_unknown_name(name, location);
}
if (in_function != NULL if (in_function != NULL
&& in_function != this->gogo_->current_function() && in_function != this->gogo_->current_function()
...@@ -5167,7 +5174,7 @@ Parse::send_or_recv_stmt(bool* is_send, Expression** channel, Expression** val, ...@@ -5167,7 +5174,7 @@ Parse::send_or_recv_stmt(bool* is_send, Expression** channel, Expression** val,
*val = this->id_to_expression(gogo->pack_hidden_name(recv_var, *val = this->id_to_expression(gogo->pack_hidden_name(recv_var,
is_rv_exported), is_rv_exported),
recv_var_loc, true); recv_var_loc, true, false);
saw_comma = true; saw_comma = true;
} }
else else
......
...@@ -231,7 +231,7 @@ class Parse ...@@ -231,7 +231,7 @@ class Parse
bool* is_type_switch, bool* is_parenthesized); bool* is_type_switch, bool* is_parenthesized);
Type* reassociate_chan_direction(Channel_type*, Location); Type* reassociate_chan_direction(Channel_type*, Location);
Expression* qualified_expr(Expression*, Location); Expression* qualified_expr(Expression*, Location);
Expression* id_to_expression(const std::string&, Location, bool); Expression* id_to_expression(const std::string&, Location, bool, bool);
void statement(Label*); void statement(Label*);
bool statement_may_start_here(); bool statement_may_start_here();
void labeled_stmt(const std::string&, Location); void labeled_stmt(const std::string&, Location);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment