diff options
Diffstat (limited to 'gcc/cp/pt.cc')
-rw-r--r-- | gcc/cp/pt.cc | 285 |
1 files changed, 251 insertions, 34 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index be9af50..fc2b31f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -12151,36 +12151,159 @@ tsubst_attribute (tree t, tree *decl_p, tree args, ++cp_unevaluated_operand; tree varid = tsubst_expr (TREE_PURPOSE (val), args, complain, in_decl); --cp_unevaluated_operand; - tree chain = TREE_CHAIN (val); + tree chain = copy_list (TREE_CHAIN (val)); location_t match_loc = cp_expr_loc_or_input_loc (TREE_PURPOSE (chain)); tree ctx = copy_list (TREE_VALUE (val)); - tree append_args_list = TREE_CHAIN (TREE_CHAIN (chain)); - if (append_args_list - && TREE_VALUE (append_args_list) - && TREE_CHAIN (TREE_VALUE (append_args_list))) - { - append_args_list = TREE_VALUE (append_args_list); - append_args_list = TREE_VALUE (TREE_CHAIN (append_args_list)); - for (; append_args_list; - append_args_list = TREE_CHAIN (append_args_list)) - { - tree pref_list = TREE_VALUE (append_args_list); - if (pref_list == NULL_TREE || TREE_CODE (pref_list) != TREE_LIST) + /* These asserts may seem strange but the layout of this attribute is + really difficult to grok and remember. They should be left in until + we refactor the layout of the stored nodes. */ + gcc_assert (TREE_CHAIN (chain)); + /* These nodes were copied by copy_list above, don't copy it again. */ + tree omp_variant_clauses = TREE_CHAIN (TREE_CHAIN (chain)); + gcc_checking_assert (!omp_variant_clauses + || TREE_PURPOSE (omp_variant_clauses) + == get_identifier ("omp variant clauses temp")); + tree adjust_args_idxs = NULL_TREE; + if (omp_variant_clauses) + { + gcc_assert (TREE_VALUE (omp_variant_clauses)); + adjust_args_idxs = copy_node (TREE_VALUE (omp_variant_clauses)); + gcc_assert (adjust_args_idxs); + gcc_checking_assert (TREE_PURPOSE (adjust_args_idxs) + == get_identifier ("omp adjust args idxs")); + /* copy_node doesn't copy the CHAIN. */ + if (adjust_args_idxs) + { + if (TREE_CHAIN (TREE_VALUE (omp_variant_clauses))) + TREE_CHAIN (adjust_args_idxs) + = copy_node (TREE_CHAIN (TREE_VALUE (omp_variant_clauses))); + TREE_VALUE (omp_variant_clauses) = adjust_args_idxs; + } + } + if (adjust_args_idxs + && TREE_CHAIN (adjust_args_idxs)) + { + /* This only needs to be copied if node PURPOSE is NULL_TREE, or if + there is a dependent prefer type node. It's hard to determine + this though, so don't try to handle it conditionally for now. */ + tree append_args_node = TREE_CHAIN (adjust_args_idxs); + /* PURPOSE holds the count of real args, it doesn't need to be copied + because it will just be replaced if it needs to be changed. + VALUE holds the list of append_args. */ + append_args_node = copy_node (append_args_node); + /* It's too hard to figure out if we have anything dependent, + unconditionally copy this list. */ + tree append_args_head = copy_list (TREE_VALUE (append_args_node)); + for (tree n = append_args_head; n != NULL_TREE; n = TREE_CHAIN (n)) + { + tree pref_list = TREE_VALUE (n); + if (pref_list == NULL_TREE + || TREE_CODE (pref_list) != TREE_LIST) + /* Not a pref_list. */ continue; - tree fr_list = TREE_VALUE (pref_list); + tree fr_list = copy_node (TREE_VALUE (pref_list)); int len = TREE_VEC_LENGTH (fr_list); + /* Track if substitution occurs. + I'm not really sure that this even works the way I hope it + does, really I'm pretty sure tsubst_expr will basically always + return some sort of copy. The proper solution is probably + marking the list as dependent during parsing. */ + bool substituted = false; for (int i = 0; i < len; i++) { - tree *fr_expr = &TREE_VEC_ELT (fr_list, i); - /* Preserve NOP_EXPR to have a location. */ - if (*fr_expr && TREE_CODE (*fr_expr) == NOP_EXPR) - TREE_OPERAND (*fr_expr, 0) - = tsubst_expr (TREE_OPERAND (*fr_expr, 0), args, complain, - in_decl); - else - *fr_expr = tsubst_expr (*fr_expr, args, complain, in_decl); + tree elt = TREE_VEC_ELT (fr_list, i); + if (!elt) + continue; + tree expr = TREE_CODE (elt) == NOP_EXPR + ? TREE_OPERAND (elt, 0) + : elt; + tree new_expr = tsubst_expr (expr, args, complain, in_decl); + if (new_expr != expr) + { + substituted = true; + if (TREE_CODE (elt) == NOP_EXPR) + { + tree copied_nop = copy_node (elt); + TREE_OPERAND (copied_nop, 0) = new_expr; + TREE_VEC_ELT (fr_list, i) = copied_nop; + } + else + TREE_VEC_ELT (fr_list, i) = new_expr; + } + } + if (substituted) + { + pref_list = copy_node (pref_list); + TREE_VALUE (pref_list) = fr_list; + /* This node gets mutated in cp_finish_omp_init_prefer_type + if fr_list is dependent, it needs to be copied. */ + TREE_PURPOSE (pref_list) + = copy_node (TREE_PURPOSE (pref_list)); + TREE_VALUE (n) = pref_list; } } + TREE_VALUE (append_args_node) = append_args_head; + TREE_CHAIN (adjust_args_idxs) = append_args_node; + } + gcc_assert (TREE_CHAIN (chain)); + + tree adjust_args_list = adjust_args_idxs + ? TREE_VALUE (adjust_args_idxs) + : NULL_TREE; + + if (adjust_args_list && ATTR_IS_DEPENDENT (adjust_args_list)) + { + tree copied = copy_list (adjust_args_list); + /* Substitute numeric ranges, we also need to copy ranges with + relative bounds, in theory it's possible for them to get expanded + while one bound is still dependent. */ + for (tree n = copied; n; n = TREE_CHAIN (n)) + { + tree item = TREE_VALUE (n); + const tree_code code = TREE_CODE (TREE_VALUE (item)); + gcc_assert (code == PARM_DECL + || code == INTEGER_CST + || code == TREE_LIST); + if (code == TREE_LIST) + { + tree range = TREE_VALUE (item); + gcc_assert (TREE_CODE (range) == TREE_LIST); + auto tsubst_bound = [&] (tree bound) + { + gcc_assert (bound != NULL_TREE); + if (bound == error_mark_node + || !ATTR_IS_DEPENDENT (bound)) + { + /* As above, copy the bound if it is relative. */ + if (TREE_PURPOSE (bound) != NULL_TREE) + return copy_node (bound); + else + return bound; + } + tree expr = TREE_VALUE (bound); + tree subst_expr + = tsubst_expr (expr, args, complain, in_decl); + gcc_assert (subst_expr != expr); + tree new_bound = build_tree_list (TREE_PURPOSE (bound), + subst_expr); + return new_bound; + }; + tree lb = tsubst_bound (TREE_PURPOSE (range)); + tree ub = tsubst_bound (TREE_VALUE (range)); + /* Only build a new range if substitution occured. */ + if (lb != TREE_PURPOSE (range) + || ub != TREE_VALUE (range)) + { + tree new_range = build_tree_list (lb, ub); + /* We don't need to copy the purpose, it just holds + a location. */ + TREE_VALUE (n) = build_tree_list (TREE_PURPOSE (item), + new_range); + } + } + } + TREE_VALUE (adjust_args_idxs) = copied; + TREE_VALUE (omp_variant_clauses) = adjust_args_idxs; } for (tree tss = ctx; tss; tss = TREE_CHAIN (tss)) { @@ -15904,7 +16027,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, = remove_attribute ("visibility", DECL_ATTRIBUTES (r)); } determine_visibility (r); - if ((!local_p || TREE_STATIC (t)) && DECL_SECTION_NAME (t)) + if ((!local_p || TREE_STATIC (t)) + && !(flag_openmp && DECL_LANG_SPECIFIC (t) + && DECL_OMP_DECLARE_MAPPER_P (t)) + && DECL_SECTION_NAME (t)) set_decl_section_name (r, t); } @@ -15956,6 +16082,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, SET_TYPE_STRUCTURAL_EQUALITY (TREE_TYPE (r)); } + if (flag_openmp + && VAR_P (t) + && DECL_LANG_SPECIFIC (t) + && DECL_OMP_DECLARE_MAPPER_P (t) + && strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL) + DECL_NAME (r) = omp_mapper_id (DECL_NAME (t), TREE_TYPE (r)); + layout_decl (r, 0); } break; @@ -17252,6 +17385,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) member access. */ id = false; type = finish_decltype_type (type, id, complain); + + if (DECLTYPE_FOR_OMP_ARRAYSHAPE_CAST (t) + && TYPE_REF_P (type)) + type = TREE_TYPE (type); } return cp_build_qualified_type (type, cp_type_quals (t) @@ -17847,9 +17984,7 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, return decl; /* Handle OpenMP iterators. */ - if (TREE_CODE (decl) == TREE_LIST - && TREE_PURPOSE (decl) - && TREE_CODE (TREE_PURPOSE (decl)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (decl)) { tree ret; if (iterator_cache[0] == TREE_PURPOSE (decl)) @@ -17911,14 +18046,17 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, = tsubst_stmt (TREE_OPERAND (decl, 1), args, complain, in_decl); tree length = tsubst_stmt (TREE_OPERAND (decl, 2), args, complain, in_decl); + tree stride = tsubst_stmt (TREE_OPERAND (decl, 3), args, complain, + in_decl); tree base = tsubst_omp_clause_decl (TREE_OPERAND (decl, 0), args, complain, in_decl, NULL); if (TREE_OPERAND (decl, 0) == base && TREE_OPERAND (decl, 1) == low_bound - && TREE_OPERAND (decl, 2) == length) + && TREE_OPERAND (decl, 2) == length + && TREE_OPERAND (decl, 3) == stride) return decl; - return build3 (OMP_ARRAY_SECTION, TREE_TYPE (base), base, low_bound, - length); + return build4 (OMP_ARRAY_SECTION, TREE_TYPE (base), base, low_bound, + length, stride); } tree ret = tsubst_stmt (decl, args, complain, in_decl); /* Undo convert_from_reference tsubst_expr could have called. */ @@ -18220,8 +18358,10 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, } new_clauses = nreverse (new_clauses); - if (ort != C_ORT_OMP_DECLARE_SIMD) + if (ort != C_ORT_OMP_DECLARE_SIMD && ort != C_ORT_OMP_DECLARE_MAPPER) { + if (ort & C_ORT_OMP) + new_clauses = c_omp_instantiate_mappers (new_clauses, ort); new_clauses = finish_omp_clauses (new_clauses, ort); if (linear_no_step) for (nc = new_clauses; nc; nc = OMP_CLAUSE_CHAIN (nc)) @@ -19668,6 +19808,31 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) OMP_DEPOBJ_CLAUSES (t)); break; + case OMP_ALLOCATE: + { + gcc_assert (flag_openmp); + + tree alloc + = tsubst_expr (OMP_ALLOCATE_ALLOCATOR (t), args, complain, in_decl); + tree align + = tsubst_expr (OMP_ALLOCATE_ALIGN (t), args, complain, in_decl); + tree vars = copy_list (OMP_ALLOCATE_VARS (t)); + for (tree node = vars; node != NULL_TREE; node = TREE_CHAIN (node)) + { + if (TREE_PURPOSE (node) == error_mark_node) + continue; + /* The var was already substituted, just look up the new node. */ + tree var = lookup_name (DECL_NAME (TREE_PURPOSE (node)), + LOOK_where::BLOCK, LOOK_want::NORMAL); + /* There's a weird edge case where lookup_name returns NULL_TREE, + but only for incorrect code. Even so, handle NULL_TREE to avoid + segfaulting in those cases. */ + TREE_PURPOSE (node) = var ? var : error_mark_node; + /* Don't copy the attr here, let finish_omp_allocate handle it. */ + } + finish_omp_allocate (OMP_ALLOCATE_LOCATION (t), vars, alloc, align); + break; + } case OACC_DATA: case OMP_TARGET_DATA: case OMP_TARGET: @@ -19736,7 +19901,9 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) case OMP_TARGET_UPDATE: case OMP_TARGET_ENTER_DATA: case OMP_TARGET_EXIT_DATA: - tmp = tsubst_omp_clauses (OMP_STANDALONE_CLAUSES (t), C_ORT_OMP, args, + tmp = tsubst_omp_clauses (OMP_STANDALONE_CLAUSES (t), + (TREE_CODE (t) == OMP_TARGET_EXIT_DATA + ? C_ORT_OMP_EXIT_DATA : C_ORT_OMP), args, complain, in_decl); t = copy_node (t); OMP_STANDALONE_CLAUSES (t) = tmp; @@ -19941,6 +20108,22 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) break; } + case OMP_DECLARE_MAPPER: + { + t = copy_node (t); + + tree decl = OMP_DECLARE_MAPPER_DECL (t); + decl = tsubst (decl, args, complain, in_decl); + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree clauses = OMP_DECLARE_MAPPER_CLAUSES (t); + clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_MAPPER, args, + complain, in_decl); + TREE_TYPE (t) = type; + OMP_DECLARE_MAPPER_DECL (t) = decl; + OMP_DECLARE_MAPPER_CLAUSES (t) = clauses; + RETURN (t); + } + case TRANSACTION_EXPR: { int flags = 0; @@ -20797,6 +20980,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) RETURN (cp_build_bit_cast (EXPR_LOCATION (t), type, op0, complain)); } + case OMP_ARRAYSHAPE_CAST_EXPR: + { + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree op0 = RECUR (TREE_OPERAND (t, 0)); + RETURN (cp_build_omp_arrayshape_cast (EXPR_LOCATION (t), type, op0, + complain)); + } + case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0), @@ -20982,7 +21173,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) case OMP_ARRAY_SECTION: { tree op0 = RECUR (TREE_OPERAND (t, 0)); - tree op1 = NULL_TREE, op2 = NULL_TREE; + tree op1 = NULL_TREE, op2 = NULL_TREE, op3 = NULL_TREE; if (op0 == error_mark_node) RETURN (error_mark_node); if (TREE_OPERAND (t, 1)) @@ -20997,7 +21188,31 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (op2 == error_mark_node) RETURN (error_mark_node); } - RETURN (build_omp_array_section (EXPR_LOCATION (t), op0, op1, op2)); + if (TREE_OPERAND (t, 3)) + { + op3 = RECUR (TREE_OPERAND (t, 3)); + if (op3 == error_mark_node) + RETURN (error_mark_node); + } + RETURN (build_omp_array_section (EXPR_LOCATION (t), op0, op1, op2, + op3)); + } + + case OMP_DECLARE_MAPPER: + { + t = copy_node (t); + + tree decl = OMP_DECLARE_MAPPER_DECL (t); + DECL_OMP_DECLARE_MAPPER_P (decl) = 1; + decl = tsubst (decl, args, complain, in_decl); + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree clauses = OMP_DECLARE_MAPPER_CLAUSES (t); + clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_MAPPER, args, + complain, in_decl); + TREE_TYPE (t) = type; + OMP_DECLARE_MAPPER_DECL (t) = decl; + OMP_DECLARE_MAPPER_CLAUSES (t) = clauses; + RETURN (t); } case SIZEOF_EXPR: @@ -27967,7 +28182,9 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) || (external_p && VAR_P (d)) /* Handle here a deleted function too, avoid generating its body (c++/61080). */ - || deleted_p) + || deleted_p + /* We need the initializer for an OpenMP declare mapper. */ + || (VAR_P (d) && DECL_LANG_SPECIFIC (d) && DECL_OMP_DECLARE_MAPPER_P (d))) { /* The definition of the static data member is now required so we must substitute the initializer. */ |