{
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);
}
}
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();
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();
// 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);
|| 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"));
// 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.
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.
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
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_;
};
}
break;
+ case NAMED_OBJECT_ERRONEOUS:
+ decl = error_mark_node;
+ break;
+
default:
go_unreachable();
}
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.
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();
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.
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);
}
}
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*
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:
case NAMED_OBJECT_UNINITIALIZED:
go_unreachable();
+ case NAMED_OBJECT_ERRONEOUS:
+ return Linemap::unknown_location();
+
case NAMED_OBJECT_UNKNOWN:
return this->unknown_value()->location();
case NAMED_OBJECT_UNKNOWN:
go_unreachable();
+ case NAMED_OBJECT_ERRONEOUS:
+ break;
+
case NAMED_OBJECT_CONST:
this->const_value()->export_const(exp, this->name_);
break;
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())
{
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();
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:
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.
{
// 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.
// Classifiers.
+ bool
+ is_erroneous() const
+ { return this->classification_ == NAMED_OBJECT_ERRONEOUS; }
+
bool
is_unknown() const
{ return this->classification_ == NAMED_OBJECT_UNKNOWN; }
// 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);
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)
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),
this->advance_token();
Function_type* fntype = this->signature(rec, this->location());
- if (fntype == NULL)
- return;
Named_object* named_object = NULL;
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;
}
}
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();
}
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;
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,
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);
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.