The Go frontend needs to call determine_types even for constant expressions, which it was not doing. The problem is that a constant expression may include code like unsafe.Sizeof(0). Something needs to determine the type of the untyped 0, and that should be the determine_types pass.
Implementing that triggered a compiler crash on test/const1.go because it permitted some erroneous constants to make it all the way to the backend. Catch that case by checking whether we get a constant overflow error, and marking the expression invalid if we do. This is a good change in any case, as previously we reported the same constant overflow error multiple times, and now we only report it once. This fixes GCC PR 78763. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 243682) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -5eb55901861f360c2c2ff70f14a8315694934c97 +e807c1deec1e7114bc4757b6193510fdae13e75f The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 243682) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -3738,8 +3738,12 @@ Unary_expression::do_lower(Gogo*, Named_ if (expr->numeric_constant_value(&nc)) { Numeric_constant result; - if (Unary_expression::eval_constant(op, &nc, loc, &result)) + bool issued_error; + if (Unary_expression::eval_constant(op, &nc, loc, &result, + &issued_error)) return result.expression(loc); + else if (issued_error) + return Expression::make_error(this->location()); } } @@ -3900,12 +3904,15 @@ Unary_expression::do_is_static_initializ } // Apply unary opcode OP to UNC, setting NC. Return true if this -// could be done, false if not. Issue errors for overflow. +// could be done, false if not. On overflow, issues an error and sets +// *ISSUED_ERROR. bool Unary_expression::eval_constant(Operator op, const Numeric_constant* unc, - Location location, Numeric_constant* nc) + Location location, Numeric_constant* nc, + bool* issued_error) { + *issued_error = false; switch (op) { case OPERATOR_PLUS: @@ -4050,7 +4057,12 @@ Unary_expression::eval_constant(Operator mpz_clear(uval); mpz_clear(val); - return nc->set_type(unc->type(), true, location); + if (!nc->set_type(unc->type(), true, location)) + { + *issued_error = true; + return false; + } + return true; } // Return the integral constant value of a unary expression, if it has one. @@ -4061,8 +4073,9 @@ Unary_expression::do_numeric_constant_va Numeric_constant unc; if (!this->expr_->numeric_constant_value(&unc)) return false; + bool issued_error; return Unary_expression::eval_constant(this->op_, &unc, this->location(), - nc); + nc, &issued_error); } // Return the type of a unary expression. @@ -4737,13 +4750,15 @@ Binary_expression::compare_complex(const // Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC. Return // true if this could be done, false if not. Issue errors at LOCATION -// as appropriate. +// as appropriate, and sets *ISSUED_ERROR if it did. bool Binary_expression::eval_constant(Operator op, Numeric_constant* left_nc, Numeric_constant* right_nc, - Location location, Numeric_constant* nc) + Location location, Numeric_constant* nc, + bool* issued_error) { + *issued_error = false; switch (op) { case OPERATOR_OROR: @@ -4792,7 +4807,11 @@ Binary_expression::eval_constant(Operato r = Binary_expression::eval_integer(op, left_nc, right_nc, location, nc); if (r) - r = nc->set_type(type, true, location); + { + r = nc->set_type(type, true, location); + if (!r) + *issued_error = true; + } return r; } @@ -5115,9 +5134,15 @@ Binary_expression::do_lower(Gogo* gogo, else { Numeric_constant nc; + bool issued_error; if (!Binary_expression::eval_constant(op, &left_nc, &right_nc, - location, &nc)) + location, &nc, + &issued_error)) + { + if (issued_error) + return Expression::make_error(location); return this; + } return nc.expression(location); } } @@ -5458,8 +5483,9 @@ Binary_expression::do_numeric_constant_v Numeric_constant right_nc; if (!this->right_->numeric_constant_value(&right_nc)) return false; + bool issued_error; return Binary_expression::eval_constant(this->op_, &left_nc, &right_nc, - this->location(), nc); + this->location(), nc, &issued_error); } // Note that the value is being discarded. @@ -5558,7 +5584,12 @@ Binary_expression::do_determine_type(con Type_context subcontext(*context); - if (is_comparison) + if (is_constant_expr) + { + subcontext.type = NULL; + subcontext.may_be_abstract = true; + } + else if (is_comparison) { // In a comparison, the context does not determine the types of // the operands. @@ -5600,8 +5631,7 @@ Binary_expression::do_determine_type(con subcontext.type = subcontext.type->make_non_abstract_type(); } - if (!is_constant_expr) - this->left_->determine_type(&subcontext); + this->left_->determine_type(&subcontext); if (is_shift_op) { @@ -5621,8 +5651,7 @@ Binary_expression::do_determine_type(con subcontext.may_be_abstract = false; } - if (!is_constant_expr) - this->right_->determine_type(&subcontext); + this->right_->determine_type(&subcontext); if (is_comparison) { Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 243321) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -1775,10 +1775,11 @@ class Unary_expression : public Expressi } // Apply unary opcode OP to UNC, setting NC. Return true if this - // could be done, false if not. Issue errors for overflow. + // could be done, false if not. On overflow, issues an error and + // sets *ISSUED_ERROR. static bool eval_constant(Operator op, const Numeric_constant* unc, - Location, Numeric_constant* nc); + Location, Numeric_constant* nc, bool *issued_error); static Expression* do_import(Import*); @@ -1893,11 +1894,11 @@ class Binary_expression : public Express // Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC. // Return true if this could be done, false if not. Issue errors at - // LOCATION as appropriate. + // LOCATION as appropriate, and sets *ISSUED_ERROR if it did. static bool eval_constant(Operator op, Numeric_constant* left_nc, Numeric_constant* right_nc, Location location, - Numeric_constant* nc); + Numeric_constant* nc, bool* issued_error); // Compare constants LEFT_NC and RIGHT_NC according to OP, setting // *RESULT. Return true if this could be done, false if not. Issue