aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/pt.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/pt.cc')
-rw-r--r--gcc/cp/pt.cc285
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. */