Patchwork C++ PATCH to fix the last couple of C++0x-mode testsuite regressions

login
register
mail settings
Submitter Jason Merrill
Date Feb. 25, 2011, 6:21 a.m.
Message ID <4D674A54.7070209@redhat.com>
Download mbox | patch
Permalink /patch/84516/
State New
Headers show

Comments

Jason Merrill - Feb. 25, 2011, 6:21 a.m.
The last couple of regressions caught by running the testsuite in 0x 
mode had to do with requiring a constant expression for array bounds. 
I've fixed this by checking for a potentially constant expression at 
cp_parser_constant_expression time as we do in C++98 mode, rather than 
depend on all clients to make sure that they have the constant 
expression they expect.  Making that change led to other failures which 
pointed out that value_dependent_expression_p needed to be updated to 
handle TYPEID_EXPR, and maybe_constant_value should reject unresolved 
overloading.

The second patch is various tweaks to testcases to either make them pass 
in C++0x mode, or clarify that they are C++98-specific.

Tested x86_64-pc-linux-gnu, applied to trunk.
commit 5780df71ec3751e1964be72ab7705f2660332e01
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Feb 24 20:40:18 2011 -0800

    	* parser.c (cp_parser_constant_expression): Set
    	non_integral_constant_expression correctly for C++0x too.
    	(cp_parser_static_assert): Allow non-constant expression.
    	(cp_parser_direct_declarator): Expect non_constant_p to be set
    	properly for C++0x.
    	* pt.c (value_dependent_expression_p): Handle TYPEID_EXPR.
    	* semantics.c (maybe_constant_value): Check type_unknown_p too.
    	(potential_rvalue_constant_expression): New.
    	(require_potential_rvalue_constant_expression): New.
commit 4c444b0a5b049f6b095129e2e4000fe6484b5c95
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Feb 24 20:40:41 2011 -0800

    	* g++.dg/parse/constant1.C: Specify C++98 mode.
    	* g++.dg/parse/constant5.C: Likewise.
    	* g++.dg/parse/error2.C: Likewise.
    	* g++.dg/parse/semicolon3.C: Likewise.
    	* g++.dg/template/crash14.C: Likewise.
    	* g++.dg/template/local4.C: Likewise.
    	* g++.dg/template/nontype3.C: Likewise.
    	* g++.dg/parse/crash31.C: Adjust expected errors.
    	* g++.dg/template/function1.C: Likewise.
    	* g++.dg/template/ref3.C: Likewise.
    	* g++.dg/template/static9.C: Likewise.
    	* g++.old-deja/g++.pt/crash41.C: Instantiate template.

