diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 037353072f3..447e652860e 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -1455,8 +1455,9 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) { if (this->is_composite_literal_key_) return this; - error_at(location, "reference to undefined name %qs", - this->named_object_->message_name().c_str()); + if (!this->no_error_message_) + error_at(location, "reference to undefined name %qs", + this->named_object_->message_name().c_str()); return Expression::make_error(location); } } @@ -1469,8 +1470,9 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) case Named_object::NAMED_OBJECT_TYPE_DECLARATION: if (this->is_composite_literal_key_) return this; - error_at(location, "reference to undefined type %qs", - real->message_name().c_str()); + if (!this->no_error_message_) + error_at(location, "reference to undefined type %qs", + real->message_name().c_str()); return Expression::make_error(location); case Named_object::NAMED_OBJECT_VAR: real->var_value()->set_is_used(); @@ -1481,7 +1483,8 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) case Named_object::NAMED_OBJECT_PACKAGE: if (this->is_composite_literal_key_) return this; - error_at(location, "unexpected reference to package"); + if (!this->no_error_message_) + error_at(location, "unexpected reference to package"); return Expression::make_error(location); default: go_unreachable(); @@ -1499,7 +1502,7 @@ Unknown_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const // Make a reference to an unknown name. -Expression* +Unknown_expression* Expression::make_unknown_reference(Named_object* no, Location location) { return new Unknown_expression(no, location); @@ -8483,6 +8486,11 @@ Builtin_call_expression::do_check_types(Gogo*) || type->function_type() != NULL || type->is_slice_type()) ; + else if ((*p)->is_type_expression()) + { + // If this is a type expression it's going to give + // an error anyhow, so we don't need one here. + } else this->report_error(_("unsupported argument type to " "builtin function")); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index efe54d1c49f..6672b684e47 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -153,7 +153,7 @@ class Expression // Make a reference to an unknown name. In a correct program this // will always be lowered to a real const/var/func reference. - static Expression* + static Unknown_expression* make_unknown_reference(Named_object*, Location); // Make a constant bool expression. @@ -1554,7 +1554,8 @@ class Unknown_expression : public Parser_expression public: Unknown_expression(Named_object* named_object, Location location) : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location), - named_object_(named_object), is_composite_literal_key_(false) + named_object_(named_object), no_error_message_(false), + is_composite_literal_key_(false) { } // The associated named object. @@ -1566,6 +1567,13 @@ class Unknown_expression : public Parser_expression const std::string& name() const; + // Call this to indicate that we should not give an error if this + // name is never defined. This is used to avoid knock-on errors + // during an erroneous parse. + void + set_no_error_message() + { 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 @@ -1592,6 +1600,9 @@ class Unknown_expression : public Parser_expression private: // The unknown name. Named_object* named_object_; + // True if we should not give errors if this is undefined. This is + // used if there was a parse failure. + bool no_error_message_; // True if this is the key in a composite literal. bool is_composite_literal_key_; }; diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 9e40851b384..9ab4a3bf2ac 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -1108,6 +1108,10 @@ Named_object::get_tree(Gogo* gogo, Named_object* function) } break; + case NAMED_OBJECT_ERRONEOUS: + decl = error_mark_node; + break; + default: go_unreachable(); } diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 61d1bd8c116..cf16ef6ccd6 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -626,8 +626,8 @@ Gogo::start_function(const std::string& name, Function_type* type, const Typed_identifier* receiver = type->receiver(); Variable* this_param = new Variable(receiver->type(), NULL, false, true, true, location); - std::string name = receiver->name(); - if (name.empty()) + std::string rname = receiver->name(); + if (rname.empty()) { // We need to give receivers a name since they wind up in // DECL_ARGUMENTS. FIXME. @@ -635,10 +635,10 @@ Gogo::start_function(const std::string& name, Function_type* type, char buf[50]; snprintf(buf, sizeof buf, "r.%u", count); ++count; - name = buf; + rname = buf; } - if (!Gogo::is_sink_name(name)) - block->bindings()->add_variable(name, NULL, this_param); + if (!Gogo::is_sink_name(rname)) + block->bindings()->add_variable(rname, NULL, this_param); } const Typed_identifier_list* parameters = type->parameters(); @@ -654,8 +654,8 @@ Gogo::start_function(const std::string& name, Function_type* type, if (is_varargs && p + 1 == parameters->end()) param->set_is_varargs_parameter(); - std::string name = p->name(); - if (name.empty() || Gogo::is_sink_name(name)) + std::string pname = p->name(); + if (pname.empty() || Gogo::is_sink_name(pname)) { // We need to give parameters a name since they wind up // in DECL_ARGUMENTS. FIXME. @@ -663,9 +663,9 @@ Gogo::start_function(const std::string& name, Function_type* type, char buf[50]; snprintf(buf, sizeof buf, "p.%u", count); ++count; - name = buf; + pname = buf; } - block->bindings()->add_variable(name, NULL, param); + block->bindings()->add_variable(pname, NULL, param); } } @@ -834,6 +834,14 @@ Gogo::finish_block(Location location) return block; } +// Add an erroneous name. + +Named_object* +Gogo::add_erroneous_name(const std::string& name) +{ + return this->package_->bindings()->add_erroneous_name(name); +} + // Add an unknown name. Named_object* @@ -3522,6 +3530,7 @@ Block::traverse(Traverse* traverse) case Named_object::NAMED_OBJECT_TYPE_DECLARATION: case Named_object::NAMED_OBJECT_UNKNOWN: + case Named_object::NAMED_OBJECT_ERRONEOUS: break; case Named_object::NAMED_OBJECT_PACKAGE: @@ -4521,6 +4530,9 @@ Named_object::location() const case NAMED_OBJECT_UNINITIALIZED: go_unreachable(); + case NAMED_OBJECT_ERRONEOUS: + return Linemap::unknown_location(); + case NAMED_OBJECT_UNKNOWN: return this->unknown_value()->location(); @@ -4565,6 +4577,9 @@ Named_object::export_named_object(Export* exp) const case NAMED_OBJECT_UNKNOWN: go_unreachable(); + case NAMED_OBJECT_ERRONEOUS: + break; + case NAMED_OBJECT_CONST: this->const_value()->export_const(exp, this->name_); break; @@ -4751,6 +4766,9 @@ Bindings::add_named_object_to_contour(Contour* contour, Named_object* Bindings::new_definition(Named_object* old_object, Named_object* new_object) { + if (new_object->is_erroneous() && !old_object->is_erroneous()) + return new_object; + std::string reason; switch (old_object->classification()) { @@ -4758,6 +4776,9 @@ Bindings::new_definition(Named_object* old_object, Named_object* new_object) case Named_object::NAMED_OBJECT_UNINITIALIZED: go_unreachable(); + case Named_object::NAMED_OBJECT_ERRONEOUS: + return old_object; + case Named_object::NAMED_OBJECT_UNKNOWN: { Named_object* real = old_object->unknown_value()->real_named_object(); @@ -5003,6 +5024,7 @@ Bindings::traverse(Traverse* traverse, bool is_global) case Named_object::NAMED_OBJECT_TYPE_DECLARATION: case Named_object::NAMED_OBJECT_FUNC_DECLARATION: case Named_object::NAMED_OBJECT_UNKNOWN: + case Named_object::NAMED_OBJECT_ERRONEOUS: break; case Named_object::NAMED_OBJECT_SINK: diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index dfaa596b318..e7b06e51b22 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -267,6 +267,11 @@ class Gogo Block* finish_block(Location); + // Declare an erroneous name. This is used to avoid knock-on errors + // after a parsing error. + Named_object* + add_erroneous_name(const std::string& name); + // Declare an unknown name. This is used while parsing. The name // must be resolved by the end of the parse. Unknown names are // always added at the package level. @@ -1688,6 +1693,9 @@ class Named_object { // An uninitialized Named_object. We should never see this. NAMED_OBJECT_UNINITIALIZED, + // An erroneous name. This indicates a parse error, to avoid + // later errors about undefined references. + NAMED_OBJECT_ERRONEOUS, // An unknown name. This is used for forward references. In a // correct program, these will all be resolved by the end of the // parse. @@ -1719,6 +1727,10 @@ class Named_object // Classifiers. + bool + is_erroneous() const + { return this->classification_ == NAMED_OBJECT_ERRONEOUS; } + bool is_unknown() const { return this->classification_ == NAMED_OBJECT_UNKNOWN; } @@ -1761,6 +1773,10 @@ class Named_object // Creators. + static Named_object* + make_erroneous_name(const std::string& name) + { return new Named_object(name, NULL, NAMED_OBJECT_ERRONEOUS); } + static Named_object* make_unknown_name(const std::string& name, Location); @@ -2032,6 +2048,11 @@ class Bindings Bindings(Bindings* enclosing); + // Add an erroneous name. + Named_object* + add_erroneous_name(const std::string& name) + { return this->add_named_object(Named_object::make_erroneous_name(name)); } + // Add an unknown name. Named_object* add_unknown_name(const std::string& name, Location location) diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 35af7585472..c6014d560d2 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -45,6 +45,7 @@ Parse::Parse(Lex* lex, Gogo* gogo) token_(Token::make_invalid_token(Linemap::unknown_location())), unget_token_(Token::make_invalid_token(Linemap::unknown_location())), unget_token_valid_(false), + is_erroneous_function_(false), gogo_(gogo), break_stack_(NULL), continue_stack_(NULL), @@ -2123,8 +2124,6 @@ Parse::function_decl() this->advance_token(); Function_type* fntype = this->signature(rec, this->location()); - if (fntype == NULL) - return; Named_object* named_object = NULL; @@ -2171,13 +2170,28 @@ Parse::function_decl() if (!this->peek_token()->is_op(OPERATOR_LCURLY)) { if (named_object == NULL && !Gogo::is_sink_name(name)) - this->gogo_->declare_function(name, fntype, location); + { + if (fntype != NULL) + this->gogo_->declare_function(name, fntype, location); + else + this->gogo_->add_erroneous_name(name); + } } else { + bool hold_is_erroneous_function = this->is_erroneous_function_; + if (fntype == NULL) + { + fntype = Type::make_function_type(NULL, NULL, NULL, location); + this->is_erroneous_function_ = true; + if (!Gogo::is_sink_name(name)) + this->gogo_->add_erroneous_name(name); + name = this->gogo_->pack_hidden_name("_", false); + } this->gogo_->start_function(name, fntype, true, location); Location end_loc = this->block(); this->gogo_->finish_function(end_loc); + this->is_erroneous_function_ = hold_is_erroneous_function; } } @@ -2392,7 +2406,15 @@ Parse::operand(bool may_be_sink) return Expression::make_func_reference(named_object, NULL, location); case Named_object::NAMED_OBJECT_UNKNOWN: - return Expression::make_unknown_reference(named_object, location); + { + Unknown_expression* ue = + Expression::make_unknown_reference(named_object, location); + if (this->is_erroneous_function_) + ue->set_no_error_message(); + return ue; + } + case Named_object::NAMED_OBJECT_ERRONEOUS: + return Expression::make_error(location); default: go_unreachable(); } @@ -2698,14 +2720,22 @@ Parse::function_lit() hold_enclosing_vars.swap(this->enclosing_vars_); Function_type* type = this->signature(NULL, location); + bool fntype_is_error = false; if (type == NULL) - type = Type::make_function_type(NULL, NULL, NULL, location); + { + type = Type::make_function_type(NULL, NULL, NULL, location); + fntype_is_error = true; + } // For a function literal, the next token must be a '{'. If we // don't see that, then we may have a type expression. if (!this->peek_token()->is_op(OPERATOR_LCURLY)) return Expression::make_type(type, location); + bool hold_is_erroneous_function = this->is_erroneous_function_; + if (fntype_is_error) + this->is_erroneous_function_ = true; + Bc_stack* hold_break_stack = this->break_stack_; Bc_stack* hold_continue_stack = this->continue_stack_; this->break_stack_ = NULL; @@ -2724,6 +2754,8 @@ Parse::function_lit() this->break_stack_ = hold_break_stack; this->continue_stack_ = hold_continue_stack; + this->is_erroneous_function_ = hold_is_erroneous_function; + hold_enclosing_vars.swap(this->enclosing_vars_); Expression* closure = this->create_closure(no, &hold_enclosing_vars, @@ -3043,13 +3075,27 @@ Parse::id_to_expression(const std::string& name, Location location) case Named_object::NAMED_OBJECT_FUNC_DECLARATION: return Expression::make_func_reference(named_object, NULL, location); case Named_object::NAMED_OBJECT_UNKNOWN: - return Expression::make_unknown_reference(named_object, location); + { + Unknown_expression* ue = + Expression::make_unknown_reference(named_object, location); + if (this->is_erroneous_function_) + ue->set_no_error_message(); + return ue; + } case Named_object::NAMED_OBJECT_PACKAGE: case Named_object::NAMED_OBJECT_TYPE: case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - // These cases can arise for a field name in a composite - // literal. - return Expression::make_unknown_reference(named_object, location); + { + // These cases can arise for a field name in a composite + // literal. + Unknown_expression* ue = + Expression::make_unknown_reference(named_object, location); + if (this->is_erroneous_function_) + ue->set_no_error_message(); + return ue; + } + case Named_object::NAMED_OBJECT_ERRONEOUS: + return Expression::make_error(location); default: error_at(this->location(), "unexpected type of identifier"); return Expression::make_error(location); diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h index f45aa854d9b..a838e4bcbbf 100644 --- a/gcc/go/gofrontend/parse.h +++ b/gcc/go/gofrontend/parse.h @@ -305,6 +305,8 @@ class Parse Token unget_token_; // Whether unget_token_ is valid. bool unget_token_valid_; + // Whether the function we are parsing had errors in the signature. + bool is_erroneous_function_; // The code we are generating. Gogo* gogo_; // A stack of statements for which break may be used.