From 4bf07f3f5fb4fefa2702eced2291ee5d9cb5ad48 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Wed, 4 Jan 2017 15:23:40 +0000 Subject: [PATCH] re PR c++/66735 ([C++14] lambda init-capture fails for const references) 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 | 11 ++++++++ gcc/cp/cp-tree.h | 5 +++- gcc/cp/lambda.c | 42 ++++++++++++++++++++-------- gcc/cp/pt.c | 3 +- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/g++.dg/cpp1y/pr66735.C | 22 +++++++++++++++ 6 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr66735.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f86dd33c787..71aada7970c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2017-01-04 Nathan Sidwell + + 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 Update copyright years. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f1a5835df83..39f5d790cdc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 715a61df4bc..98fdb740a74 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index fc2175082de..51c3c57b009 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9e7cae41419..65f63605435 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-01-04 Nathan Sidwell + + PR c++/66735 + * g++.dg/cpp1y/pr66735.C: New. + 2017-01-04 Jakub Jelinek 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 index 00000000000..2d81fb880ef --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr66735.C @@ -0,0 +1,22 @@ +// { dg-do compile { target c++14 } } + +// PR c++/66735, lost constness on reference capture + +template void Foo () +{ + T const x = 5; + + auto l = [&rx = x]() {}; + + l (); +} + +void Baz () +{ + int const x = 5; + auto l = [&rx = x]() {}; + + + l (); + Foo (); +} -- 2.30.2