Capture adjustments for P0588R1.
authorJason Merrill <jason@redhat.com>
Mon, 13 Nov 2017 22:34:38 +0000 (17:34 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 13 Nov 2017 22:34:38 +0000 (17:34 -0500)
* semantics.c (process_outer_var_ref): Capture variables when
they are named; complain about non-capture uses when odr-used.
* expr.c (mark_use): Rvalue use looks through capture proxy.
* constexpr.c (potential_constant_expression_1): Improve error about
use of captured variable.
* lambda.c (need_generic_capture, dependent_capture_r)
(do_dependent_capture, processing_nonlambda_template): Remove.
* call.c (build_this): Remove uses of the above.
* decl.c (cp_finish_decl): Likewise.
* semantics.c (maybe_cleanup_point_expr)
(maybe_cleanup_point_expr_void, finish_goto_stmt)
(maybe_convert_cond): Likewise.
* typeck.c (check_return_expr): Likewise.

From-SVN: r254713

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/expr.c
gcc/cp/lambda.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/typeck.c

index f71506b..ce0c874 100644 (file)
@@ -1,5 +1,20 @@
 2017-11-13  Jason Merrill  <jason@redhat.com>
 
+       Capture adjustments for P0588R1.
+       * semantics.c (process_outer_var_ref): Capture variables when
+       they are named; complain about non-capture uses when odr-used.
+       * expr.c (mark_use): Rvalue use looks through capture proxy.
+       * constexpr.c (potential_constant_expression_1): Improve error about
+       use of captured variable.
+       * lambda.c (need_generic_capture, dependent_capture_r)
+       (do_dependent_capture, processing_nonlambda_template): Remove.
+       * call.c (build_this): Remove uses of the above.
+       * decl.c (cp_finish_decl): Likewise.
+       * semantics.c (maybe_cleanup_point_expr)
+       (maybe_cleanup_point_expr_void, finish_goto_stmt)
+       (maybe_convert_cond): Likewise.
+       * typeck.c (check_return_expr): Likewise.
+
        Defer folding of *&.
        * typeck.c (cp_build_fold_indirect_ref): New.
        (cp_build_indirect_ref_1): Split out from cp_build_indirect_ref.
index e18f077..e09cf97 100644 (file)
@@ -3365,7 +3365,7 @@ build_this (tree obj)
 {
   /* In a template, we are only concerned about the type of the
      expression, so we can take a shortcut.  */
-  if (processing_nonlambda_template ())
+  if (processing_template_decl)
     return build_address (obj);
 
   return cp_build_addr_expr (obj, tf_warning_or_error);
index 670aae2..d6b6843 100644 (file)
@@ -1286,8 +1286,6 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
          && is_dummy_object (x))
        {
          x = ctx->object;
-         /* We don't use cp_build_addr_expr here because we don't want to
-            capture the object argument during constexpr evaluation.  */
          x = build_address (x);
        }
       bool lval = false;
@@ -5289,7 +5287,25 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 
     case VAR_DECL:
       if (DECL_HAS_VALUE_EXPR_P (t))
-       return RECUR (DECL_VALUE_EXPR (t), rval);
+       {
+         if (now && is_normal_capture_proxy (t))
+           {
+             /* -- in a lambda-expression, a reference to this or to a
+                variable with automatic storage duration defined outside that
+                lambda-expression, where the reference would be an
+                odr-use.  */
+             if (flags & tf_error)
+               {
+                 tree cap = DECL_CAPTURED_VARIABLE (t);
+                 error ("lambda capture of %qE is not a constant expression",
+                        cap);
+                 if (!want_rval && decl_constant_var_p (cap))
+                   inform (input_location, "because it is used as a glvalue");
+               }
+             return false;
+           }
+         return RECUR (DECL_VALUE_EXPR (t), rval);
+       }
       if (want_rval
          && !var_in_maybe_constexpr_fn (t)
          && !type_dependent_expression_p (t)
index ea61e87..b994206 100644 (file)
@@ -6462,7 +6462,6 @@ extern int uses_template_parms                    (tree);
 extern bool uses_template_parms_level          (tree, int);
 extern bool in_template_function               (void);
 extern bool need_generic_capture               (void);
-extern bool processing_nonlambda_template      (void);
 extern tree instantiate_class_template         (tree);
 extern tree instantiate_template               (tree, tree, tsubst_flags_t);
 extern tree fn_type_unification                        (tree, tree, tree,
index 54077d5..2e356a0 100644 (file)
@@ -6844,8 +6844,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
          DECL_INITIAL (decl) = NULL_TREE;
        }
 
-      init = do_dependent_capture (init);
-
       /* Generally, initializers in templates are expanded when the
         template is instantiated.  But, if DECL is a variable constant
         then it can be used in future constant expressions, so its value
index 23e30cf..81b9a5b 100644 (file)
@@ -111,6 +111,14 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
     {
     case VAR_DECL:
     case PARM_DECL:
+      if (rvalue_p && is_normal_capture_proxy (expr))
+       {
+         /* Look through capture by copy.  */
+         tree cap = DECL_CAPTURED_VARIABLE (expr);
+         if (TREE_CODE (TREE_TYPE (cap)) == TREE_CODE (TREE_TYPE (expr))
+             && decl_constant_var_p (cap))
+           return RECUR (cap);
+       }
       if (outer_automatic_var_p (expr)
          && decl_constant_var_p (expr))
        {
@@ -146,6 +154,14 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
        {
          /* Try to look through the reference.  */
          tree ref = TREE_OPERAND (expr, 0);
+         if (rvalue_p && is_normal_capture_proxy (ref))
+           {
+             /* Look through capture by reference.  */
+             tree cap = DECL_CAPTURED_VARIABLE (ref);
+             if (TREE_CODE (TREE_TYPE (cap)) != REFERENCE_TYPE
+                 && decl_constant_var_p (cap))
+               return RECUR (cap);
+           }
          tree r = mark_rvalue_use (ref, loc, reject_builtin);
          if (r != ref)
            expr = convert_from_reference (r);
index 7c8b640..2cbad87 100644 (file)
@@ -985,121 +985,6 @@ generic_lambda_fn_p (tree callop)
          && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (callop)));
 }
 
