re PR c++/49172 ([C++0x][constexpr] References should be declarable with constexpr)
authorJason Merrill <jason@redhat.com>
Wed, 22 Jun 2011 04:18:02 +0000 (00:18 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 22 Jun 2011 04:18:02 +0000 (00:18 -0400)
PR c++/49172
* decl.c (cp_finish_decl): Adjust init_const_expr_p for refs.
(grokdeclarator): constexpr doesn't apply const for refs.
* parser.c (cp_parser_initializer_clause): Don't call
maybe_constant_value here.
* call.c (initialize_reference): Handle constexpr.

From-SVN: r175284

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/decl.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C
gcc/testsuite/g++.dg/cpp0x/constexpr-ref1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C [new file with mode: 0644]

index cf325fc7926b85c93adf9e4d9e0b56aa522aa1b7..a329733f4e4d6569fa66ac9a16b96e38d76c3998 100644 (file)
@@ -1,5 +1,12 @@
 2011-06-21  Jason Merrill  <jason@redhat.com>
 
+       PR c++/49172
+       * decl.c (cp_finish_decl): Adjust init_const_expr_p for refs.
+       (grokdeclarator): constexpr doesn't apply const for refs.
+       * parser.c (cp_parser_initializer_clause): Don't call
+       maybe_constant_value here.
+       * call.c (initialize_reference): Handle constexpr.
+
        PR c++/49482
        * semantics.c (maybe_add_lambda_conv_op): Call mark_exp_read for
        static fn parameters.
index 8123e3dd25237584f1507d9c071d2f13c023383e..dd4dced8d723517dc7f5811e88530bee66148b70 100644 (file)
@@ -8629,6 +8629,8 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
       tree var;
       tree base_conv_type;
 
+      gcc_assert (complain == tf_warning_or_error);
+
       /* Skip over the REF_BIND.  */
       conv = conv->u.next;
       /* If the next conversion is a BASE_CONV, skip that too -- but
@@ -8646,7 +8648,7 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
                                /*inner=*/-1,
                                /*issue_conversion_warnings=*/true,
                                /*c_cast_p=*/false,
-                               tf_warning_or_error);
+                               complain);
       if (error_operand_p (expr))
        expr = error_mark_node;
       else
@@ -8667,18 +8669,24 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
            }
          else
            /* Take the address of EXPR.  */
-           expr = cp_build_addr_expr (expr, tf_warning_or_error);
+           expr = cp_build_addr_expr (expr, complain);
          /* If a BASE_CONV was required, perform it now.  */
          if (base_conv_type)
            expr = (perform_implicit_conversion
                    (build_pointer_type (base_conv_type), expr,
-                    tf_warning_or_error));
+                    complain));
          expr = build_nop (type, expr);
+         if (DECL_DECLARED_CONSTEXPR_P (decl))
+           {
+             expr = cxx_constant_value (expr);
+             DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
+               = reduced_constant_expression_p (expr);
+           }
        }
     }
   else
     /* Perform the conversion.  */
-    expr = convert_like (conv, expr, tf_warning_or_error);
+    expr = convert_like (conv, expr, complain);
 
   /* Free all the conversions we allocated.  */
   obstack_free (&conversion_obstack, p);
