This patch to the Go compiler avoids useless knockon errors for invalid uses of the blank identifier "_". I added a simple general facility for erroneous names although it is currently only used for _. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.8 branch.
Ian
diff -r a8b1cc175cc1 go/gogo-tree.cc --- a/go/gogo-tree.cc Fri Sep 27 15:11:52 2013 -0700 +++ b/go/gogo-tree.cc Sat Sep 28 13:21:19 2013 -0700 @@ -1061,6 +1061,12 @@ if (this->tree_ != NULL_TREE) return this->tree_; + if (Gogo::is_erroneous_name(this->name_)) + { + this->tree_ = error_mark_node; + return error_mark_node; + } + tree name; if (this->classification_ == NAMED_OBJECT_TYPE) name = NULL_TREE; diff -r a8b1cc175cc1 go/gogo.cc --- a/go/gogo.cc Fri Sep 27 15:11:52 2013 -0700 +++ b/go/gogo.cc Sat Sep 28 13:21:19 2013 -0700 @@ -1192,6 +1192,27 @@ this->interface_types_.push_back(itype); } +// Return an erroneous name that indicates that an error has already +// been reported. + +std::string +Gogo::erroneous_name() +{ + static int erroneous_count; + char name[50]; + snprintf(name, sizeof name, "$erroneous%d", erroneous_count); + ++erroneous_count; + return name; +} + +// Return whether a name is an erroneous name. + +bool +Gogo::is_erroneous_name(const std::string& name) +{ + return name.compare(0, 10, "$erroneous") == 0; +} + // Return a name for a thunk object. std::string diff -r a8b1cc175cc1 go/gogo.h --- a/go/gogo.h Fri Sep 27 15:11:52 2013 -0700 +++ b/go/gogo.h Sat Sep 28 13:21:19 2013 -0700 @@ -387,6 +387,16 @@ void mark_locals_used(); + // Return a name to use for an error case. This should only be used + // after reporting an error, and is used to avoid useless knockon + // errors. + static std::string + erroneous_name(); + + // Return whether the name indicates an error. + static bool + is_erroneous_name(const std::string&); + // Return a name to use for a thunk function. A thunk function is // one we create during the compilation, for a go statement or a // defer statement or a method expression. diff -r a8b1cc175cc1 go/parse.cc --- a/go/parse.cc Fri Sep 27 15:11:52 2013 -0700 +++ b/go/parse.cc Sat Sep 28 13:21:19 2013 -0700 @@ -213,7 +213,7 @@ if (name == "_") { error_at(this->location(), "invalid use of %<_%>"); - name = "blank"; + name = Gogo::erroneous_name(); } if (package->name() == this->gogo_->package_name()) @@ -3104,7 +3104,7 @@ if (token->identifier() == "_") { error_at(this->location(), "invalid use of %<_%>"); - name = this->gogo_->pack_hidden_name("blank", false); + name = Gogo::erroneous_name(); } this->advance_token(); return Expression::make_selector(left, name, location); @@ -4929,7 +4929,7 @@ { error_at(recv_var_loc, "no new variables on left side of %<:=%>"); - recv_var = "blank"; + recv_var = Gogo::erroneous_name(); } *is_send = false; *varname = gogo->pack_hidden_name(recv_var, is_rv_exported); @@ -4965,7 +4965,7 @@ { error_at(recv_var_loc, "no new variables on left side of %<:=%>"); - recv_var = "blank"; + recv_var = Gogo::erroneous_name(); } *is_send = false; if (recv_var != "_") @@ -5502,7 +5502,7 @@ if (name == "_") { error_at(this->location(), "invalid package name _"); - name = "blank"; + name = Gogo::erroneous_name(); } this->advance_token(); } diff -r a8b1cc175cc1 go/types.cc --- a/go/types.cc Fri Sep 27 15:11:52 2013 -0700 +++ b/go/types.cc Sat Sep 28 13:21:19 2013 -0700 @@ -9269,7 +9269,11 @@ } else { - if (!ambig1.empty()) + if (Gogo::is_erroneous_name(name)) + { + // An error was already reported. + } + else if (!ambig1.empty()) error_at(location, "%qs is ambiguous via %qs and %qs", Gogo::message_name(name).c_str(), ambig1.c_str(), ambig2.c_str());