Patchwork C++ PATCH for c++/49172 (allow constexpr reference variables)

login
register
mail settings
Submitter Jason Merrill
Date June 22, 2011, 4:19 a.m.
Message ID <4E016D35.6000102@redhat.com>
Download mbox | patch
Permalink /patch/101389/
State New
Headers show

Comments

Jason Merrill - June 22, 2011, 4:19 a.m.
We decided at the Madrid meeting to allow constexpr reference variables, 
and this patch adds that support to GCC.

Tested x86_64-pc-linux-gnu, applying to trunk.
Jason Merrill - Oct. 19, 2011, 8:36 p.m.
On 06/22/2011 12:19 AM, Jason Merrill wrote:
> We decided at the Madrid meeting to allow constexpr reference variables,
> and this patch adds that support to GCC.

The cp_parser_initializer_clause hunk also fixes 50787, a bug with 
direct binding of references in 4.6, so I'm applying that one there.

Tested x86_64-pc-linux-gnu.

Patch

commit 02d12daad9a5d1b265a328e43d758d9eedd9bb04
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jun 21 22:24:29 2011 -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.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 8123e3d..dd4dced 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 263ab3f..b8435a6 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 856a8a7..f1b7976 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C
index 35643b9..856246f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C
@@ -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
index 0000000..482e1ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref1.C
@@ -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
index 0000000..2a86eb7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C
@@ -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 "" }
+}
+