-/* Returns true iff we need to consider default capture for an enclosing
-   generic lambda.  */
-
-bool
-need_generic_capture (void)
-{
-  if (!processing_template_decl)
-    return false;
-
-  tree outer_closure = NULL_TREE;
-  for (tree t = current_class_type; t;
-       t = decl_type_context (TYPE_MAIN_DECL (t)))
-    {
-      tree lam = CLASSTYPE_LAMBDA_EXPR (t);
-      if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE)
-       /* No default capture.  */
-       break;
-      outer_closure = t;
-    }
-
-  if (!outer_closure)
-    /* No lambda.  */
-    return false;
-  else if (dependent_type_p (outer_closure))
-    /* The enclosing context isn't instantiated.  */
-    return false;
-  else
-    return true;
-}
-
-/* A lambda-expression...is said to implicitly capture the entity...if the
-   compound-statement...names the entity in a potentially-evaluated
-   expression where the enclosing full-expression depends on a generic lambda
-   parameter declared within the reaching scope of the lambda-expression.  */
-
-static tree
-dependent_capture_r (tree *tp, int *walk_subtrees, void *data)
-{
-  hash_set<tree> *pset = (hash_set<tree> *)data;
-
-  if (TYPE_P (*tp))
-    *walk_subtrees = 0;
-
-  if (outer_automatic_var_p (*tp))
-    {
-      tree t = process_outer_var_ref (*tp, tf_warning_or_error, /*force*/true);
-      if (t != *tp
-         && TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
-         && TREE_CODE (TREE_TYPE (*tp)) != REFERENCE_TYPE)
-       t = convert_from_reference (t);
-      *tp = t;
-    }
-
-  if (pset->add (*tp))
-    *walk_subtrees = 0;
-
-  switch (TREE_CODE (*tp))
-    {
-      /* Don't walk into unevaluated context or another lambda.  */
-    case SIZEOF_EXPR:
-    case ALIGNOF_EXPR:
-    case TYPEID_EXPR:
-    case NOEXCEPT_EXPR:
-    case LAMBDA_EXPR:
-      *walk_subtrees = 0;
-      break;
-
-      /* Don't walk into statements whose subexpressions we already
-        handled.  */
-    case TRY_BLOCK:
-    case EH_SPEC_BLOCK:
-    case HANDLER:
-    case IF_STMT:
-    case FOR_STMT:
-    case RANGE_FOR_STMT:
-    case WHILE_STMT:
-    case DO_STMT:
-    case SWITCH_STMT:
-    case STATEMENT_LIST:
-    case RETURN_EXPR:
-      *walk_subtrees = 0;
-      break;
-
-    case DECL_EXPR:
-      {
-       tree decl = DECL_EXPR_DECL (*tp);
-       if (VAR_P (decl))
-         {
-           /* walk_tree_1 won't step in here.  */
-           cp_walk_tree (&DECL_INITIAL (decl),
-                         dependent_capture_r, &pset, NULL);
-           *walk_subtrees = 0;
-         }
-      }
-      break;
-
-    default:
-      break;
-    }
-
-  return NULL_TREE;
-}
-
-tree
-do_dependent_capture (tree expr, bool force)
-{
-  if (!need_generic_capture ()
-      || (!force && !instantiation_dependent_expression_p (expr)))
-    return expr;
-
-  hash_set<tree> pset;
-  cp_walk_tree (&expr, dependent_capture_r, &pset, NULL);
-  return expr;
-}
-
 /* If the closure TYPE has a static op(), also add a conversion to function
    pointer.  */
 
