From b1adbc27c4a85ded4db81ed65b1cefce4cee8d15 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 26 Nov 2020 16:11:28 -0800 Subject: [PATCH] compiler: avoid follow-on errors for bad types 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 | 2 +- gcc/go/gofrontend/expressions.cc | 39 +++++++++++++++- gcc/go/gofrontend/types.cc | 45 ++++++++++++++++--- gcc/go/gofrontend/types.h | 4 ++ .../go.test/test/fixedbugs/bug255.go | 21 +++++---- 5 files changed, 95 insertions(+), 16 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 59648326fcc..46959070e85 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 448888b0ad7..dc7399ebb3a 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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; diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index c4570b41a71..286ecc16366 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -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; } diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 5965d5a3fde..d0970295d75 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -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*); diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug255.go b/gcc/testsuite/go.test/test/fixedbugs/bug255.go index acf4f23910d..458fb972b20 100644 --- a/gcc/testsuite/go.test/test/fixedbugs/bug255.go +++ b/gcc/testsuite/go.test/test/fixedbugs/bug255.go @@ -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" -- 2.30.2