Mercurial > hg > CbC > CbC_gcc
diff gcc/cp/lambda.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/cp/lambda.c Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/cp/lambda.c Thu Oct 25 07:37:49 2018 +0900 @@ -3,7 +3,7 @@ building RTL. These routines are used both during actual parsing and during the instantiation of template functions. - Copyright (C) 1998-2017 Free Software Foundation, Inc. + Copyright (C) 1998-2018 Free Software Foundation, Inc. This file is part of GCC. @@ -30,7 +30,6 @@ #include "tree-iterator.h" #include "toplev.h" #include "gimplify.h" -#include "cp-cilkplus.h" /* Constructor for a lambda expression. */ @@ -91,7 +90,7 @@ val = build_array_copy (val); else if (DECL_NORMAL_CAPTURE_P (field) && !DECL_VLA_CAPTURE_P (field) - && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE) + && !TYPE_REF_P (TREE_TYPE (field))) { /* "the entities that are captured by copy are used to direct-initialize each corresponding non-static data @@ -201,7 +200,7 @@ if (CLASSTYPE_TEMPLATE_INSTANTIATION (type) && !COMPLETE_OR_OPEN_TYPE_P (type)) return NULL_TREE; - lambda = lookup_member (type, cp_operator_id (CALL_EXPR), + lambda = lookup_member (type, call_op_identifier, /*protect=*/0, /*want_type=*/false, tf_warning_or_error); if (lambda) @@ -245,7 +244,8 @@ { type = non_reference (unlowered_expr_type (expr)); - if (!is_this && by_reference_p) + if (!is_this + && (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE)) type = build_reference_type (type); } @@ -261,6 +261,7 @@ return (VAR_P (decl) && DECL_HAS_VALUE_EXPR_P (decl) && !DECL_ANON_UNION_VAR_P (decl) + && !DECL_DECOMPOSITION_P (decl) && LAMBDA_FUNCTION_P (DECL_CONTEXT (decl))); } @@ -290,6 +291,17 @@ return DECL_NORMAL_CAPTURE_P (val); } +/* Returns true iff DECL is a capture proxy for a normal capture + of a constant variable. */ + +bool +is_constant_capture_proxy (tree decl) +{ + if (is_normal_capture_proxy (decl)) + return decl_constant_var_p (DECL_CAPTURED_VARIABLE (decl)); + return false; +} + /* VAR is a capture proxy created by build_capture_proxy; add it to the current function, which is the operator() for the appropriate lambda. */ @@ -376,7 +388,7 @@ inside the operator(), build a placeholder var for future lookups and debugging. */ -tree +static tree build_capture_proxy (tree member, tree init) { tree var, object, fn, closure, name, lam, type; @@ -399,7 +411,7 @@ type = lambda_proxy_type (object); - if (name == this_identifier && !POINTER_TYPE_P (type)) + if (name == this_identifier && !INDIRECT_TYPE_P (type)) { type = build_pointer_type (type); type = cp_build_qualified_type (type, TYPE_QUAL_CONST); @@ -420,6 +432,8 @@ object = convert (type, ptr); } + complete_type (type); + var = build_decl (input_location, VAR_DECL, name, type); SET_DECL_VALUE_EXPR (var, object); DECL_HAS_VALUE_EXPR_P (var) = 1; @@ -439,10 +453,12 @@ { if (PACK_EXPANSION_P (init)) init = PACK_EXPANSION_PATTERN (init); - if (TREE_CODE (init) == INDIRECT_REF) - init = TREE_OPERAND (init, 0); - STRIP_NOPS (init); } + + if (INDIRECT_REF_P (init)) + init = TREE_OPERAND (init, 0); + STRIP_NOPS (init); + gcc_assert (VAR_P (init) || TREE_CODE (init) == PARM_DECL); while (is_normal_capture_proxy (init)) init = DECL_CAPTURED_VARIABLE (init); @@ -538,13 +554,13 @@ else if (!dependent_type_p (type) && variably_modified_type_p (type, NULL_TREE)) { - error ("capture of variable-size type %qT that is not an N3639 array " + sorry ("capture of variably-modified type %qT that is not an N3639 array " "of runtime bound", type); if (TREE_CODE (type) == ARRAY_TYPE && variably_modified_type_p (TREE_TYPE (type), NULL_TREE)) inform (input_location, "because the array element type %qT has " "variable size", TREE_TYPE (type)); - type = error_mark_node; + return error_mark_node; } else { @@ -555,10 +571,9 @@ if (id == this_identifier && !by_reference_p) { - gcc_assert (POINTER_TYPE_P (type)); + gcc_assert (INDIRECT_TYPE_P (type)); type = TREE_TYPE (type); - initializer = cp_build_indirect_ref (initializer, RO_NULL, - tf_warning_or_error); + initializer = cp_build_fold_indirect_ref (initializer); } if (dependent_type_p (type)) @@ -648,6 +663,7 @@ return build_capture_proxy (member, initializer); /* For explicit captures we haven't started the function yet, so we wait and build the proxy from cp_parser_lambda_body. */ + LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (lambda)) = true; return NULL_TREE; } @@ -679,14 +695,10 @@ add_default_capture (tree lambda_stack, tree id, tree initializer) { bool this_capture_p = (id == this_identifier); - tree var = NULL_TREE; - tree saved_class_type = current_class_type; - tree node; - - for (node = lambda_stack; + for (tree node = lambda_stack; node; node = TREE_CHAIN (node)) { @@ -704,6 +716,19 @@ == CPLD_REFERENCE)), /*explicit_init_p=*/false); initializer = convert_from_reference (var); + + /* Warn about deprecated implicit capture of this via [=]. */ + if (cxx_dialect >= cxx2a + && this_capture_p + && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) == CPLD_COPY + && !in_system_header_at (LAMBDA_EXPR_LOCATION (lambda))) + { + if (warning_at (LAMBDA_EXPR_LOCATION (lambda), OPT_Wdeprecated, + "implicit capture of %qE via %<[=]%> is deprecated " + "in C++20", this_identifier)) + inform (LAMBDA_EXPR_LOCATION (lambda), "add explicit %<this%> or " + "%<*this%> capture"); + } } current_class_type = saved_class_type; @@ -727,9 +752,7 @@ add_capture_p = false; /* Try to default capture 'this' if we can. */ - if (!this_capture - && (!add_capture_p - || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE)) + if (!this_capture) { tree lambda_stack = NULL_TREE; tree init = NULL_TREE; @@ -740,26 +763,41 @@ 3. a non-default capturing lambda function. */ for (tree tlambda = lambda; ;) { - lambda_stack = tree_cons (NULL_TREE, - tlambda, - lambda_stack); + if (add_capture_p + && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE) + /* tlambda won't let us capture 'this'. */ + break; + + if (add_capture_p) + lambda_stack = tree_cons (NULL_TREE, + tlambda, + lambda_stack); + + tree closure = LAMBDA_EXPR_CLOSURE (tlambda); + tree containing_function + = decl_function_context (TYPE_NAME (closure)); - if (LAMBDA_EXPR_EXTRA_SCOPE (tlambda) - && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)) == FIELD_DECL) + tree ex = LAMBDA_EXPR_EXTRA_SCOPE (tlambda); + if (ex && TREE_CODE (ex) == FIELD_DECL) { - /* In an NSDMI, we don't have a function to look up the decl in, - but the fake 'this' pointer that we're using for parsing is - in scope_chain. */ - init = scope_chain->x_current_class_ptr; + /* Lambda in an NSDMI. We don't have a function to look up + 'this' in, but we can find (or rebuild) the fake one from + inject_this_parameter. */ + if (!containing_function && !COMPLETE_TYPE_P (closure)) + /* If we're parsing a lambda in a non-local class, + we can find the fake 'this' in scope_chain. */ + init = scope_chain->x_current_class_ptr; + else + /* Otherwise it's either gone or buried in + function_context_stack, so make another. */ + init = build_this_parm (NULL_TREE, DECL_CONTEXT (ex), + TYPE_UNQUALIFIED); gcc_checking_assert (init && (TREE_TYPE (TREE_TYPE (init)) == current_nonlambda_class_type ())); break; } - tree closure_decl = TYPE_NAME (LAMBDA_EXPR_CLOSURE (tlambda)); - tree containing_function = decl_function_context (closure_decl); - if (containing_function == NULL_TREE) /* We ran out of scopes; there's no 'this' to capture. */ break; @@ -782,10 +820,6 @@ init = LAMBDA_EXPR_THIS_CAPTURE (tlambda); break; } - - if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE) - /* An outer lambda won't let us capture 'this'. */ - break; } if (init) @@ -829,6 +863,20 @@ return result; } +/* Return the innermost LAMBDA_EXPR we're currently in, if any. */ + +tree +current_lambda_expr (void) +{ + tree type = current_class_type; + while (type && !LAMBDA_TYPE_P (type)) + type = decl_type_context (TYPE_NAME (type)); + if (type) + return CLASSTYPE_LAMBDA_EXPR (type); + else + return NULL_TREE; +} + /* Return the current LAMBDA_EXPR, if this is a resolvable dummy object. NULL otherwise.. */ @@ -845,7 +893,7 @@ && current_class_type && LAMBDA_TYPE_P (current_class_type) && lambda_function (current_class_type) - && DERIVED_FROM_P (type, current_nonlambda_class_type ())) + && DERIVED_FROM_P (type, nonlambda_method_basetype())) return CLASSTYPE_LAMBDA_EXPR (current_class_type); return NULL_TREE; @@ -862,8 +910,7 @@ if (tree lam = resolvable_dummy_lambda (object)) if (tree cap = lambda_expr_this_capture (lam, add_capture_p)) if (cap != error_mark_node) - object = build_x_indirect_ref (EXPR_LOCATION (object), cap, - RO_NULL, tf_warning_or_error); + object = build_fold_indirect_ref (cap); return object; } @@ -911,30 +958,37 @@ return fn; } -/* Returns the method basetype of the innermost non-lambda function, or - NULL_TREE if none. */ +/* Returns the method basetype of the innermost non-lambda function, including + a hypothetical constructor if inside an NSDMI, or NULL_TREE if none. */ tree nonlambda_method_basetype (void) { - tree fn, type; if (!current_class_ref) return NULL_TREE; - type = current_class_type; - if (!LAMBDA_TYPE_P (type)) + tree type = current_class_type; + if (!type || !LAMBDA_TYPE_P (type)) return type; - /* Find the nearest enclosing non-lambda function. */ - fn = TYPE_NAME (type); - do - fn = decl_function_context (fn); - while (fn && LAMBDA_FUNCTION_P (fn)); + while (true) + { + tree lam = CLASSTYPE_LAMBDA_EXPR (type); + tree ex = LAMBDA_EXPR_EXTRA_SCOPE (lam); + if (ex && TREE_CODE (ex) == FIELD_DECL) + /* Lambda in an NSDMI. */ + return DECL_CONTEXT (ex); - if (!fn || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) - return NULL_TREE; - - return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); + tree fn = TYPE_CONTEXT (type); + if (!fn || TREE_CODE (fn) != FUNCTION_DECL + || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + /* No enclosing non-lambda method. */ + return NULL_TREE; + if (!LAMBDA_FUNCTION_P (fn)) + /* Found an enclosing non-lambda method. */ + return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); + type = DECL_CONTEXT (fn); + } } /* Like current_scope, but looking through lambdas. */ @@ -987,121 +1041,6 @@ && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (callop))); } -/* Returns true iff we need to consider default capture for an enclosing - generic lambda. */ - -bool -need_generic_capture (void) -{ - if (!processing_template_decl) - return false; - - tree outer_closure = NULL_TREE; - for (tree t = current_class_type; t; - t = decl_type_context (TYPE_MAIN_DECL (t))) - { - tree lam = CLASSTYPE_LAMBDA_EXPR (t); - if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE) - /* No default capture. */ - break; - outer_closure = t; - } - - if (!outer_closure) - /* No lambda. */ - return false; - else if (dependent_type_p (outer_closure)) - /* The enclosing context isn't instantiated. */ - return false; - else - return true; -} - -/* A lambda-expression...is said to implicitly capture the entity...if the - compound-statement...names the entity in a potentially-evaluated - expression where the enclosing full-expression depends on a generic lambda - parameter declared within the reaching scope of the lambda-expression. */ - -static tree -dependent_capture_r (tree *tp, int *walk_subtrees, void *data) -{ - hash_set<tree> *pset = (hash_set<tree> *)data; - - if (TYPE_P (*tp)) - *walk_subtrees = 0; - - if (outer_automatic_var_p (*tp)) - { - tree t = process_outer_var_ref (*tp, tf_warning_or_error, /*force*/true); - if (t != *tp - && TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE - && TREE_CODE (TREE_TYPE (*tp)) != REFERENCE_TYPE) - t = convert_from_reference (t); - *tp = t; - } - - if (pset->add (*tp)) - *walk_subtrees = 0; - - switch (TREE_CODE (*tp)) - { - /* Don't walk into unevaluated context or another lambda. */ - case SIZEOF_EXPR: - case ALIGNOF_EXPR: - case TYPEID_EXPR: - case NOEXCEPT_EXPR: - case LAMBDA_EXPR: - *walk_subtrees = 0; - break; - - /* Don't walk into statements whose subexpressions we already - handled. */ - case TRY_BLOCK: - case EH_SPEC_BLOCK: - case HANDLER: - case IF_STMT: - case FOR_STMT: - case RANGE_FOR_STMT: - case WHILE_STMT: - case DO_STMT: - case SWITCH_STMT: - case STATEMENT_LIST: - case RETURN_EXPR: - *walk_subtrees = 0; - break; - - case DECL_EXPR: - { - tree decl = DECL_EXPR_DECL (*tp); - if (VAR_P (decl)) - { - /* walk_tree_1 won't step in here. */ - cp_walk_tree (&DECL_INITIAL (decl), - dependent_capture_r, &pset, NULL); - *walk_subtrees = 0; - } - } - break; - - default: - break; - } - - return NULL_TREE; -} - -tree -do_dependent_capture (tree expr, bool force) -{ - if (!need_generic_capture () - || (!force && !instantiation_dependent_expression_p (expr))) - return expr; - - hash_set<tree> pset; - cp_walk_tree (&expr, dependent_capture_r, &pset, NULL); - return expr; -} - /* If the closure TYPE has a static op(), also add a conversion to function pointer. */ @@ -1154,8 +1093,7 @@ return expression for a deduced return call op to allow for simple implementation of the conversion operator. */ - tree instance = cp_build_indirect_ref (thisarg, RO_NULL, - tf_warning_or_error); + tree instance = cp_build_fold_indirect_ref (thisarg); tree objfn = build_min (COMPONENT_REF, NULL_TREE, instance, DECL_NAME (callop), NULL_TREE); int nargs = list_length (DECL_ARGUMENTS (callop)) - 1; @@ -1220,7 +1158,6 @@ } } - if (generic_lambda_p) { if (decltype_call) @@ -1255,10 +1192,10 @@ tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST); tree fntype = build_method_type_directly (thistype, rettype, void_list_node); tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype); + SET_DECL_LANGUAGE (convfn, lang_cplusplus); tree fn = convfn; DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); SET_DECL_ALIGN (fn, MINIMUM_METHOD_BOUNDARY); - SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR); grokclassfn (type, fn, NO_SPECIAL); set_linkage_according_to_type (type, fn); rest_of_decl_compilation (fn, namespace_bindings_p (), at_eof); @@ -1286,8 +1223,8 @@ /* Now build up the thunk to be returned. */ - name = get_identifier ("_FUN"); - tree statfn = build_lang_decl (FUNCTION_DECL, name, stattype); + tree statfn = build_lang_decl (FUNCTION_DECL, fun_identifier, stattype); + SET_DECL_LANGUAGE (statfn, lang_cplusplus); fn = statfn; DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); grokclassfn (type, fn, NO_SPECIAL); @@ -1312,11 +1249,9 @@ fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop)); if (flag_sanitize & SANITIZE_NULL) - { - /* Don't UBsan this function; we're deliberately calling op() with a null - object argument. */ - add_no_sanitize_value (fn, SANITIZE_UNDEFINED); - } + /* Don't UBsan this function; we're deliberately calling op() with a null + object argument. */ + add_no_sanitize_value (fn, SANITIZE_UNDEFINED); add_method (type, fn, false); @@ -1453,6 +1388,24 @@ LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++; } +/* This lambda is an instantiation of a lambda in a template default argument + that got no LAMBDA_EXPR_EXTRA_SCOPE, so this shouldn't either. But we do + need to use and increment the global count to avoid collisions. */ + +void +record_null_lambda_scope (tree lambda) +{ + if (vec_safe_is_empty (lambda_scope_stack)) + record_lambda_scope (lambda); + else + { + tree_int *p = lambda_scope_stack->begin(); + LAMBDA_EXPR_EXTRA_SCOPE (lambda) = p->t; + LAMBDA_EXPR_DISCRIMINATOR (lambda) = p->i++; + } + gcc_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == NULL_TREE); +} + void finish_lambda_scope (void) { @@ -1484,11 +1437,120 @@ return body; } +/* Subroutine of prune_lambda_captures: CAP is a node in + LAMBDA_EXPR_CAPTURE_LIST. Return the variable it captures for which we + might optimize away the capture, or NULL_TREE if there is no such + variable. */ + +static tree +var_to_maybe_prune (tree cap) +{ + if (LAMBDA_CAPTURE_EXPLICIT_P (cap)) + /* Don't prune explicit captures. */ + return NULL_TREE; + + tree mem = TREE_PURPOSE (cap); + if (!DECL_P (mem) || !DECL_NORMAL_CAPTURE_P (mem)) + /* Packs and init-captures aren't captures of constant vars. */ + return NULL_TREE; + + tree init = TREE_VALUE (cap); + if (is_normal_capture_proxy (init)) + init = DECL_CAPTURED_VARIABLE (init); + if (decl_constant_var_p (init)) + return init; + + return NULL_TREE; +} + +/* walk_tree helper for prune_lambda_captures: Remember which capture proxies + for constant variables are actually used in the lambda body. + + There will always be a DECL_EXPR for the capture proxy; remember it when we + see it, but replace it with any other use. */ + +static tree +mark_const_cap_r (tree *t, int *walk_subtrees, void *data) +{ + hash_map<tree,tree*> &const_vars = *(hash_map<tree,tree*>*)data; + + tree var = NULL_TREE; + if (TREE_CODE (*t) == DECL_EXPR) + { + tree decl = DECL_EXPR_DECL (*t); + if (is_constant_capture_proxy (decl)) + var = DECL_CAPTURED_VARIABLE (decl); + *walk_subtrees = 0; + } + else if (is_constant_capture_proxy (*t)) + var = DECL_CAPTURED_VARIABLE (*t); + + if (var) + { + tree *&slot = const_vars.get_or_insert (var); + if (!slot || VAR_P (*t)) + slot = t; + } + + return NULL_TREE; +} + +/* We're at the end of processing a lambda; go back and remove any captures of + constant variables for which we've folded away all uses. */ + +static void +prune_lambda_captures (tree body) +{ + tree lam = current_lambda_expr (); + if (!LAMBDA_EXPR_CAPTURE_OPTIMIZED (lam)) + /* No uses were optimized away. */ + return; + if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE) + /* No default captures, and we don't prune explicit captures. */ + return; + + hash_map<tree,tree*> const_vars; + + cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars); + + tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam)); + for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; ) + { + tree cap = *capp; + if (tree var = var_to_maybe_prune (cap)) + { + tree **use = const_vars.get (var); + if (use && TREE_CODE (**use) == DECL_EXPR) + { + /* All uses of this capture were folded away, leaving only the + proxy declaration. */ + + /* Splice the capture out of LAMBDA_EXPR_CAPTURE_LIST. */ + *capp = TREE_CHAIN (cap); + + /* And out of TYPE_FIELDS. */ + tree field = TREE_PURPOSE (cap); + while (*fieldp != field) + fieldp = &DECL_CHAIN (*fieldp); + *fieldp = DECL_CHAIN (*fieldp); + + /* And remove the capture proxy declaration. */ + **use = void_node; + continue; + } + } + + capp = &TREE_CHAIN (cap); + } +} + void finish_lambda_function (tree body) { finish_function_body (body); + prune_lambda_captures (body); + /* Finish the function and generate code for it if necessary. */ tree fn = finish_function (/*inline_p=*/true);