index 710333d..4ca5974 100644 (file)
@@ -9500,16 +9500,6 @@ in_template_function (void)
   return ret;
 }
 
-/* Returns true iff we are currently within a template other than a
-   default-capturing generic lambda, so we don't need to worry about semantic
-   processing.  */
-
-bool
-processing_nonlambda_template (void)
-{
-  return processing_template_decl && !need_generic_capture ();
-}
-
 /* Returns true if T depends on any template parameter with level LEVEL.  */
 
 bool
index 664952e..51489d1 100644 (file)
@@ -410,8 +410,6 @@ maybe_cleanup_point_expr (tree expr)
 {
   if (!processing_template_decl && stmts_are_full_exprs_p ())
     expr = fold_build_cleanup_point_expr (TREE_TYPE (expr), expr);
-  else
-    expr = do_dependent_capture (expr);
   return expr;
 }
 
@@ -425,8 +423,6 @@ maybe_cleanup_point_expr_void (tree expr)
 {
   if (!processing_template_decl && stmts_are_full_exprs_p ())
     expr = fold_build_cleanup_point_expr (void_type_node, expr);
-  else
-    expr = do_dependent_capture (expr);
   return expr;
 }
 
@@ -633,8 +629,6 @@ finish_goto_stmt (tree destination)
            = fold_build_cleanup_point_expr (TREE_TYPE (destination),
                                             destination);
        }
-      else
-       destination = do_dependent_capture (destination);
     }
 
   check_goto (destination);
@@ -656,7 +650,7 @@ maybe_convert_cond (tree cond)
 
   /* Wait until we instantiate templates before doing conversion.  */
   if (processing_template_decl)
-    return do_dependent_capture (cond);
+    return cond;
 
   if (warn_sequence_point)
     verify_sequence_points (cond);
@@ -3291,10 +3285,14 @@ outer_automatic_var_p (tree decl)
 }
 
 /* DECL satisfies outer_automatic_var_p.  Possibly complain about it or
-   rewrite it for lambda capture.  */
+   rewrite it for lambda capture.
+
+   If ODR_USE is true, we're being called from mark_use, and we complain about
+   use of constant variables.  If ODR_USE is false, we're being called for the
+   id-expression, and we do lambda capture.  */
 
 tree
-process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
+process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
 {
   if (cp_unevaluated_operand)
     /* It's not a use (3.2) if we're in an unevaluated context.  */
@@ -3315,12 +3313,6 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
   if (parsing_nsdmi ())
     containing_function = NULL_TREE;
 
-  /* Core issue 696: Only an odr-use of an outer automatic variable causes a
-     capture (or error), and a constant variable can decay to a prvalue
-     constant without odr-use.  So don't capture yet.  */
-  if (decl_constant_var_p (decl) && !force_use)
-    return decl;
-
   if (containing_function && LAMBDA_FUNCTION_P (containing_function))
     {
       /* Check whether we've already built a proxy.  */
@@ -3336,7 +3328,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
            return d;
          else
            /* We need to capture an outer proxy.  */
-           return process_outer_var_ref (d, complain, force_use);
+           return process_outer_var_ref (d, complain, odr_use);
        }
     }
 
@@ -3382,12 +3374,19 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
        error ("cannot capture member %qD of anonymous union", decl);
       return error_mark_node;
     }
-  if (context == containing_function)
+  /* Do lambda capture when processing the id-expression, not when
+     odr-using a variable.  */
+  if (!odr_use && context == containing_function)
     {
       decl = add_default_capture (lambda_stack,
                                  /*id=*/DECL_NAME (decl),
                                  initializer);
     }
+  /* Only an odr-use of an outer automatic variable causes an
+     error, and a constant variable can decay to a prvalue
+     constant without odr-use.  So don't complain yet.  */
+  else if (!odr_use && decl_constant_var_p (decl))
+    return decl;
   else if (lambda_expr)
     {
       if (complain & tf_error)
index f9a5f85..cb93cc3 100644 (file)
@@ -9158,7 +9158,7 @@ check_return_expr (tree retval, bool *no_warning)
     dependent:
       /* We should not have changed the return value.  */
       gcc_assert (retval == saved_retval);
-      return do_dependent_capture (retval, /*force*/true);
+      return retval;
     }
 
   /* The fabled Named Return Value optimization, as per [class.copy]/15: