@@ -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);
@@ -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;
@@ -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
@@ -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);
@@ -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. */
new file mode 100644
@@ -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;
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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");
+}
@@ -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;
@@ -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];
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);