From 593bcbb8e43c07296325e167ba98bdc52ee3c8de Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 20 Jun 2013 20:28:30 -0400 Subject: [PATCH] re PR c++/55149 (capturing VLA in lambda) PR c++/55149 * decl.c (compute_array_index_type): Don't reject VLAs in SFINAE context if we're in C++14 mode. * tree.c (array_of_runtime_bound_p): Return true for a dependent bound that is not potentually constant. * cp-tree.h (DECL_VLA_CAPTURE_P, REFERENCE_VLA_OK): New. * pt.c (tsubst) [REFERENCE_TYPE]: Check REFERENCE_VLA_OK. * semantics.c (build_lambda_object): Don't rvalue a VLA capture. (build_capture_proxy): Set REFERENCE_VLA_OK. (vla_capture_type): Make it a proper C++ class. (add_capture): Set DECL_VLA_CAPTURE_P. Don't pre-digest the initializer. From-SVN: r200279 --- gcc/cp/ChangeLog | 13 +++++++++++ gcc/cp/cp-tree.h | 12 ++++++++++ gcc/cp/decl.c | 3 ++- gcc/cp/pt.c | 4 +++- gcc/cp/semantics.c | 38 ++++++++++++++++--------------- gcc/cp/tree.c | 4 ++-- gcc/testsuite/g++.dg/cpp1y/vla8.C | 31 +++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/vla8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index adff4e4d36a..7f1168e11ef 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,18 @@ 2013-06-20 Jason Merrill + PR c++/55149 + * decl.c (compute_array_index_type): Don't reject VLAs in SFINAE + context if we're in C++14 mode. + * tree.c (array_of_runtime_bound_p): Return true for a dependent + bound that is not potentually constant. + * cp-tree.h (DECL_VLA_CAPTURE_P, REFERENCE_VLA_OK): New. + * pt.c (tsubst) [REFERENCE_TYPE]: Check REFERENCE_VLA_OK. + * semantics.c (build_lambda_object): Don't rvalue a VLA capture. + (build_capture_proxy): Set REFERENCE_VLA_OK. + (vla_capture_type): Make it a proper C++ class. + (add_capture): Set DECL_VLA_CAPTURE_P. Don't pre-digest the + initializer. + * decl.c (compute_array_index_type): Use size_one_node. * pt.c (process_partial_specialization): Build a TEMPLATE_DECL for diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9fc4aeb1365..cf54acf0d68 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -126,6 +126,7 @@ c-common.h, not after. 5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE) ENUM_FIXED_UNDERLYING_TYPE_P (in ENUMERAL_TYPE) AUTO_IS_DECLTYPE (in TEMPLATE_TYPE_PARM) + REFERENCE_VLA_OK (in REFERENCE_TYPE) 6: TYPE_DEPENDENT_P_VALID Usage of DECL_LANG_FLAG_?: @@ -139,6 +140,7 @@ c-common.h, not after. DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL) FUNCTION_PARAMETER_PACK_P (in PARM_DECL) USING_DECL_TYPENAME_P (in USING_DECL) + DECL_VLA_CAPTURE_P (in FIELD_DECL) 2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL). DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL) 3: DECL_IN_AGGR_P. @@ -2979,6 +2981,11 @@ extern void decl_shadowed_for_var_insert (tree, tree); && (TREE_CODE (TREE_TYPE (TREE_OPERAND ((NODE), 0))) \ == REFERENCE_TYPE)) +/* True if NODE is a REFERENCE_TYPE which is OK to instantiate to be a + reference to VLA type, because it's used for VLA capture. */ +#define REFERENCE_VLA_OK(NODE) \ + (TYPE_LANG_FLAG_5 (REFERENCE_TYPE_CHECK (NODE))) + #define NEW_EXPR_USE_GLOBAL(NODE) \ TREE_LANG_FLAG_0 (NEW_EXPR_CHECK (NODE)) #define DELETE_EXPR_USE_GLOBAL(NODE) \ @@ -3616,6 +3623,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_THIS_STATIC(NODE) \ DECL_LANG_FLAG_6 (VAR_FUNCTION_OR_PARM_DECL_CHECK (NODE)) +/* Nonzero for FIELD_DECL node means that this field is a lambda capture + field for an array of runtime bound. */ +#define DECL_VLA_CAPTURE_P(NODE) \ + DECL_LANG_FLAG_1 (FIELD_DECL_CHECK (NODE)) + /* Nonzero for FIELD_DECL node means that this field is a base class of the parent object, as opposed to a member field. */ #define DECL_FIELD_IS_BASE(NODE) \ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index dad1e102dc6..225f13122ac 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8296,7 +8296,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain) else if (TREE_CONSTANT (size) /* We don't allow VLAs at non-function scopes, or during tentative template substitution. */ - || !at_function_scope_p () || !(complain & tf_error)) + || !at_function_scope_p () + || (cxx_dialect < cxx1y && !(complain & tf_error))) { if (!(complain & tf_error)) return error_mark_node; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 97efdc99b1a..cfabba9e3dd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11575,7 +11575,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) r = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t)); r = cp_build_qualified_type_real (r, cp_type_quals (t), complain); - if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type)) + if (cxx_dialect >= cxx1y + && !(TREE_CODE (t) == REFERENCE_TYPE && REFERENCE_VLA_OK (t)) + && array_of_runtime_bound_p (type)) { if (complain & tf_warning_or_error) pedwarn diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0a700b7a0f6..135ef74bec0 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9033,6 +9033,7 @@ build_lambda_object (tree lambda_expr) if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) val = build_array_copy (val); else if (DECL_NORMAL_CAPTURE_P (field) + && !DECL_VLA_CAPTURE_P (field) && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE) { /* "the entities that are captured by copy are used to @@ -9404,8 +9405,7 @@ build_capture_proxy (tree member) type = lambda_proxy_type (object); - if (TREE_CODE (type) == RECORD_TYPE - && TYPE_NAME (type) == NULL_TREE) + if (DECL_VLA_CAPTURE_P (member)) { /* Rebuild the VLA type from the pointer and maxindex. */ tree field = next_initializable_field (TYPE_FIELDS (type)); @@ -9414,8 +9414,9 @@ build_capture_proxy (tree member) tree max = build_simple_component_ref (object, field); type = build_array_type (TREE_TYPE (TREE_TYPE (ptr)), build_index_type (max)); - object = convert (build_reference_type (type), ptr); - object = convert_from_reference (object); + type = build_reference_type (type); + REFERENCE_VLA_OK (type) = true; + object = convert (type, ptr); } var = build_decl (input_location, VAR_DECL, name, type); @@ -9446,19 +9447,20 @@ static tree vla_capture_type (tree array_type) { static tree ptr_id, max_id; + tree type = xref_tag (record_type, make_anon_name (), ts_current, false); + xref_basetypes (type, NULL_TREE); + type = begin_class_definition (type); if (!ptr_id) { ptr_id = get_identifier ("ptr"); max_id = get_identifier ("max"); } tree ptrtype = build_pointer_type (TREE_TYPE (array_type)); - tree field1 = build_decl (input_location, FIELD_DECL, ptr_id, ptrtype); - tree field2 = build_decl (input_location, FIELD_DECL, max_id, sizetype); - DECL_CHAIN (field2) = field1; - tree type = make_node (RECORD_TYPE); - finish_builtin_struct (type, "__cap", field2, NULL_TREE); - TYPE_NAME (type) = NULL_TREE; - return type; + tree field = build_decl (input_location, FIELD_DECL, ptr_id, ptrtype); + finish_member_declaration (field); + field = build_decl (input_location, FIELD_DECL, max_id, sizetype); + finish_member_declaration (field); + return finish_struct (type, NULL_TREE); } /* From an ID and INITIALIZER, create a capture (by reference if @@ -9471,6 +9473,7 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, { char *buf; tree type, member, name; + bool vla = false; if (TREE_CODE (initializer) == TREE_LIST) initializer = build_x_compound_expr_from_list (initializer, ELK_INIT, @@ -9478,6 +9481,7 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, type = lambda_capture_field_type (initializer, explicit_init_p); if (array_of_runtime_bound_p (type)) { + vla = true; if (!by_reference_p) error ("array of runtime bound cannot be captured by copy, " "only by reference"); @@ -9486,13 +9490,10 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, maximum index, and then reconstruct the VLA for the proxy. */ tree elt = cp_build_array_ref (input_location, initializer, integer_zero_node, tf_warning_or_error); - tree ctype = vla_capture_type (type); - tree ptr_field = next_initializable_field (TYPE_FIELDS (ctype)); - tree nelts_field = next_initializable_field (DECL_CHAIN (ptr_field)); - initializer = build_constructor_va (ctype, 2, - ptr_field, build_address (elt), - nelts_field, array_type_nelts (type)); - type = ctype; + initializer = build_constructor_va (init_list_type_node, 2, + NULL_TREE, build_address (elt), + NULL_TREE, array_type_nelts (type)); + type = vla_capture_type (type); } else if (variably_modified_type_p (type, NULL_TREE)) { @@ -9544,6 +9545,7 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, /* Make member variable. */ member = build_lang_decl (FIELD_DECL, name, type); + DECL_VLA_CAPTURE_P (member) = vla; if (!explicit_init_p) /* Normal captures are invisible to name lookup but uses are replaced diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8524f6cff91..d54d46dbb79 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -884,8 +884,8 @@ array_of_runtime_bound_p (tree t) if (!dom) return false; tree max = TYPE_MAX_VALUE (dom); - return (!value_dependent_expression_p (max) - && !TREE_CONSTANT (max)); + return (!potential_rvalue_constant_expression (max) + || (!value_dependent_expression_p (max) && !TREE_CONSTANT (max))); } /* Return a reference type node referring to TO_TYPE. If RVAL is diff --git a/gcc/testsuite/g++.dg/cpp1y/vla8.C b/gcc/testsuite/g++.dg/cpp1y/vla8.C new file mode 100644 index 00000000000..6e2031af83b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/vla8.C @@ -0,0 +1,31 @@ +// PR c++/55149 +// { dg-options -std=c++1y } + +template + struct SA + { + SA (const int & PA); + int nt; + }; + +template + inline void + test(TB aa) + { + ; + } + +template + inline + SA::SA(const int & PA) + { + float e[nt]; + test([&e](int i, int j){ return e[i] < e[j]; }); + } + +int main() +{ + int d; + SA<2> iso(d); + return 0; +} -- 2.30.2