diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-12-05 00:22:13 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-12-05 00:22:13 +0000 |
commit | 54d04de72b3232ec654ea4824f8b1e37f0cb1961 (patch) | |
tree | cbe1685ae7bb4bcb0b4607d751bd180d8c95a87b /gcc/go | |
parent | e9bfc6060b11515bd9a9d1134d9691f34fd7c62c (diff) | |
download | gcc-54d04de72b3232ec654ea4824f8b1e37f0cb1961.zip gcc-54d04de72b3232ec654ea4824f8b1e37f0cb1961.tar.gz gcc-54d04de72b3232ec654ea4824f8b1e37f0cb1961.tar.bz2 |
compiler: Check for negative or inverted arguments to make.
From-SVN: r194173
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 61 |
1 files changed, 43 insertions, 18 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 7a5fcf2..3734d9b 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -6623,7 +6623,7 @@ class Builtin_call_expression : public Call_expression lower_make(); bool - check_int_value(Expression*); + check_int_value(Expression*, bool is_length); // A pointer back to the general IR structure. This avoids a global // variable, or passing it around everywhere. @@ -6897,11 +6897,8 @@ Builtin_call_expression::lower_make() else { len_arg = *parg; - if (!this->check_int_value(len_arg)) - { - this->report_error(_("bad size for make")); - return Expression::make_error(this->location()); - } + if (!this->check_int_value(len_arg, true)) + return Expression::make_error(this->location()); if (len_arg->type()->integer_type() != NULL && len_arg->type()->integer_type()->bits() > uintptr_bits) have_big_args = true; @@ -6912,11 +6909,23 @@ Builtin_call_expression::lower_make() if (is_slice && parg != args->end()) { cap_arg = *parg; - if (!this->check_int_value(cap_arg)) - { - this->report_error(_("bad capacity when making slice")); + if (!this->check_int_value(cap_arg, false)) + return Expression::make_error(this->location()); + + Numeric_constant nclen; + Numeric_constant nccap; + unsigned long vlen; + unsigned long vcap; + if (len_arg->numeric_constant_value(&nclen) + && cap_arg->numeric_constant_value(&nccap) + && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID + && nccap.to_unsigned_long(&vcap) == Numeric_constant::NC_UL_VALID + && vlen > vcap) + { + this->report_error(_("len larger than cap")); return Expression::make_error(this->location()); } + if (cap_arg->type()->integer_type() != NULL && cap_arg->type()->integer_type()->bits() > uintptr_bits) have_big_args = true; @@ -6973,20 +6982,36 @@ Builtin_call_expression::lower_make() // function. bool -Builtin_call_expression::check_int_value(Expression* e) +Builtin_call_expression::check_int_value(Expression* e, bool is_length) { - if (e->type()->integer_type() != NULL) - return true; - - // Check for a floating point constant with integer value. Numeric_constant nc; - mpz_t ival; - if (e->numeric_constant_value(&nc) && nc.to_int(&ival)) + if (e->numeric_constant_value(&nc)) { - mpz_clear(ival); - return true; + unsigned long v; + switch (nc.to_unsigned_long(&v)) + { + case Numeric_constant::NC_UL_VALID: + return true; + case Numeric_constant::NC_UL_NOTINT: + error_at(e->location(), "non-integer %s argument to make", + is_length ? "len" : "cap"); + return false; + case Numeric_constant::NC_UL_NEGATIVE: + error_at(e->location(), "negative %s argument to make", + is_length ? "len" : "cap"); + return false; + case Numeric_constant::NC_UL_BIG: + // We don't want to give a compile-time error for a 64-bit + // value on a 32-bit target. + return true; + } } + if (e->type()->integer_type() != NULL) + return true; + + error_at(e->location(), "non-integer %s argument to make", + is_length ? "len" : "cap"); return false; } |