diff --git a/gcc/testsuite/g++.dg/parse/constant1.C b/gcc/testsuite/g++.dg/parse/constant1.C
index 0a88928..c8a948a 100644
--- a/gcc/testsuite/g++.dg/parse/constant1.C
+++ b/gcc/testsuite/g++.dg/parse/constant1.C
@@ -1,3 +1,5 @@
+// { dg-options -std=c++98 }
+
 void f () {
   switch (0) {
   case (3, 0): // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/parse/constant5.C b/gcc/testsuite/g++.dg/parse/constant5.C
index db11afb..f868108 100644
--- a/gcc/testsuite/g++.dg/parse/constant5.C
+++ b/gcc/testsuite/g++.dg/parse/constant5.C
@@ -1,3 +1,5 @@
+// { dg-options "-std=c++98 -pedantic-errors" }
+
 enum E { 
   a = 24.2, // { dg-error "constant" }
   b = (int)3.7, 
diff --git a/gcc/testsuite/g++.dg/parse/crash31.C b/gcc/testsuite/g++.dg/parse/crash31.C
index 0068846..b0a7e18 100644
--- a/gcc/testsuite/g++.dg/parse/crash31.C
+++ b/gcc/testsuite/g++.dg/parse/crash31.C
@@ -3,7 +3,7 @@ struct A // { dg-error "forward declaration" }
   A : A; // { dg-error "expected|incomplete" }
   A : B; // { dg-error "not declared|incomplete" }
   A : A(); // { dg-error "undefined type|incomplete" }
-  A : B(); // { dg-error "function call|incomplete" }
+  A : B(); // { dg-error "function call|incomplete|not declared" }
   A : A[]; // { dg-error "expected|array reference|incomplete" }
   A : B[]; // { dg-error "not declared|expected|array reference|incomplete" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/error2.C b/gcc/testsuite/g++.dg/parse/error2.C
index 619f894..7b08df4 100644
--- a/gcc/testsuite/g++.dg/parse/error2.C
+++ b/gcc/testsuite/g++.dg/parse/error2.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-options "-fshow-column" }
+// { dg-options "-fshow-column -std=c++98" }
 // Properly print CALL_EXPRs while dumping expressions
 
 double g;
diff --git a/gcc/testsuite/g++.dg/parse/semicolon3.C b/gcc/testsuite/g++.dg/parse/semicolon3.C
index bc43b48..8a2b1ac 100644
--- a/gcc/testsuite/g++.dg/parse/semicolon3.C
+++ b/gcc/testsuite/g++.dg/parse/semicolon3.C
@@ -1,5 +1,6 @@
 // PR c++/45331
 // { dg-do compile }
+// { dg-options -std=c++98 }
 
 struct OK1
 {
diff --git a/gcc/testsuite/g++.dg/template/crash14.C b/gcc/testsuite/g++.dg/template/crash14.C
index 7b3af04..cf6fffa 100644
--- a/gcc/testsuite/g++.dg/template/crash14.C
+++ b/gcc/testsuite/g++.dg/template/crash14.C
@@ -1,3 +1,5 @@
+// { dg-options -std=c++98 }
+
 template <int T> class foo { public: foo() { } class Z { };};
 template <int I[2]> void dep7(foo<I[0]> *) { } // { dg-error "" }
 
diff --git a/gcc/testsuite/g++.dg/template/function1.C b/gcc/testsuite/g++.dg/template/function1.C
index 3f82d53..8a112c1 100644
--- a/gcc/testsuite/g++.dg/template/function1.C
+++ b/gcc/testsuite/g++.dg/template/function1.C
@@ -3,25 +3,25 @@
 
 template<const char *, int> struct A {};
 const char func[] = "abc";
-template<int N> struct A<func, N> {};	// { dg-error "cannot appear|is invalid|not a valid" }
+template<int N> struct A<func, N> {};	// { dg-error "cannot appear|is invalid|not a valid|not declared constexpr" }
 
 char a1[1];
 A<a1, 0> a;
 
 template<const char *, int> struct B {};
-template<int N> struct B<__FUNCTION__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid" }
+template<int N> struct B<__FUNCTION__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid|not declared constexpr" }
 
 char b1[1];
 B<b1, 0> b;
 
 template<const char *, int> struct C {};
-template<int N> struct C<__PRETTY_FUNCTION__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid" }
+template<int N> struct C<__PRETTY_FUNCTION__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid|not declared constexpr" }
 
 char c1[1];
 C<c1, 0> c;
 
 template<const char *, int> struct D {};
-template<int N> struct D<__func__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid|function scope" }
+template<int N> struct D<__func__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid|function scope|not declared constexpr" }
 
 char d1[1];
 D<d1, 0> d;
diff --git a/gcc/testsuite/g++.dg/template/local4.C b/gcc/testsuite/g++.dg/template/local4.C
index 7ee922b..9a03c9a 100644
--- a/gcc/testsuite/g++.dg/template/local4.C
+++ b/gcc/testsuite/g++.dg/template/local4.C
@@ -1,9 +1,10 @@
 // PR c++/17413
+// { dg-options -std=c++98 }
 
 template <typename T> void foo() {} // { dg-message "note" }
 
 int main () {
   struct S {};
   foo<S> (); // { dg-error "match" } 
-  // { dg-message "candidate" "candidate note" { target *-*-* } 7 }
+  // { dg-message "candidate" "candidate note" { target *-*-* } 8 }
 }
diff --git a/gcc/testsuite/g++.dg/template/nontype3.C b/gcc/testsuite/g++.dg/template/nontype3.C
index 5f24562..d0c6b72 100644
--- a/gcc/testsuite/g++.dg/template/nontype3.C
+++ b/gcc/testsuite/g++.dg/template/nontype3.C
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options -std=c++98 }
 // Origin: <drow at gcc dot gnu dot org>,
 //         <giovannibajo at gcc dot gnu dot org>
 // c++/13243: Template parameters of non integral or enumeration type can't be
diff --git a/gcc/testsuite/g++.dg/template/ref3.C b/gcc/testsuite/g++.dg/template/ref3.C
index 4390f71..976c093 100644
--- a/gcc/testsuite/g++.dg/template/ref3.C
+++ b/gcc/testsuite/g++.dg/template/ref3.C
@@ -4,8 +4,8 @@ template<const int&> struct A {};
 
 template<typename T> struct B
 {
-  A<(T)0> b; // { dg-error "constant" }
-  A<T(0)> a; // { dg-error "constant" }
+  A<(T)0> b; // { dg-error "constant|not a valid" }
+  A<T(0)> a; // { dg-error "constant|not a valid" }
 };
 
 B<const int&> b;
diff --git a/gcc/testsuite/g++.dg/template/static9.C b/gcc/testsuite/g++.dg/template/static9.C
index a9814418..8845647 100644
--- a/gcc/testsuite/g++.dg/template/static9.C
+++ b/gcc/testsuite/g++.dg/template/static9.C
@@ -3,7 +3,7 @@
 template<typename T> struct A
 {
   static const T i = 0; // { dg-error "declared void" "void" }
-			// { dg-error "invalid" "invalid" { target *-*-* } 5 }
+			// { dg-error "invalid|non-literal" "invalid" { target *-*-* } 5 }
 };
 
 A<void> a; // { dg-message "instantiated" }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash41.C b/gcc/testsuite/g++.old-deja/g++.pt/crash41.C
index fc7f7b5..452ba91 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/crash41.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash41.C
@@ -9,3 +9,5 @@ template <class T>
 void f(S2 s2) {
   S1<s2.i> s1; // { dg-error "" }
 }
+
+template void f<int>(S2);

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ee72322..d5a6d5c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5256,7 +5256,9 @@  extern tree register_constexpr_fundef (tree, tree);
 extern bool check_constexpr_ctor_body (tree, tree);
 extern tree ensure_literal_type_for_constexpr_object (tree);
 extern bool potential_constant_expression (tree);
+extern bool potential_rvalue_constant_expression (tree);
 extern bool require_potential_constant_expression (tree);
+extern bool require_potential_rvalue_constant_expression (tree);
 extern tree cxx_constant_value (tree);
 extern tree maybe_constant_value (tree);
 extern tree maybe_constant_init (tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 14d530a..93c1848 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5824,12 +5824,10 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
   if (init && TREE_CODE (decl) == VAR_DECL)
     {
       DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
-      /* FIXME we rely on TREE_CONSTANT below; basing that on
-	 init_const_expr_p is probably wrong for C++0x.  */
       if (init_const_expr_p)
 	{
-	  /* Set these flags now for C++98 templates.  We'll update the
-	     flags in store_init_value for instantiations and C++0x.  */
+	  /* Set these flags now for templates.  We'll update the flags in
+	     store_init_value for instantiations.  */
 	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
 	  if (decl_maybe_constant_var_p (decl))
 	    TREE_CONSTANT (decl) = 1;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 1e8f03b..314a2ff 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7266,10 +7266,19 @@  cp_parser_constant_expression (cp_parser* parser,
     = saved_integral_constant_expression_p;
   parser->allow_non_integral_constant_expression_p
     = saved_allow_non_integral_constant_expression_p;
+  if (cxx_dialect >= cxx0x)
+    {
+      /* Require an rvalue constant expression here; that's what our
+	 callers expect.  Reference constant expressions are handled
+	 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 (allow_non_constant_p)
     *non_constant_p = parser->non_integral_constant_expression_p;
-  else if (parser->non_integral_constant_expression_p
-	   && cxx_dialect < cxx0x)
+  else if (parser->non_integral_constant_expression_p)
     expression = error_mark_node;
   parser->non_integral_constant_expression_p
     = saved_non_integral_constant_expression_p;
@@ -10212,6 +10221,7 @@  cp_parser_static_assert(cp_parser *parser, bool member_p)
   tree message;
   cp_token *token;
   location_t saved_loc;
+  bool dummy;
 
   /* Peek at the `static_assert' token so we can keep track of exactly
      where the static assertion started.  */
@@ -10231,11 +10241,12 @@  cp_parser_static_assert(cp_parser *parser, bool member_p)
   /* Parse the `(' starting the static assertion condition.  */
   cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 
-  /* Parse the constant-expression.  */
+  /* Parse the constant-expression.  Allow a non-constant expression
+     here in order to give better diagnostics in finish_static_assert.  */
   condition = 
     cp_parser_constant_expression (parser,
-                                   /*allow_non_constant_p=*/false,
-                                   /*non_constant_p=*/NULL);
+                                   /*allow_non_constant_p=*/true,
+                                   /*non_constant_p=*/&dummy);
 
   /* Parse the separating `,'.  */
   cp_parser_require (parser, CPP_COMMA, RT_COMMA);
@@ -15115,7 +15126,7 @@  cp_parser_direct_declarator (cp_parser* parser,
 		= cp_parser_constant_expression (parser,
 						 /*allow_non_constant=*/true,
 						 &non_constant_p);
-	      if (!non_constant_p || cxx_dialect >= cxx0x)
+	      if (!non_constant_p)
 		/* OK */;
 	      /* Normally, the array bound must be an integral constant
 		 expression.  However, as an extension, we allow VLAs
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8d28219..ed9d28b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18091,6 +18091,7 @@  value_dependent_expression_p (tree expression)
 
     case SIZEOF_EXPR:
     case ALIGNOF_EXPR:
+    case TYPEID_EXPR:
       /* A `sizeof' expression is value-dependent if the operand is
 	 type-dependent or is a pack expansion.  */
       expression = TREE_OPERAND (expression, 0);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 8a7dd7d..199084a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7138,6 +7138,7 @@  maybe_constant_value (tree t)
   tree r;
 
   if (type_dependent_expression_p (t)
+      || type_unknown_p (t)
       || !potential_constant_expression (t)
       || value_dependent_expression_p (t))
     return t;
@@ -7727,6 +7728,14 @@  potential_constant_expression (tree t)
   return potential_constant_expression_1 (t, false, tf_none);
 }
 
+/* As above, but require a constant rvalue.  */
+
+bool
+potential_rvalue_constant_expression (tree t)
+{
+  return potential_constant_expression_1 (t, true, tf_none);
+}
+
 /* Like above, but complain about non-constant expressions.  */
 
 bool
@@ -7734,6 +7743,14 @@  require_potential_constant_expression (tree t)
 {
   return potential_constant_expression_1 (t, false, tf_warning_or_error);
 }
+
+/* Cross product of the above.  */
+
+bool
+require_potential_rvalue_constant_expression (tree t)
+{
+  return potential_constant_expression_1 (t, true, tf_warning_or_error);
+}
 
 /* Constructor for a lambda expression.  */
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-tparm.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-tparm.C
new file mode 100644
index 0000000..c17090c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-tparm.C
@@ -0,0 +1,5 @@ 
+// { dg-options -std=c++0x }
+
+template <const int I[2]> struct A { int ir[I[0]]; };
+extern constexpr int ar[2] = { 1, 2 };
+A<ar> a;
diff --git a/gcc/testsuite/g++.dg/cpp0x/regress/debug-debug7.C b/gcc/testsuite/g++.dg/cpp0x/regress/debug-debug7.C
new file mode 100644
index 0000000..8ee8824
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/regress/debug-debug7.C
@@ -0,0 +1,19 @@ 
+// { dg-do compile }
+// { dg-options -std=c++0x }
+
+void f (int);
+
+int
+main() {
+
+  int a = 4;
+  int b = 5;
+  int (*x)[b] = new int[a][b]; // { dg-error "" }
+
+  x[2][1] = 7;
+
+  for (int i = 0; i < a; ++i)
+    for (int j = 0; j < b; ++j)
+      f (x[i][j]);
+  delete [] x;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/regress/parse-ambig5.C b/gcc/testsuite/g++.dg/cpp0x/regress/parse-ambig5.C
new file mode 100644
index 0000000..9be2f92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/regress/parse-ambig5.C
@@ -0,0 +1,8 @@ 
+// PR c++/41786
+// { dg-options -std=c++0x }
+
+struct A { A(int, char const*); };
+int main() {
+  int i = 0, *b = &i;
+  A a(int(b[i]), "hello");
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/regress/template-function1.C b/gcc/testsuite/g++.dg/cpp0x/regress/template-function1.C
index ec686ee..028669e 100644
--- a/gcc/testsuite/g++.dg/cpp0x/regress/template-function1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/regress/template-function1.C
@@ -4,25 +4,25 @@ 
 
 template<const char *, int> struct A {};
 const char func[] = "abc";
-template<int N> struct A<func, N> {};	// { dg-error "cannot appear|is invalid|not a valid" }
+template<int N> struct A<func, N> {};	// { dg-error "cannot appear|is invalid|not a valid|not declared constexpr" }
 
 char a1[1];
 A<a1, 0> a;
 
 template<const char *, int> struct B {};
-template<int N> struct B<__FUNCTION__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid" }
+template<int N> struct B<__FUNCTION__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid|not declared constexpr" }
 
 char b1[1];
 B<b1, 0> b;
 
 template<const char *, int> struct C {};
-template<int N> struct C<__PRETTY_FUNCTION__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid" }
+template<int N> struct C<__PRETTY_FUNCTION__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid|not declared constexpr" }
 
 char c1[1];
 C<c1, 0> c;
 
 template<const char *, int> struct D {};
-template<int N> struct D<__func__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid|function scope" }
+template<int N> struct D<__func__, N> {};	// { dg-error "cannot appear|is invalid|is not a valid|function scope|not declared constexpr" }
 
 char d1[1];
 D<d1, 0> d;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic20.C b/gcc/testsuite/g++.dg/cpp0x/variadic20.C
index 06204c7..7f2446e 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic20.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic20.C
@@ -37,9 +37,9 @@  struct metatuple<First, Second, Metafunctions...> { // { dg-error "struct" }
 
 int a0[metatuple<>::value == 0? 1 : -1];
 int a1[metatuple<add_pointer>::value == 1? 1 : -1];
-int a2a[metatuple<add_pointer, add_pointer>::value == 2? 1 : -1]; // { dg-error "ambiguous" }
+int a2a[metatuple<add_pointer, add_pointer>::value == 2? 1 : -1]; // { dg-error "ambiguous|array bound" }
 int a2b[metatuple<add_reference, add_reference>::value == 2? 1 : -1];
-int a3[metatuple<add_pointer, add_reference>::value == 3? 1 : -1]; // { dg-error "ambiguous" }
+int a3[metatuple<add_pointer, add_reference>::value == 3? 1 : -1]; // { dg-error "ambiguous|array bound" }
 int a4[metatuple<add_reference>::value == 4? 1 : -1];
 int a5[metatuple<add_reference, add_pointer>::value == 5? 1 : -1];