Without this change, cp_parser_constant_expression reports errors in
C++11 mode, but does not provide any indication to callers, which
continue processing and produce misleading errors.
The changes to check_bitfield_decl and build_enumerator are required for
identical error report in C++11 and C++98 mode. This removes several
spurious errors, and the testsuite is adjusted accordingly.
Bootstrapped on x86_64-linux-gnu with C, C++, TLO enabled, "make
check-c++" passes with no regressions.
(Sorry if Thunderbird has garbled the changelog entries.)
2012-06-04 Florian Weimer <fwei...@redhat.com>
* parser.c (cp_parser_constant_expression):
Return error_mark_node on error if !allow_non_constant_p.
* class.c (check_bitfield_decl): Handle error_mark_node in
width.
* decl.c (build_enumerator): Handle error_mark_node in value.
2012-06-04 Florian Weimer <fwei...@redhat.com>
* g++.dg/warn/overflow-warn-4.C, g++.dg/cpp0x/pr51225.C,
g++.dg/cpp0x/regress/error-recovery1.C: Adjust error messages.
Index: gcc/testsuite/g++.dg/warn/overflow-warn-4.C
===================================================================
--- gcc/testsuite/g++.dg/warn/overflow-warn-4.C (revision 188104)
+++ gcc/testsuite/g++.dg/warn/overflow-warn-4.C (working copy)
@@ -20,11 +20,9 @@ enum e {
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
- /* { dg-error "enumerator value for 'E5' is not an integer constant" "enum error" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
E6 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
- /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 25 } */
- /* { dg-error "enumerator value for 'E6' is not an integer constant" "enum error" { target *-*-* } 25 } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 24 } */
/* A cast does not constitute overflow in conversion. */
E7 = (char) INT_MAX
};
@@ -33,8 +31,7 @@ struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
- /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 35 } */
- /* { dg-error "bit-field .* width not an integer constant" "" { target *-*-* } 35 } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 33 } */
};
void
@@ -56,10 +53,10 @@ void *n = 0;
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
+/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 55 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 61 } */
+/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 58 } */
void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
void
@@ -70,7 +67,7 @@ g (int i)
case 0 * (1/0): /* { dg-warning "division by zero" } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
- /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 72 } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 69 } */
;
}
}
Index: gcc/testsuite/g++.dg/cpp0x/regress/error-recovery1.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/regress/error-recovery1.C (revision 188104)
+++ gcc/testsuite/g++.dg/cpp0x/regress/error-recovery1.C (working copy)
@@ -7,5 +7,3 @@ foo ()
const bool b =; // { dg-error "" }
foo < b > (); // { dg-error "constant expression" }
};
-
-// { dg-error "no match" "" { target *-*-* } 8 }
Index: gcc/testsuite/g++.dg/cpp0x/pr51225.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/pr51225.C (revision 188104)
+++ gcc/testsuite/g++.dg/cpp0x/pr51225.C (working copy)
@@ -12,3 +12,5 @@ template<typename> struct bar
{
static constexpr A<1> b = A<1>(x); // { dg-error "not declared" }
};
+
+// { dg-error "template argument.*invalid" "" { target *-*-* } 8 }
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c (revision 188104)
+++ gcc/cp/init.c (working copy)
@@ -2805,6 +2805,34 @@ build_new (VEC(tree,gc) **placement, tree type, tr
make_args_non_dependent (*init);
}
+ /* If the type is variably modified (a GNU extension for C
+ compatibility), we could end up with a variable-times-variable
+ multiplication at run time, complicating overflow checking. */
+ if (variably_modified_type_p (type, NULL_TREE))
+ {
+ /* Try to transform new (T[n]) to new T[n], and accept the
+ result if T is not variably modified. */
+ bool good = false;
+ if (nelts == NULL_TREE && TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree inner_type = TREE_TYPE (type);
+ if (!variably_modified_type_p (inner_type, NULL_TREE))
+ {
+ pedwarn (input_location, OPT_Wvla,
+ "ISO C++ forbids variable array length in parenthesized type-id");
+ nelts = array_type_nelts_top (type);
+ type = inner_type;
+ good = true;
+ }
+ }
+ if (!good)
+ {
+ if (complain & tf_error)
+ error ("new cannot be applied to a variably modified type");
+ return error_mark_node;
+ }
+ }
+
if (nelts)
{
if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false))
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c (revision 188104)
+++ gcc/cp/class.c (working copy)
@@ -2902,7 +2902,9 @@ check_bitfield_decl (tree field)
w = cxx_constant_value (w);
input_location = loc;
- if (TREE_CODE (w) != INTEGER_CST)
+ if (w == error_mark_node)
+ ; /* Continue with error processing below. */
+ else if (TREE_CODE (w) != INTEGER_CST)
{
error ("bit-field %q+D width not an integer constant", field);
w = error_mark_node;
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 188104)
+++ gcc/cp/decl.c (working copy)
@@ -12453,8 +12453,9 @@ build_enumerator (tree name, tree value, tree enum
if (TREE_CODE (value) != INTEGER_CST
|| ! INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (value)))
{
- error ("enumerator value for %qD is not an integer constant",
- name);
+ if (value != error_mark_node)
+ error ("enumerator value for %qD is not an integer constant",
+ name);
value = NULL_TREE;
}
}
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 188104)
+++ gcc/cp/parser.c (working copy)
@@ -7689,9 +7689,6 @@ cp_parser_constant_expression (cp_parser* parser,
determine whether a particular assignment-expression is in fact
constant. */
expression = cp_parser_assignment_expression (parser, /*cast_p=*/false, NULL);
- /* Restore the old settings. */
- parser->integral_constant_expression_p
- = saved_integral_constant_expression_p;
parser->allow_non_integral_constant_expression_p
= saved_allow_non_integral_constant_expression_p;
if (cxx_dialect >= cxx0x)
@@ -7701,11 +7698,17 @@ cp_parser_constant_expression (cp_parser* parser,
separately in e.g. cp_parser_template_argument. */
bool is_const = potential_rvalue_constant_expression (expression);
parser->non_integral_constant_expression_p = !is_const;
- if (!is_const && !allow_non_constant_p)
- require_potential_rvalue_constant_expression (expression);
+ if (!is_const && !allow_non_constant_p
+ && !require_potential_rvalue_constant_expression (expression))
+ expression = error_mark_node;
}
+ else if (!parser->integral_constant_expression_p
+ && !parser->non_integral_constant_expression_p)
+ expression = error_mark_node;
if (allow_non_constant_p)
*non_constant_p = parser->non_integral_constant_expression_p;
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
parser->non_integral_constant_expression_p
= saved_non_integral_constant_expression_p;