compiler: avoid follow-on errors for bad types
authorIan Lance Taylor <iant@golang.org>
Fri, 27 Nov 2020 00:11:28 +0000 (16:11 -0800)
committerIan Lance Taylor <iant@golang.org>
Sat, 28 Nov 2020 15:01:41 +0000 (07:01 -0800)
Mark bad types as erroneous, to avoid generating further errors.

This required some code using array types to check for errors.

For https://golang.org/issue/19880

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/273626

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h
gcc/testsuite/go.test/test/fixedbugs/bug255.go

index 59648326fcc27d05549dc4ed34b58d174ad6f3e7..46959070e854a93de7aefd12b58e32c59f403a65 100644 (file)
@@ -1,4 +1,4 @@
-66669bb6cae475eda6666a94f6ff4f616ffa77d7
+16ab9b001c214cf831bc52a7bca5a2d18e9e4f3c
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 448888b0ad76def59c0dd27b637564dd7adb1127..dc7399ebb3a4d5bc293e59f1bcda8a26e597ca90 100644 (file)
@@ -15303,9 +15303,22 @@ Array_construction_expression::do_is_static_initializer() const
 void
 Array_construction_expression::do_determine_type(const Type_context*)
 {
+  if (this->is_error_expression())
+    {
+      go_assert(saw_errors());
+      return;
+    }
+
   if (this->vals() == NULL)
     return;
-  Type_context subcontext(this->type_->array_type()->element_type(), false);
+  Array_type* at = this->type_->array_type();
+  if (at == NULL || at->is_error() || at->element_type()->is_error())
+    {
+      go_assert(saw_errors());
+      this->set_is_error();
+      return;
+    }
+  Type_context subcontext(at->element_type(), false);
   for (Expression_list::const_iterator pv = this->vals()->begin();
        pv != this->vals()->end();
        ++pv)
@@ -15320,10 +15333,22 @@ Array_construction_expression::do_determine_type(const Type_context*)
 void
 Array_construction_expression::do_check_types(Gogo*)
 {
+  if (this->is_error_expression())
+    {
+      go_assert(saw_errors());
+      return;
+    }
+
   if (this->vals() == NULL)
     return;
 
   Array_type* at = this->type_->array_type();
+  if (at == NULL || at->is_error() || at->element_type()->is_error())
+    {
+      go_assert(saw_errors());
+      this->set_is_error();
+      return;
+    }
   int i = 0;
   Type* element_type = at->element_type();
   for (Expression_list::const_iterator pv = this->vals()->begin();
@@ -15348,6 +15373,12 @@ Expression*
 Array_construction_expression::do_flatten(Gogo*, Named_object*,
                                           Statement_inserter* inserter)
 {
+  if (this->is_error_expression())
+    {
+      go_assert(saw_errors());
+      return this;
+    }
+
   if (this->vals() == NULL)
     return this;
 
@@ -15384,6 +15415,12 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*,
 void
 Array_construction_expression::do_add_conversions()
 {
+  if (this->is_error_expression())
+    {
+      go_assert(saw_errors());
+      return;
+    }
+
   if (this->vals() == NULL)
     return;
 
index c4570b41a71bd7707b947d5a5d272c9446cf6858..286ecc16366f29bf22797943ffe4934adfecc89c 100644 (file)
@@ -261,6 +261,15 @@ Type::is_error_type() const
     }
 }
 
+// Note that this type is an error.  This is called by children when
+// they discover an error during the verify_types pass.
+
+void
+Type::set_is_error()
+{
+  this->classification_ = TYPE_ERROR;
+}
+
 // If this is a pointer type, return the type to which it points.
 // Otherwise, return NULL.
 
@@ -5871,6 +5880,7 @@ Struct_type::do_verify()
            {
              go_error_at(p->location(), "embedded type may not be a pointer");
              p->set_type(Type::make_error_type());
+             this->set_is_error();
            }
          else if (t->points_to() != NULL
                   && t->points_to()->interface_type() != NULL)
@@ -5878,6 +5888,7 @@ Struct_type::do_verify()
              go_error_at(p->location(),
                       "embedded type may not be pointer to interface");
              p->set_type(Type::make_error_type());
+             this->set_is_error();
            }
        }
     }
