compiler: Error if name defined in both package and file blocks.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 21 Dec 2012 22:23:23 +0000 (22:23 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 21 Dec 2012 22:23:23 +0000 (22:23 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@194685 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
libgo/go/image/image_test.go

index 41f9665..735b4c8 100644 (file)
@@ -29,6 +29,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
     package_(NULL),
     functions_(),
     globals_(new Bindings(NULL)),
+    file_block_names_(),
     imports_(),
     imported_unsafe_(false),
     packages_(),
@@ -1243,6 +1244,33 @@ Gogo::define_global_names()
       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 @@ Gogo::define_global_names()
 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 @@ Bindings::Bindings(Bindings* enclosing)
 // 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 @@ Bindings::clear_file_scope()
       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);
+       }
     }
 }
 
index cffdd21..f96ffcd 100644 (file)
@@ -377,6 +377,11 @@ class Gogo
   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 @@ class Gogo
   // This is used for initialization dependency analysis.
   typedef std::map<Variable*, Named_object*> 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 @@ class Gogo
   // 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 @@ class Bindings
 
   // 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.
index 2b3f149..2656757 100644 (file)
@@ -10,7 +10,7 @@ import (
        "testing"
 )
 
-type image interface {
+type timage interface {
        Image
        Opaque() bool
        Set(int, int, color.Color)
@@ -24,7 +24,7 @@ func cmp(t *testing.T, cm color.Model, c0, c1 color.Color) bool {
 }
 
 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 @@ func TestImage(t *testing.T) {
                        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 @@ func Test16BitsPerColorChannel(t *testing.T) {
                        continue
                }
        }
-       testImage := []image{
+       testImage := []timage{
                NewRGBA64(Rect(0, 0, 10, 10)),
                NewNRGBA64(Rect(0, 0, 10, 10)),
                NewAlpha16(Rect(0, 0, 10, 10)),