From patchwork Fri Dec 21 22:23:26 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Go patch committed: Date: Fri, 21 Dec 2012 12:23:26 -0000 From: Ian Taylor X-Patchwork-Id: 207893 Message-Id: To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com In Go it is an error if the same name is defined in both the package block (names defined anywhere in the package) and the file block (names defined only in a single file, which can only happen via import statements). The gccgo frontend was not diagnosing this error. This patch fixes the problem. This required a tweak to one of the tests. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian diff -r 9a016fbfe7b3 go/gogo.cc --- a/go/gogo.cc Fri Dec 21 06:59:06 2012 -0800 +++ b/go/gogo.cc Fri Dec 21 14:19:44 2012 -0800 @@ -29,6 +29,7 @@ package_(NULL), functions_(), globals_(new Bindings(NULL)), + file_block_names_(), imports_(), imported_unsafe_(false), packages_(), @@ -1243,6 +1244,33 @@ else if (no->is_unknown()) no->unknown_value()->set_real_named_object(global_no); } + + // Give an error if any name is defined in both the package block + // and the file block. For example, this can happen if one file + // imports "fmt" and another file defines a global variable fmt. + for (Bindings::const_declarations_iterator p = + this->package_->bindings()->begin_declarations(); + p != this->package_->bindings()->end_declarations(); + ++p) + { + if (p->second->is_unknown() + && p->second->unknown_value()->real_named_object() == NULL) + { + // No point in warning about an undefined name, as we will + // get other errors later anyhow. + continue; + } + File_block_names::const_iterator pf = + this->file_block_names_.find(p->second->name()); + if (pf != this->file_block_names_.end()) + { + std::string n = p->second->message_name(); + error_at(p->second->location(), + "%qs defined as both imported name and global name", + n.c_str()); + inform(pf->second, "%qs imported here", n.c_str()); + } + } } // Clear out names in file scope. @@ -1250,7 +1278,7 @@ void Gogo::clear_file_scope() { - this->package_->bindings()->clear_file_scope(); + this->package_->bindings()->clear_file_scope(this); // Warn about packages which were imported but not used. bool quiet = saw_errors(); @@ -4855,7 +4883,7 @@ // Clear imports. void -Bindings::clear_file_scope() +Bindings::clear_file_scope(Gogo* gogo) { Contour::iterator p = this->bindings_.begin(); while (p != this->bindings_.end()) @@ -4875,7 +4903,10 @@ if (keep) ++p; else - p = this->bindings_.erase(p); + { + gogo->add_file_block_name(p->second->name(), p->second->location()); + p = this->bindings_.erase(p); + } } } diff -r 9a016fbfe7b3 go/gogo.h --- a/go/gogo.h Fri Dec 21 06:59:06 2012 -0800 +++ b/go/gogo.h Fri Dec 21 14:19:44 2012 -0800 @@ -377,6 +377,11 @@ void add_named_object(Named_object*); + // Add an identifier to the list of names seen in the file block. + void + add_file_block_name(const std::string& name, Location location) + { this->file_block_names_[name] = location; } + // Mark all local variables in current bindings as used. This is // used when there is a parse error to avoid useless errors. void @@ -678,6 +683,10 @@ // This is used for initialization dependency analysis. typedef std::map Var_deps; + // Type used to map identifiers in the file block to the location + // where they were defined. + typedef Unordered_map(std::string, Location) File_block_names; + // Type used to queue writing a type specific function. struct Specific_type_function { @@ -710,6 +719,8 @@ // The global binding contour. This includes the builtin functions // and the package we are compiling. Bindings* globals_; + // The list of names we have seen in the file block. + File_block_names file_block_names_; // Mapping from import file names to packages. Imports imports_; // Whether the magic unsafe package was imported. @@ -2265,7 +2276,7 @@ // Clear all names in file scope from the bindings. void - clear_file_scope(); + clear_file_scope(Gogo*); // Look up a name in this binding contour and in any enclosing // binding contours. This returns NULL if the name is not found. diff -r 9a016fbfe7b3 libgo/go/image/image_test.go --- a/libgo/go/image/image_test.go Fri Dec 21 06:59:06 2012 -0800 +++ b/libgo/go/image/image_test.go Fri Dec 21 14:19:44 2012 -0800 @@ -10,7 +10,7 @@ "testing" ) -type image interface { +type timage interface { Image Opaque() bool Set(int, int, color.Color) @@ -24,7 +24,7 @@ } func TestImage(t *testing.T) { - testImage := []image{ + testImage := []timage{ NewRGBA(Rect(0, 0, 10, 10)), NewRGBA64(Rect(0, 0, 10, 10)), NewNRGBA(Rect(0, 0, 10, 10)), @@ -52,11 +52,11 @@ t.Errorf("%T: at (6, 3), want a non-zero color, got %v", m, m.At(6, 3)) continue } - if !m.SubImage(Rect(6, 3, 7, 4)).(image).Opaque() { + if !m.SubImage(Rect(6, 3, 7, 4)).(timage).Opaque() { t.Errorf("%T: at (6, 3) was not opaque", m) continue } - m = m.SubImage(Rect(3, 2, 9, 8)).(image) + m = m.SubImage(Rect(3, 2, 9, 8)).(timage) if !Rect(3, 2, 9, 8).Eq(m.Bounds()) { t.Errorf("%T: sub-image want bounds %v, got %v", m, Rect(3, 2, 9, 8), m.Bounds()) continue @@ -97,7 +97,7 @@ continue } } - testImage := []image{ + testImage := []timage{ NewRGBA64(Rect(0, 0, 10, 10)), NewNRGBA64(Rect(0, 0, 10, 10)), NewAlpha16(Rect(0, 0, 10, 10)),