diff options
Diffstat (limited to 'gcc/cp/semantics.c')
-rw-r--r-- | gcc/cp/semantics.c | 167 |
1 files changed, 133 insertions, 34 deletions
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8199af0e693..e270a734fa0 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); static tree capture_decltype (tree); +static tree thisify_lambda_field (tree); /* Deferred Access Checking Overview @@ -1447,14 +1448,13 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) return error_mark_node; } - /* If decl is a field, object has a lambda type, and decl is not a member - of that type, then we have a reference to a member of 'this' from a + /* If decl is a non-capture field and object has a lambda type, + then we have a reference to a member of 'this' from a lambda inside a non-static member function, and we must get to decl through the 'this' capture. If decl is not a member of that object, either, then its access will still fail later. */ if (LAMBDA_TYPE_P (TREE_TYPE (object)) - && !same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (decl), - TREE_TYPE (object))) + && !LAMBDA_TYPE_P (DECL_CONTEXT (decl))) object = cp_build_indirect_ref (lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (object))), @@ -2063,17 +2063,13 @@ finish_this_expr (void) { tree result; - if (current_class_ptr) - { - tree type = TREE_TYPE (current_class_ref); - - /* In a lambda expression, 'this' refers to the captured 'this'. */ - if (LAMBDA_TYPE_P (type)) - result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type)); - else - result = current_class_ptr; - - } + /* In a lambda expression, 'this' refers to the captured 'this'. */ + if (current_function_decl + && LAMBDA_FUNCTION_P (current_function_decl)) + result = (lambda_expr_this_capture + (CLASSTYPE_LAMBDA_EXPR (current_class_type))); + else if (current_class_ptr) + result = current_class_ptr; else if (current_function_decl && DECL_STATIC_FUNCTION_P (current_function_decl)) { @@ -2648,6 +2644,18 @@ outer_automatic_var_p (tree decl) && DECL_CONTEXT (decl) != current_function_decl); } +/* Returns true iff DECL is a capture field from a lambda that is not our + immediate context. */ + +static bool +outer_lambda_capture_p (tree decl) +{ + return (TREE_CODE (decl) == FIELD_DECL + && LAMBDA_TYPE_P (DECL_CONTEXT (decl)) + && (!current_class_type + || !DERIVED_FROM_P (DECL_CONTEXT (decl), current_class_type))); +} + /* ID_EXPRESSION is a representation of parsed, but unprocessed, id-expression. (See cp_parser_id_expression for details.) SCOPE, if non-NULL, is the type or namespace used to explicitly qualify @@ -2751,7 +2759,8 @@ finish_id_expression (tree id_expression, /* Disallow uses of local variables from containing functions, except within lambda-expressions. */ - if (outer_automatic_var_p (decl) + if ((outer_automatic_var_p (decl) + || outer_lambda_capture_p (decl)) /* It's not a use (3.2) if we're in an unevaluated context. */ && !cp_unevaluated_operand) { @@ -2759,6 +2768,7 @@ finish_id_expression (tree id_expression, tree containing_function = current_function_decl; tree lambda_stack = NULL_TREE; tree lambda_expr = NULL_TREE; + tree initializer = decl; /* Core issue 696: "[At the July 2009 meeting] the CWG expressed support for an approach in which a reference to a local @@ -2770,6 +2780,13 @@ finish_id_expression (tree id_expression, if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)) return integral_constant_value (decl); + if (TYPE_P (context)) + { + /* Implicit capture of an explicit capture. */ + context = lambda_function (context); + initializer = thisify_lambda_field (decl); + } + /* If we are in a lambda function, we can move out until we hit 1. the context, 2. a non-lambda function, or @@ -2796,7 +2813,7 @@ finish_id_expression (tree id_expression, { decl = add_default_capture (lambda_stack, /*id=*/DECL_NAME (decl), - /*initializer=*/decl); + initializer); } else if (lambda_expr) { @@ -4741,6 +4758,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) /* The type denoted by decltype(e) is defined as follows: */ + expr = resolve_nondeduced_context (expr); if (id_expression_or_member_access_p) { /* If e is an id-expression or a class member access (5.2.5 @@ -4766,9 +4784,13 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) /* See through BASELINK nodes to the underlying functions. */ expr = BASELINK_FUNCTIONS (expr); + if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == OVERLOAD) { - if (OVL_CHAIN (expr)) + if (OVL_CHAIN (expr) + || TREE_CODE (OVL_FUNCTION (expr)) == TEMPLATE_DECL) { error ("%qE refers to a set of overloaded functions", orig_expr); return error_mark_node; @@ -5328,6 +5350,20 @@ build_lambda_object (tree lambda_expr) do some magic to make it work here. */ if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) val = build_array_copy (val); + else if (DECL_NORMAL_CAPTURE_P (field) + && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE) + { + /* "the entities that are captured by copy are used to + direct-initialize each corresponding non-static data + member of the resulting closure object." + + There's normally no way to express direct-initialization + from an element of a CONSTRUCTOR, so we build up a special + TARGET_EXPR to bypass the usual copy-initialization. */ + val = force_rvalue (val); + if (TREE_CODE (val) == TARGET_EXPR) + TARGET_EXPR_DIRECT_INIT_P (val) = true; + } CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val); } @@ -5545,7 +5581,8 @@ capture_decltype (tree decl) and return it. */ tree -add_capture (tree lambda, tree id, tree initializer, bool by_reference_p) +add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, + bool explicit_init_p) { tree type; tree member; @@ -5560,6 +5597,13 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p) /* Make member variable. */ member = build_lang_decl (FIELD_DECL, id, type); + if (!explicit_init_p) + /* Normal captures are invisible to name lookup but uses are replaced + with references to the capture field; we implement this by only + really making them invisible in unevaluated context; see + qualify_lookup. For now, let's make explicitly initialized captures + always visible. */ + DECL_NORMAL_CAPTURE_P (member) = true; /* Add it to the appropriate closure class. */ finish_member_declaration (member); @@ -5577,6 +5621,21 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p) return member; } +/* Given a FIELD_DECL decl belonging to a closure type, return a + COMPONENT_REF of it relative to the 'this' parameter of the op() for + that type. */ + +static tree +thisify_lambda_field (tree decl) +{ + tree context = lambda_function (DECL_CONTEXT (decl)); + tree object = cp_build_indirect_ref (DECL_ARGUMENTS (context), + /*errorstring*/"", + tf_warning_or_error); + return finish_non_static_data_member (decl, object, + /*qualifying_scope*/NULL_TREE); +} + /* Similar to add_capture, except this works on a stack of nested lambdas. BY_REFERENCE_P in this case is derived from the default capture mode. Returns the capture for the lambda at the bottom of the stack. */ @@ -5605,17 +5664,9 @@ add_default_capture (tree lambda_stack, tree id, tree initializer) /*by_reference_p=*/ (!this_capture_p && (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) - == CPLD_REFERENCE))); - - { - /* Have to get the old value of current_class_ref. */ - tree object = cp_build_indirect_ref (DECL_ARGUMENTS - (lambda_function (lambda)), - /*errorstring=*/"", - /*complain=*/tf_warning_or_error); - initializer = finish_non_static_data_member - (member, object, /*qualifying_scope=*/NULL_TREE); - } + == CPLD_REFERENCE)), + /*explicit_init_p=*/false); + initializer = thisify_lambda_field (member); } current_class_type = saved_class_type; @@ -5654,10 +5705,7 @@ lambda_expr_this_capture (tree lambda) { /* An outer lambda has already captured 'this'. */ tree cap = LAMBDA_EXPR_THIS_CAPTURE (lambda); - tree lthis - = cp_build_indirect_ref (DECL_ARGUMENTS (containing_function), - "", tf_warning_or_error); - init = finish_non_static_data_member (cap, lthis, NULL_TREE); + init = thisify_lambda_field (cap); break; } @@ -5707,4 +5755,55 @@ lambda_expr_this_capture (tree lambda) return result; } +/* If the closure TYPE has a static op(), also add a conversion to function + pointer. */ + +void +maybe_add_lambda_conv_op (tree type) +{ + bool nested = (current_function_decl != NULL_TREE); + tree callop = lambda_function (type); + tree rettype, name, fntype, fn, body, compound_stmt; + + if (!DECL_STATIC_FUNCTION_P (callop)) + return; + + rettype = build_pointer_type (TREE_TYPE (callop)); + name = mangle_conv_op_name_for_type (rettype); + fntype = build_function_type (rettype, void_list_node); + fn = build_lang_decl (FUNCTION_DECL, name, fntype); + DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); + + if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn + && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) + DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; + + SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR); + grokclassfn (type, fn, NO_SPECIAL); + set_linkage_according_to_type (type, fn); + rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); + DECL_IN_AGGR_P (fn) = 1; + DECL_ARTIFICIAL (fn) = 1; + DECL_NOT_REALLY_EXTERN (fn) = 1; + DECL_DECLARED_INLINE_P (fn) = 1; + DECL_STATIC_FUNCTION_P (fn) = 1; + + add_method (type, fn, NULL_TREE); + + if (nested) + push_function_context (); + start_preparsed_function (fn, NULL_TREE, + SF_PRE_PARSED | SF_INCLASS_INLINE); + body = begin_function_body (); + compound_stmt = begin_compound_stmt (0); + + finish_return_stmt (decay_conversion (callop)); + + finish_compound_stmt (compound_stmt); + finish_function_body (body); + + expand_or_defer_fn (finish_function (2)); + if (nested) + pop_function_context (); +} #include "gt-cp-semantics.h" |