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;
 

Reply via email to