diff mbox

C++ PATCH for c++/60992 (lambda and constant variable)

Message ID 53889E8C.7050501@redhat.com
State New
Headers show

Commit Message

Jason Merrill May 30, 2014, 3:06 p.m. UTC
On 05/02/2014 03:46 PM, Jason Merrill wrote:
> My change to avoid building a dummy variable in a nested function turns
> out to have been too aggressive; in this case, we have a reference to a
> local const variable in the type of an array that we're capturing.  It
> seems safe enough to make dummy copies of const and static variables
> when instantiating a lambda operator, so let's do that.

This was incomplete; we also need to instantiate the initializer.

And as long as we're handling this in some cases, let's stop returning 
the identifier from finish_id_expression.

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

Patch

commit 08e64eaaa5576eba62851b374fe734ff762bcc7e
Author: Jason Merrill <jason@redhat.com>
Date:   Tue May 27 17:12:35 2014 -0400

    	PR c++/60992
    	* pt.c (tsubst_init): Split out from...
    	(tsubst_expr) [DECL_EXPR]: Here.
    	(tsubst_copy) [VAR_DECL]: Use it.
    	* semantics.c (finish_id_expression): Return the decl for static/const.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0b3cd7f..a24e044 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12513,6 +12513,37 @@  tsubst_qualified_id (tree qualified_id, tree args,
   return expr;
 }
 
+/* tsubst the initializer for a VAR_DECL.  INIT is the unsubstituted
+   initializer, DECL is the substituted VAR_DECL.  Other arguments are as
+   for tsubst.  */
+
+static tree
+tsubst_init (tree init, tree decl, tree args,
+	     tsubst_flags_t complain, tree in_decl)
+{
+  if (!init)
+    return NULL_TREE;
+
+  init = tsubst_expr (init, args, complain, in_decl, false);
+
+  if (!init)
+    {
+      /* If we had an initializer but it
+	 instantiated to nothing,
+	 value-initialize the object.  This will
+	 only occur when the initializer was a
+	 pack expansion where the parameter packs
+	 used in that expansion were of length
+	 zero.  */
+      init = build_value_init (TREE_TYPE (decl),
+			       complain);
+      if (TREE_CODE (init) == AGGR_INIT_EXPR)
+	init = get_target_expr_sfinae (init, complain);
+    }
+
+  return init;
+}
+
 /* Like tsubst, but deals with expressions.  This function just replaces
    template parms; to finish processing the resultant expression, use
    tsubst_copy_and_build or tsubst_expr.  */
@@ -12670,11 +12701,34 @@  tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 		     local static or constant.  Building a new VAR_DECL
 		     should be OK in all those cases.  */
 		  r = tsubst_decl (t, args, complain);
-		  if (decl_constant_var_p (r))
-		    /* A use of a local constant must decay to its value.  */
-		    return integral_constant_value (r);
+		  if (decl_maybe_constant_var_p (r))
+		    {
+		      /* We can't call cp_finish_decl, so handle the
+			 initializer by hand.  */
+		      tree init = tsubst_init (DECL_INITIAL (t), r, args,
+					       complain, in_decl);
+		      if (!processing_template_decl)
+			init = maybe_constant_init (init);
+		      if (processing_template_decl
+			  ? potential_constant_expression (init)
+			  : reduced_constant_expression_p (init))
+			DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r)
+			  = TREE_CONSTANT (r) = true;
+		      DECL_INITIAL (r) = init;
+		    }
 		  gcc_assert (cp_unevaluated_operand || TREE_STATIC (r)
+			      || decl_constant_var_p (r)
 			      || errorcount || sorrycount);
+		  if (!processing_template_decl)
+		    {
+		      if (TREE_STATIC (r))
+			rest_of_decl_compilation (r, toplevel_bindings_p (),
+						  at_eof);
+		      else if (decl_constant_var_p (r))
+			/* A use of a local constant decays to its value.
+			   FIXME update for core DR 696.  */
+			return integral_constant_value (r);
+		    }
 		  return r;
 		}
 	    }
@@ -13544,26 +13598,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 			init = cp_fname_init (name, &TREE_TYPE (decl));
 		      }
 		    else
-		      {
-			tree t = RECUR (init);
-
-			if (init && !t)
-			  {
-			    /* If we had an initializer but it
-			       instantiated to nothing,
-			       value-initialize the object.  This will
-			       only occur when the initializer was a
-			       pack expansion where the parameter packs
-			       used in that expansion were of length
-			       zero.  */
-			    init = build_value_init (TREE_TYPE (decl),
-						     complain);
-			    if (TREE_CODE (init) == AGGR_INIT_EXPR)
-			      init = get_target_expr_sfinae (init, complain);
-			  }
-			else
-			  init = t;
-		      }
+		      init = tsubst_init (init, decl, args, complain, in_decl);
 
 		    if (VAR_P (decl))
 		      const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index edab330..396a893 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3166,12 +3166,7 @@  finish_id_expression (tree id_expression,
       else if (TREE_STATIC (decl)
 	       /* It's not a use (3.2) if we're in an unevaluated context.  */
 	       || cp_unevaluated_operand)
-	{
-	  if (processing_template_decl)
-	    /* For a use of an outer static/unevaluated var, return the id
-	       so that we'll look it up again in the instantiation.  */
-	    return id_expression;
-	}
+	/* OK */;
       else
 	{
 	  tree context = DECL_CONTEXT (decl);
@@ -3190,13 +3185,13 @@  finish_id_expression (tree id_expression,
 	     the complexity of the problem"
 
 	     FIXME update for final resolution of core issue 696.  */
-	  if (decl_constant_var_p (decl))
+	  if (decl_maybe_constant_var_p (decl))
 	    {
 	      if (processing_template_decl)
 		/* In a template, the constant value may not be in a usable
-		   form, so look it up again at instantiation time.  */
-		return id_expression;
-	      else
+		   form, so wait until instantiation time.  */
+		return decl;
+	      else if (decl_constant_var_p (decl))
 		return integral_constant_value (decl);
 	    }