@@ -7236,6 +7247,13 @@ Array_type::verify_length()
   Type_context context(Type::lookup_integer_type("int"), false);
   this->length_->determine_type(&context);
 
+  if (this->length_->is_error_expression()
+      || this->length_->type()->is_error())
+    {
+      go_assert(saw_errors());
+      return false;
+    }
+
   if (!this->length_->is_constant())
     {
       go_error_at(this->length_->location(), "array bound is not constant");
@@ -7310,7 +7328,10 @@ Array_type::do_verify()
   if (this->element_type()->is_error_type())
     return false;
   if (!this->verify_length())
-    this->length_ = Expression::make_error(this->length_->location());
+    {
+      this->length_ = Expression::make_error(this->length_->location());
+      this->set_is_error();
+    }
   return true;
 }
 
@@ -8125,11 +8146,20 @@ Map_type::do_verify()
 {
   // The runtime support uses "map[void]void".
   if (!this->key_type_->is_comparable() && !this->key_type_->is_void_type())
-    go_error_at(this->location_, "invalid map key type");
+    {
+      go_error_at(this->location_, "invalid map key type");
+      this->set_is_error();
+    }
   if (!this->key_type_->in_heap())
-    go_error_at(this->location_, "go:notinheap map key not allowed");
+    {
+      go_error_at(this->location_, "go:notinheap map key not allowed");
+      this->set_is_error();
+    }
   if (!this->val_type_->in_heap())
-    go_error_at(this->location_, "go:notinheap map value not allowed");
+    {
+      go_error_at(this->location_, "go:notinheap map value not allowed");
+      this->set_is_error();
+    }
   return true;
 }
 
@@ -8660,8 +8690,11 @@ Channel_type::do_verify()
   // We have no location for this error, but this is not something the
   // ordinary user will see.
   if (!this->element_type_->in_heap())
-    go_error_at(Linemap::unknown_location(),
-               "chan of go:notinheap type not allowed");
+    {
+      go_error_at(Linemap::unknown_location(),
+                 "chan of go:notinheap type not allowed");
+      this->set_is_error();
+    }
   return true;
 }
 
index 5965d5a3fdeccf734b4998a81c07db6a582d3d72..d0970295d755be75e1335affab89ca41af3e7691 100644 (file)
@@ -1141,6 +1141,10 @@ class Type
   virtual void
   do_export(Export*) const;
 
+  // For children to call when they detect that they are in error.
+  void
+  set_is_error();
+
   // Return whether a method expects a pointer as the receiver.
   static bool
   method_expects_pointer(const Named_object*);
index acf4f23910d69f2a48f530c1744cd2aef6446c89..458fb972b20958484e89e011c97a7c179097c14c 100644 (file)
@@ -1,15 +1,20 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// Copyright 2010 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
 package main
 
-var a [10]int  // ok
-var b [1e1]int // ok
-var c [1.5]int // ERROR "truncated"
-var d ["abc"]int       // ERROR "invalid array bound|not numeric"
-var e [nil]int // ERROR "invalid array bound|not numeric"
-var f [e]int   // ERROR "invalid array bound|not constant"
-var g [1<<65]int       // ERROR "array bound is too large|overflows"
+var a [10]int      // ok
+var b [1e1]int     // ok
+var c [1.5]int     // ERROR "truncated"
+var d ["abc"]int   // ERROR "invalid array bound|not numeric"
+var e [nil]int     // ERROR "use of untyped nil|invalid array bound|not numeric"
+var f [e]int       // ok: error already reported for e
+var g [1 << 65]int // ERROR "array bound is too large|overflows"
+var h [len(a)]int  // ok
+
+func ff() string
+
+var i [len([1]string{ff()})]int // ERROR "non-constant array bound|not constant"