re PR c++/66735 ([C++14] lambda init-capture fails for const references)
authorNathan Sidwell <nathan@acm.org>
Wed, 4 Jan 2017 15:23:40 +0000 (15:23 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Wed, 4 Jan 2017 15:23:40 +0000 (15:23 +0000)
cp/
PR c++/66735
* cp-tree.h (DECLTYPE_FOR_REF_CAPTURE): New.
(lambda_capture_field_type): Update prototype.
* lambda.c (lambda_capture_field_type): Add is_reference parm.
Add referenceness here.
(add_capture): Adjust lambda_capture_field_type call, refactor
error checking.
* pt.c (tsubst): Adjust lambda_capture_field_type call.

testsuite/
PR c++/66735
* g++.dg/cpp1y/pr66735.C: New.

From-SVN: r244056

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/lambda.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/pr66735.C [new file with mode: 0644]

index f86dd33c7877f1cb7d288169a6347eece6d5b4ba..71aada7970c5b5dbe6ca5fa750d8cb56b1d0f89e 100644 (file)
@@ -1,3 +1,14 @@
+2017-01-04  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/66735
+       * cp-tree.h (DECLTYPE_FOR_REF_CAPTURE): New.
+       (lambda_capture_field_type): Update prototype.
+       * lambda.c (lambda_capture_field_type): Add is_reference parm.
+       Add referenceness here.
+       (add_capture): Adjust lambda_capture_field_type call, refactor
+       error checking.
+       * pt.c (tsubst): Adjust lambda_capture_field_type call.
+
 2017-01-01  Jakub Jelinek  <jakub@redhat.com>
 
        Update copyright years.
index f1a5835df83aa1f69e1183f45ae3a78160d12fb6..39f5d790cdc469515e13d2b807a42b79147d11f6 100644 (file)
@@ -181,6 +181,7 @@ operator == (const cp_expr &lhs, tree rhs)
       BIND_EXPR_BODY_BLOCK (in BIND_EXPR)
       DECL_NON_TRIVIALLY_INITIALIZED_P (in VAR_DECL)
       CALL_EXPR_ORDERED_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
+      DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE)
    4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
          CALL_EXPR, or FIELD_DECL).
       IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
@@ -4103,6 +4104,8 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
   TREE_LANG_FLAG_1 (DECLTYPE_TYPE_CHECK (NODE))
 #define DECLTYPE_FOR_LAMBDA_PROXY(NODE) \
   TREE_LANG_FLAG_2 (DECLTYPE_TYPE_CHECK (NODE))
+#define DECLTYPE_FOR_REF_CAPTURE(NODE) \
+  TREE_LANG_FLAG_3 (DECLTYPE_TYPE_CHECK (NODE))
 
 /* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was
    specified in its declaration.  This can also be set for an
@@ -6528,7 +6531,7 @@ extern tree finish_trait_expr                     (enum cp_trait_kind, tree, tree);
 extern tree build_lambda_expr                   (void);
 extern tree build_lambda_object                        (tree);
 extern tree begin_lambda_type                   (tree);
-extern tree lambda_capture_field_type          (tree, bool);
+extern tree lambda_capture_field_type          (tree, bool, bool);
 extern tree lambda_return_type                 (tree);
 extern tree lambda_proxy_type                  (tree);
 extern tree lambda_function                    (tree);
index 715a61df4bc94d1301563563e82b328b0352e020..98fdb740a742f3366d95fe3db5555413586c5359 100644 (file)
@@ -211,29 +211,45 @@ lambda_function (tree lambda)
 }
 
 /* Returns the type to use for the FIELD_DECL corresponding to the
-   capture of EXPR.
-   The caller should add REFERENCE_TYPE for capture by reference.  */
+   capture of EXPR.  EXPLICIT_INIT_P indicates whether this is a
+   C++14 init capture, and BY_REFERENCE_P indicates whether we're
+   capturing by reference.  */
 
 tree
