diff mbox

C++ PATCH for N4268, constant evaluation of non-type template arguments

Message ID 5625A235.5020800@redhat.com
State New
Headers show

Commit Message

Jason Merrill Oct. 20, 2015, 2:08 a.m. UTC
N4268 is the last bullet point remaining for C++1z features until 
Saturday, when presumably more stuff will be added.  The basic 
functionality is quite straightforward: first generalize parsing, then 
pass all arguments through maybe_constant_value.  But to get correct 
handling of pointers to members, we need to prevent constexpr evaluation 
from lowering PTRMEM_CST until it's really needed, namely if we're 
trying to use one in a .* expression or we're handing off to the 
language-independent code.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit fea6597952f6cb45b5751f1b2097a2092cb18b8d
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Oct 18 22:57:08 2015 -1000

    	Expand PTRMEM_CST only when necessary.
    
    	* constexpr.c (cxx_eval_constant_expression): Expand PTRMEM_CST
    	only when necessary.
    	(cxx_eval_component_reference): Like here.
    	* decl2.c (lower_var_init): And here.
    	(c_parse_final_cleanups): Call it.
    	* decl.c (complete_vars): Not here.
    	* typeck2.c (digest_init_r): Or here.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 6619c42..dd27b99 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1873,6 +1873,8 @@  cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 					     lval,
 					     non_constant_p, overflow_p);
+  if (TREE_CODE (whole) == PTRMEM_CST)
+    whole = cplus_expand_constant (whole);
   if (whole == orig_whole)
     return t;
   if (lval)
@@ -3139,9 +3141,7 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     }
   if (CONSTANT_CLASS_P (t))
     {
-      if (TREE_CODE (t) == PTRMEM_CST)
-	t = cplus_expand_constant (t);
-      else if (TREE_OVERFLOW (t) && (!flag_permissive || ctx->quiet))
+      if (TREE_OVERFLOW (t) && (!flag_permissive || ctx->quiet))
 	*overflow_p = true;
       return t;
     }
@@ -3555,7 +3555,11 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 						non_constant_p, overflow_p);
 	if (*non_constant_p)
 	  return t;
-	if (POINTER_TYPE_P (TREE_TYPE (t))
+	tree type = TREE_TYPE (t);
+	if (TREE_CODE (op) == PTRMEM_CST
+	    && !TYPE_PTRMEM_P (type))
+	  op = cplus_expand_constant (op);
+	if (POINTER_TYPE_P (type)
 	    && TREE_CODE (op) == INTEGER_CST
 	    && !integer_zerop (op))
 	  {
@@ -3569,7 +3573,7 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  /* We didn't fold at the top so we could check for ptr-int
 	     conversion.  */
 	  return fold (t);
-	r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), op);
+	r = fold_build1 (TREE_CODE (t), type, op);
 	/* Conversion of an out-of-range value has implementation-defined
 	   behavior; the language considers it different from arithmetic
 	   overflow, which is undefined.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5716a13..50bb39c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6714,6 +6714,9 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	       to put statics on the list so we can deal with the label
 	       address extension.  FIXME.  */
 	    add_local_decl (cfun, decl);
+	  /* And make sure it's in the symbol table for
+	     c_parse_final_cleanups to find.  */
+	  varpool_node::get_create (decl);
 	}
 
       /* Convert the initializer to the type of DECL, if we have not
@@ -14887,10 +14890,6 @@  complete_vars (tree type)
 	      cp_apply_type_quals_to_decl (cp_type_quals (type), var);
 	    }
 
-	  if (DECL_INITIAL (var)
-	      && decl_constant_var_p (var))
-	    DECL_INITIAL (var) = cplus_expand_constant (DECL_INITIAL (var));
-
 	  /* Remove this entry from the list.  */
 	  incomplete_vars->unordered_remove (ix);
 	}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a5b44e0..3b3817e 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4484,6 +4484,22 @@  maybe_warn_sized_delete ()
   maybe_warn_sized_delete (VEC_DELETE_EXPR);
 }
 
+/* Earlier we left PTRMEM_CST in variable initializers alone so that we could
+   look them up when evaluating non-type template parameters.  Now we need to
+   lower them to something the back end can understand.  */
+
+static void
+lower_var_init ()
+{
+  varpool_node *node;
+  FOR_EACH_VARIABLE (node)
+    {
+      tree d = node->decl;
+      if (tree init = DECL_INITIAL (d))
+	DECL_INITIAL (d) = cplus_expand_constant (init);
+    }
+}
+
 /* This routine is called at the end of compilation.
    Its job is to create all the code needed to initialize and
    destroy the global aggregates.  We do the destruction
@@ -4793,6 +4809,8 @@  c_parse_final_cleanups (void)
     }
   while (reconsider);
 
+  lower_var_init ();
+
   generate_mangling_aliases ();
 
   /* All used inline functions must have a definition at this point.  */
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 2c9143e..e61a57f 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1059,22 +1059,11 @@  digest_init_r (tree type, tree init, bool nested, int flags,
        || BRACE_ENCLOSED_INITIALIZER_P (init))
       && (SCALAR_TYPE_P (type) || code == REFERENCE_TYPE))
     {
-      tree *exp;
-
       if (nested)
 	flags |= LOOKUP_NO_NARROWING;
       init = convert_for_initialization (0, type, init, flags,
 					 ICR_INIT, NULL_TREE, 0,
 					 complain);
-      exp = &init;
-
-      /* Skip any conversions since we'll be outputting the underlying
-	 constant.  */
-      while (CONVERT_EXPR_P (*exp)
-	     || TREE_CODE (*exp) == NON_LVALUE_EXPR)
-	exp = &TREE_OPERAND (*exp, 0);
-
-      *exp = cplus_expand_constant (*exp);
 
       return init;
     }