index 263ab3fdafe2a32a45f1cc4650171e2aef8dcbd7..b8435a6ddaa265091113df53a4373037f7ef3b57 100644 (file)
@@ -5987,6 +5987,11 @@ 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;
+      /* If DECL is a reference, then we want to know whether init is a
+        reference constant; init_const_expr_p as passed tells us whether
+        it's an rvalue constant.  */
+      if (TREE_CODE (type) == REFERENCE_TYPE)
+       init_const_expr_p = potential_constant_expression (init);
       if (init_const_expr_p)
        {
          /* Set these flags now for templates.  We'll update the flags in
@@ -9333,8 +9338,11 @@ grokdeclarator (const cp_declarator *declarator,
         error ("both %<const%> and %<constexpr%> cannot be used here");
       if (type_quals & TYPE_QUAL_VOLATILE)
         error ("both %<volatile%> and %<constexpr%> cannot be used here");
-      type_quals |= TYPE_QUAL_CONST;
-      type = cp_build_qualified_type (type, type_quals);
+      if (TREE_CODE (type) != REFERENCE_TYPE)
+       {
+         type_quals |= TYPE_QUAL_CONST;
+         type = cp_build_qualified_type (type, type_quals);
+       }
     }
 
   if (unqualified_id && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR
index 856a8a7b67c076dbb6721c203f1548d9d55297e3..f1b79761b8c742c55970f2076926501fb5ec892c 100644 (file)
@@ -16532,16 +16532,6 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
        = cp_parser_constant_expression (parser,
                                        /*allow_non_constant_p=*/true,
                                        non_constant_p);
-      if (!*non_constant_p)
-       {
-         /* We only want to fold if this is really a constant
-            expression.  FIXME Actually, we don't want to fold here, but in
-            cp_finish_decl.  */
-         tree folded = fold_non_dependent_expr (initializer);
-         folded = maybe_constant_value (folded);
-         if (TREE_CONSTANT (folded))
-           initializer = folded;
-       }
     }
   else
     initializer = cp_parser_braced_list (parser, non_constant_p);
index 59464fa2703ce339601a4b96d005cca7a023d549..fae9f953566acaa9898750273486feee053812e6 100644 (file)
@@ -1,5 +1,10 @@
 2011-06-21  Jason Merrill  <jason@redhat.com>
 
+       PR c++/49172
+       * g++.dg/cpp0x/constexpr-ref1.C: New.
+       * g++.dg/cpp0x/constexpr-ref2.C: New.
+       * g++.dg/cpp0x/constexpr-ice2.C: Remove dg-error tag.
+
        PR c++/49482
        * g++.dg/cpp0x/lambda/lambda-warn3.C: New.
 
index 35643b990c101bb4e10dc3c706150657e6783cb3..856246fcc95a3552d42ffad4645b7620ae96dcf2 100644 (file)
@@ -1,3 +1,3 @@
 // { dg-options -std=c++0x }
 int x;
-constexpr int& rx = x; // { dg-error "int&" }
+constexpr int& rx = x;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref1.C
new file mode 100644 (file)
index 0000000..482e1ba
--- /dev/null
@@ -0,0 +1,44 @@
+// PR c++/49172
+// { dg-options -std=c++0x }
+
+#define SA(X) static_assert((X),#X)
+
+constexpr int g() { return 42; };
+constexpr int(&rg)() = g; // #1
+
+SA(rg() == 42);
+
+constexpr int i = 24;
+constexpr int const& ri = i; // #2
+
+SA(&ri == &i);
+SA(ri == 24);
+
+void f()
+{
+  constexpr int(&rg)() = g; // #1
+
+  SA(rg() == 42);
+
+  constexpr static int i = 24;
+  constexpr int const& ri = i; // #2
+
+  SA(&ri == &i);
+  SA(ri == 24);
+}
+
+template <class T>
+void f2()
+{
+  constexpr int(&rg)() = g; // #1
+
+  SA(rg() == 42);
+
+  constexpr static int i = 24;
+  constexpr int const& ri = i; // #2
+
+  SA(&ri == &i);
+  SA(ri == 24);
+}
+
+template void f2<int>();
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C
new file mode 100644 (file)
index 0000000..2a86eb7
--- /dev/null
@@ -0,0 +1,17 @@
+// Negative reference variable tests.
+// { dg-options -std=c++0x }
+
+extern int *p;
+constexpr int& ri = *p;                // { dg-error "p" }
+
+extern constexpr int &er;      // { dg-error "not a definition" }
+constexpr int& ri2 = er;       // { dg-error "er" }
+
+void f(int j)
+{
+  constexpr int i = 42;
+  constexpr int const& ri = i; // { dg-error "" }
+
+  constexpr int& rj = j;       // { dg-error "" }
+}
+