This patch fixes 66735, where we lose cv qualifiers on an explicit
lambda capture by reference:
[&r = <EXPR>] () {...}
The problem is the partitioning between lambda_capture_field_type and
add_capture, where the latter is responsible for adding the
referenceness. That leaves auto deduction clueless that it should
preserve cv qualifiers. Fixed by moving the referenceness into LCFT and
adjusting.
I also refactored the error checking in add_capture, as that seemed a
little repetitious to me -- both paths check for type completeness.
ok?
nathan
--
Nathan Sidwell
2017-01-03 Nathan Sidwell <nat...@acm.org>
cp/
PR c++/66735
* lambda.c (lambda_capture_field_type): Add is_reference parm.
(add_capture): Adjust lambda_capture_field_type call, refactor
error checking.
* pt.c (tsubst): Adjust lambda_capture_field_type call.
* cp-tree.h (lambda_capture_field_type): Update prototype.
testsuite/
PR c++/66735
* g++.dg/cpp1y/pr66735.C: New.
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 244021)
+++ cp/cp-tree.h (working copy)
@@ -6528,7 +6528,7 @@ extern tree finish_trait_expr (enum cp
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: cp/lambda.c
===================================================================
--- cp/lambda.c (revision 244021)
+++ cp/lambda.c (working copy)
@@ -211,14 +211,17 @@ 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);
@@ -229,11 +232,24 @@ lambda_capture_field_type (tree expr, bo
}
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);
+ by_reference_p = false;
+ }
+ type = do_auto_deduction (type, expr, auto_node);
}
else
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
}
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
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: cp/pt.c
===================================================================
--- cp/pt.c (revision 244021)
+++ cp/pt.c (working copy)
@@ -13988,7 +13988,8 @@ tsubst (tree t, tree args, tsubst_flags_
if (DECLTYPE_FOR_LAMBDA_CAPTURE (t))
type = lambda_capture_field_type (type,
- DECLTYPE_FOR_INIT_CAPTURE (t));
+ DECLTYPE_FOR_INIT_CAPTURE (t),
+ /*by_reference_p=*/false);
else if (DECLTYPE_FOR_LAMBDA_PROXY (t))
type = lambda_proxy_type (type);
else
Index: testsuite/g++.dg/cpp1y/pr66735.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr66735.C (revision 0)
+++ testsuite/g++.dg/cpp1y/pr66735.C (working copy)
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++14 } }
+
+// PR c++/66735, lost constness on reference capture
+
+int const x = 5;
+
+void Foo ()
+{
+ auto l = [&rx = x]() {};
+}