-lambda_capture_field_type (tree expr, bool explicit_init_p)
+lambda_capture_field_type (tree expr, bool explicit_init_p,
+                          bool by_reference_p)
 {
   tree type;
   bool is_this = is_this_parameter (tree_strip_nop_conversions (expr));
+
   if (!is_this && type_dependent_expression_p (expr))
     {
       type = cxx_make_type (DECLTYPE_TYPE);
       DECLTYPE_TYPE_EXPR (type) = expr;
       DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true;
       DECLTYPE_FOR_INIT_CAPTURE (type) = explicit_init_p;
+      DECLTYPE_FOR_REF_CAPTURE (type) = by_reference_p;
       SET_TYPE_STRUCTURAL_EQUALITY (type);
     }
   else if (!is_this && explicit_init_p)
     {
-      type = make_auto ();
-      type = do_auto_deduction (type, expr, type);
+      tree auto_node = make_auto ();
+      
+      type = auto_node;
+      if (by_reference_p)
+       /* Add the reference now, so deduction doesn't lose
+          outermost CV qualifiers of EXPR.  */
+       type = build_reference_type (type);
+      type = do_auto_deduction (type, expr, auto_node);
     }
   else
-    type = non_reference (unlowered_expr_type (expr));
+    {
+      type = non_reference (unlowered_expr_type (expr));
+
+      if (!is_this && by_reference_p)
+       type = build_reference_type (type);
+    }
+
   return type;
 }
 
@@ -504,9 +520,11 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
     }
   else
     {
-      type = lambda_capture_field_type (initializer, explicit_init_p);
+      type = lambda_capture_field_type (initializer, explicit_init_p,
+                                       by_reference_p);
       if (type == error_mark_node)
        return error_mark_node;
+
       if (id == this_identifier && !by_reference_p)
        {
          gcc_assert (POINTER_TYPE_P (type));
@@ -514,17 +532,19 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
          initializer = cp_build_indirect_ref (initializer, RO_NULL,
                                               tf_warning_or_error);
        }
-      if (id != this_identifier && by_reference_p)
+
+      if (dependent_type_p (type))
+       ;
+      else if (id != this_identifier && by_reference_p)
        {
-         type = build_reference_type (type);
-         if (!dependent_type_p (type) && !lvalue_p (initializer))
+         if (!lvalue_p (initializer))
            error ("cannot capture %qE by reference", initializer);
        }
       else
        {
          /* Capture by copy requires a complete type.  */
          type = complete_type (type);
-         if (!dependent_type_p (type) && !COMPLETE_TYPE_P (type))
+         if (!COMPLETE_TYPE_P (type))
            {
              error ("capture by copy of incomplete type %qT", type);
              cxx_incomplete_type_inform (type);
index fc2175082de69bab296300bf057d837160213e5e..51c3c57b009f74758b12073a58d24a4417c2ab4f 100644 (file)
@@ -13988,7 +13988,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
        if (DECLTYPE_FOR_LAMBDA_CAPTURE (t))
          type = lambda_capture_field_type (type,
-                                           DECLTYPE_FOR_INIT_CAPTURE (t));
+                                           DECLTYPE_FOR_INIT_CAPTURE (t),
+                                           DECLTYPE_FOR_REF_CAPTURE (t));
        else if (DECLTYPE_FOR_LAMBDA_PROXY (t))
          type = lambda_proxy_type (type);
        else
index 9e7cae4141956110ce6a1e084acd6fe31a97eb4b..65f636054354c40bb21ce7fd3e7f8f41208781e9 100644 (file)
@@ -1,3 +1,8 @@
+2017-01-04  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/66735
+       * g++.dg/cpp1y/pr66735.C: New.
+
 2017-01-04  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/71563
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr66735.C b/gcc/testsuite/g++.dg/cpp1y/pr66735.C
new file mode 100644 (file)
index 0000000..2d81fb8
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++14 } }
+
+// PR c++/66735, lost constness on reference capture
+
+template <typename T> void Foo ()
+{
+  T const x = 5;
+
+  auto l = [&rx = x]() {};
+
+  l ();
+}
+
+void Baz ()
+{
+  int const x = 5;
+  auto l = [&rx = x]() {};
+
+
+  l ();
+  Foo<int> ();
+}