aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/decl.cc')
-rw-r--r--gcc/cp/decl.cc410
1 files changed, 294 insertions, 116 deletions
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 4e97093..9db508f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -7871,6 +7871,12 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
}
else if (!init && DECL_REALLY_EXTERN (decl))
;
+ else if (flag_openmp
+ && VAR_P (decl)
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_OMP_DECLARE_MAPPER_P (decl)
+ && TREE_CODE (init) == OMP_DECLARE_MAPPER)
+ return NULL_TREE;
else if (init || type_build_ctor_call (type)
|| TYPE_REF_P (type))
{
@@ -8165,6 +8171,17 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec)
&& !var_in_maybe_constexpr_fn (decl))
|| DECL_VIRTUAL_P (decl));
+ /* See testsuite/g++.dg/gomp/allocate-15.C
+ This is a band-aid to fix an ICE with implicit constexpr functions, it
+ does not fix the non-template case in allocate-15.C though. We currently
+ sorry on all cases where this is relevant so it shouldn't be necessary.
+ The above needs to be changed but it makes more sense to defer it to
+ another patch as it relates to some other bugs too and has slightly wider
+ implications than just within the scope of OpenMP. */
+ if (!defer_p && flag_openmp
+ && lookup_attribute ("omp allocate", DECL_ATTRIBUTES (decl)))
+ defer_p = 1;
+
/* Defer template instantiations. */
if (DECL_LANG_SPECIFIC (decl)
&& DECL_IMPLICIT_INSTANTIATION (decl))
@@ -8465,15 +8482,29 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
parm = DECL_CHAIN (parm);
for (; parm; parm = DECL_CHAIN (parm))
vec_safe_push (args, forward_parm (parm));
-
+ /* The layout of these nodes are a mess, this function is generally very hard
+ to reason about because of it, this needs to be fixed. */
+ const tree adjust_args_idxs = [&] ()
+ {
+ const tree omp_variant_clauses_temp = TREE_CHAIN (TREE_CHAIN (chain));
+ gcc_checking_assert (!omp_variant_clauses_temp
+ || TREE_PURPOSE (omp_variant_clauses_temp)
+ == get_identifier ("omp variant clauses temp"));
+ const tree adjust_args_idxs = omp_variant_clauses_temp
+ ? TREE_VALUE (omp_variant_clauses_temp)
+ : NULL_TREE;
+ gcc_checking_assert (!adjust_args_idxs
+ || TREE_PURPOSE (adjust_args_idxs)
+ == get_identifier ("omp adjust args idxs"));
+ return adjust_args_idxs;
+ } (); /* IILE. */
unsigned nappend_args = 0;
- tree append_args_list = TREE_CHAIN (TREE_CHAIN (chain));
+ const tree append_args_list
+ = adjust_args_idxs && TREE_CHAIN (adjust_args_idxs)
+ ? TREE_VALUE (TREE_CHAIN (adjust_args_idxs))
+ : NULL_TREE;;
if (append_args_list)
{
- append_args_list = TREE_VALUE (append_args_list);
- append_args_list = (append_args_list && TREE_CHAIN (append_args_list)
- ? TREE_VALUE (TREE_CHAIN (append_args_list))
- : NULL_TREE);
for (tree t = append_args_list; t; t = TREE_CHAIN (t))
nappend_args++;
if (nappend_args)
@@ -8504,6 +8535,55 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
vec_safe_push (args, build_stub_object (TREE_TYPE (type)));
}
}
+ /* We assume the this parameter is included in the declaration, if it isn't
+ our parm count will be wrong. */
+ gcc_assert (!DECL_IOBJ_MEMBER_FUNCTION_P (decl)
+ || is_this_parameter (DECL_ARGUMENTS (decl)));
+ struct bundled_parm_info
+ {
+ int count;
+ bool unexpanded_pack;
+ bool variadic;
+ };
+ const bundled_parm_info parm_info = [&] ()
+ {
+ bool pack = false;
+ int cnt = 0;
+ tree parm_t = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ while (parm_t && parm_t != void_list_node)
+ {
+ /* We can't tell how many parameters there are until all parameter
+ packs have been expanded. */
+ if (PACK_EXPANSION_P (TREE_VALUE (parm_t)))
+ pack = true;
+ parm_t = TREE_CHAIN (parm_t);
+ ++cnt;
+ }
+ return bundled_parm_info{!pack ? cnt : 0, pack, parm_t == NULL_TREE};
+ } (); /* IILE. */
+ tree adjust_args_list = adjust_args_idxs ? TREE_VALUE (adjust_args_idxs)
+ : NULL_TREE;
+ if (adjust_args_list)
+ {
+ /* We currently treat a parm count of 0 as variadic. */
+ adjust_args_list
+ = finish_omp_parm_list (adjust_args_list,
+ decl,
+ parm_info.variadic ? 0 : parm_info.count);
+ if (adjust_args_list != error_mark_node)
+ adjust_args_list
+ = finish_omp_adjust_args (adjust_args_list,
+ decl,
+ parm_info.variadic ? 0 : parm_info.count);
+ if (adjust_args_list == error_mark_node)
+ adjust_args_list = NULL_TREE;
+ }
+ /* This will also clear the adjust_args_list if there was an error. */
+ if (adjust_args_idxs)
+ TREE_VALUE (adjust_args_idxs) = adjust_args_list;
+
+ /* Maybe we should just return at this point if an unexpanded pack was
+ encountered, there isn't much else that we can do if there is. */
bool koenig_p = false;
if (idk == CP_ID_KIND_UNQUALIFIED || idk == CP_ID_KIND_TEMPLATE_ID)
@@ -8543,6 +8623,21 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
if (idk == CP_ID_KIND_QUALIFIED)
variant = finish_call_expr (variant, &args, /*disallow_virtual=*/true,
koenig_p, tf_warning_or_error);
+ else if (idk == CP_ID_KIND_NONE
+ && TREE_CODE (variant) == FUNCTION_DECL
+ && DECL_IOBJ_MEMBER_FUNCTION_P (variant)
+ && CLASS_TYPE_P (DECL_CONTEXT (decl)))
+ {
+ tree saved_ccp = current_class_ptr;
+ tree saved_ccr = current_class_ref;
+ current_class_ptr = NULL_TREE;
+ current_class_ref = NULL_TREE;
+ inject_this_parameter (DECL_CONTEXT (decl), TYPE_UNQUALIFIED);
+ variant = finish_call_expr (variant, &args, /*disallow_virtual=*/false,
+ koenig_p, tf_warning_or_error);
+ current_class_ptr = saved_ccp;
+ current_class_ref = saved_ccr;
+ }
else
variant = finish_call_expr (variant, &args, /*disallow_virtual=*/false,
koenig_p, tf_warning_or_error);
@@ -8555,120 +8650,119 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
variant = cp_get_callee_fndecl_nofold (STRIP_REFERENCE_REF (variant));
input_location = save_loc;
- if (variant)
+ if (!variant)
{
- bool fail;
- const char *varname = IDENTIFIER_POINTER (DECL_NAME (variant));
- if (!nappend_args)
- fail = !comptypes (TREE_TYPE (decl), TREE_TYPE (variant),
- COMPARE_STRICT);
- else
- {
- unsigned nbase_args = 0;
- for (tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
- t && TREE_VALUE (t) != void_type_node; t = TREE_CHAIN (t))
- nbase_args++;
- tree vargs, varg;
- vargs = varg = TYPE_ARG_TYPES (TREE_TYPE (variant));
- for (unsigned i = 0; i < nbase_args && varg;
- i++, varg = TREE_CHAIN (varg))
- vargs = varg;
- for (unsigned i = 0; i < nappend_args && varg; i++)
- varg = TREE_CHAIN (varg);
- tree saved_vargs;
- if (nbase_args)
- {
- saved_vargs = TREE_CHAIN (vargs);
- TREE_CHAIN (vargs) = varg;
- }
- else
- {
- saved_vargs = vargs;
- TYPE_ARG_TYPES (TREE_TYPE (variant)) = varg;
- }
- /* Skip assert check that TYPE_CANONICAL is the same. */
- fail = !comptypes (TREE_TYPE (decl), TREE_TYPE (variant),
- COMPARE_STRUCTURAL);
- if (nbase_args)
- TREE_CHAIN (vargs) = saved_vargs;
- else
- TYPE_ARG_TYPES (TREE_TYPE (variant)) = saved_vargs;
- varg = saved_vargs;
- if (!fail && !processing_template_decl)
- for (unsigned i = 0; i < nappend_args;
- i++, varg = TREE_CHAIN (varg))
- if (!varg || !c_omp_interop_t_p (TREE_VALUE (varg)))
- {
- error_at (DECL_SOURCE_LOCATION (variant),
- "argument %d of %qD must be of %<omp_interop_t%>",
- nbase_args + i + 1, variant);
- inform (EXPR_LOCATION (TREE_PURPOSE (append_args_list)),
- "%<append_args%> specified here");
- break;
- }
- }
+ /* Don't error unless we are fully instantiated. */
+ if (processing_template_decl)
+ return false;
+ error_at (varid_loc, "could not find variant declaration");
+ return true;
+ }
+
+ /* We should probably just error and return here if the two functions are not
+ both member functions or both free functions, but I don't want to move
+ the later error that checks for builtins ip right now. */
+ auto emit_variant_type_error = [&] ()
+ {
+ error_at (varid_loc, "variant %qD and base %qD have incompatible "
+ "types", variant, decl);
+ };
+ /* Unlike below, COMPARE_STRICT is fine here. */
+ if (!nappend_args
+ && !comptypes (TREE_TYPE (decl), TREE_TYPE (variant), COMPARE_STRICT))
+ {
+ error_at (varid_loc, "variant %qD and base %qD have incompatible "
+ "types", variant, decl);
+ return true;
+ }
+ if (nappend_args)
+ {
+ const unsigned nbase_parms = parm_info.count;
+ {
+ tree t = TREE_CHAIN (TREE_CHAIN (chain));
+ tree append_args_node = TREE_CHAIN (TREE_VALUE (t));
+ /* Add the number of parameters once we know how many there are, for
+ now just wait until we are fully instantiated to keep it simple. */
+ if (append_args_node && !processing_template_decl)
+ TREE_PURPOSE (append_args_node)
+ = build_int_cst (integer_type_node, nbase_parms);
+ }
+ /* This is where appended interop parms start, we need to remove them
+ temporarily to compare the function types. */
+ tree *const last_regular_parm_chain = [&] ()
+ {
+ if (!nbase_parms)
+ return &TYPE_ARG_TYPES (TREE_TYPE (variant));
+ /* Return a pointer to the last regular parm's chain, subtract 1 from
+ nbase_parms so we don't iterate past it. */
+ tree last_regular_parm
+ = chain_index (nbase_parms - 1,
+ TYPE_ARG_TYPES (TREE_TYPE (variant)));
+ return &TREE_CHAIN (last_regular_parm);
+ } (); /* IILE. */
+
+ /* Go past the added interop parms to find the first hidden parm, or the
+ end of the list of parms, this can be NULL_TREE or void_list_node. */
+ tree first_hidden_parm = chain_index (nappend_args,
+ *last_regular_parm_chain);
+ tree interop_parms_start = *last_regular_parm_chain;
+ *last_regular_parm_chain = first_hidden_parm;
+ /* Skip assert check that TYPE_CANONICAL is the same, use
+ COMPARE_STRUCTURAL, not COMPARE_STRICT. */
+ const bool fail = !comptypes (TREE_TYPE (decl), TREE_TYPE (variant),
+ COMPARE_STRUCTURAL);
+ /* Return the variant back to normal, even if the comparison failed. */
+ *last_regular_parm_chain = interop_parms_start;
+
if (fail)
{
- error_at (varid_loc, "variant %qD and base %qD have incompatible "
- "types", variant, decl);
- return true;
- }
- if (fndecl_built_in_p (variant)
- && (startswith (varname, "__builtin_")
- || startswith (varname, "__sync_")
- || startswith (varname, "__atomic_")))
- {
- error_at (varid_loc, "variant %qD is a built-in", variant);
+ emit_variant_type_error ();
return true;
}
- else
- {
- tree construct
- = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
- omp_mark_declare_variant (match_loc, variant, construct);
- if (!omp_context_selector_matches (ctx, NULL_TREE, false))
- return true;
- TREE_PURPOSE (TREE_VALUE (attr)) = variant;
-
- // Prepend adjust_args list to variant attributes
- tree adjust_args_list = TREE_CHAIN (TREE_CHAIN (chain));
- if (adjust_args_list != NULL_TREE)
- {
- if (DECL_NONSTATIC_MEMBER_P (variant)
- && TREE_VALUE (adjust_args_list))
- {
- /* Shift arg position for the added 'this' pointer. */
- /* Handle need_device_ptr */
- for (tree t = TREE_PURPOSE (TREE_VALUE (adjust_args_list));
- t; t = TREE_CHAIN (t))
- TREE_VALUE (t)
- = build_int_cst (TREE_TYPE (t),
- tree_to_uhwi (TREE_VALUE (t)) + 1);
- }
- if (DECL_NONSTATIC_MEMBER_P (variant) && append_args_list)
- {
- /* Shift likewise the number of args after which the
- interop object should be added. */
- tree nargs = TREE_CHAIN (TREE_VALUE (adjust_args_list));
- TREE_PURPOSE (nargs)
- = build_int_cst (TREE_TYPE (nargs),
- tree_to_uhwi (TREE_PURPOSE (nargs)) + 1);
- }
- for (tree t = append_args_list; t; t = TREE_CHAIN (t))
- TREE_VALUE (t)
- = cp_finish_omp_init_prefer_type (TREE_VALUE (t));
- DECL_ATTRIBUTES (variant) = tree_cons (
- get_identifier ("omp declare variant variant args"),
- TREE_VALUE (adjust_args_list), DECL_ATTRIBUTES (variant));
- }
- }
+ tree interop_parm = interop_parms_start;
+ if (!processing_template_decl)
+ for (unsigned i = 0; i < nappend_args; i++)
+ {
+ if (!interop_parm
+ || !c_omp_interop_t_p (TREE_VALUE (interop_parm)))
+ {
+ error_at (DECL_SOURCE_LOCATION (variant),
+ "argument %d of %qD must be of %<omp_interop_t%>",
+ nbase_parms + i + 1, variant);
+ inform (EXPR_LOCATION (TREE_PURPOSE (append_args_list)),
+ "%<append_args%> specified here");
+ break;
+ }
+ interop_parm = TREE_CHAIN (interop_parm);
+ }
}
- else if (!processing_template_decl)
+ const char *varname = IDENTIFIER_POINTER (DECL_NAME (variant));
+ if (fndecl_built_in_p (variant)
+ && (startswith (varname, "__builtin_")
+ || startswith (varname, "__sync_")
+ || startswith (varname, "__atomic_")))
{
- error_at (varid_loc, "could not find variant declaration");
+ error_at (varid_loc, "variant %qD is a built-in", variant);
return true;
}
+ tree construct
+ = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
+ omp_mark_declare_variant (match_loc, variant, construct);
+ if (!omp_context_selector_matches (ctx, NULL_TREE, false))
+ return true;
+ TREE_PURPOSE (TREE_VALUE (attr)) = variant;
+
+ // Prepend adjust_args list to variant attributes
+ if (adjust_args_idxs != NULL_TREE)
+ {
+ for (tree t = append_args_list; t; t = TREE_CHAIN (t))
+ TREE_VALUE (t) = cp_finish_omp_init_prefer_type (TREE_VALUE (t));
+ DECL_ATTRIBUTES (variant)
+ = tree_cons (get_identifier ("omp declare variant variant args"),
+ adjust_args_idxs, DECL_ATTRIBUTES (variant));
+ }
+
return false;
}
@@ -9188,14 +9282,23 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
varpool_node::get_create (decl);
}
+ if (flag_openmp
+ && VAR_P (decl)
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_OMP_DECLARE_MAPPER_P (decl)
+ && init)
+ {
+ gcc_assert (TREE_CODE (init) == OMP_DECLARE_MAPPER);
+ DECL_INITIAL (decl) = init;
+ }
/* Convert the initializer to the type of DECL, if we have not
already initialized DECL. */
- if (!DECL_INITIALIZED_P (decl)
- /* If !DECL_EXTERNAL then DECL is being defined. In the
- case of a static data member initialized inside the
- class-specifier, there can be an initializer even if DECL
- is *not* defined. */
- && (!DECL_EXTERNAL (decl) || init))
+ else if (!DECL_INITIALIZED_P (decl)
+ /* If !DECL_EXTERNAL then DECL is being defined. In the
+ case of a static data member initialized inside the
+ class-specifier, there can be an initializer even if DECL
+ is *not* defined. */
+ && (!DECL_EXTERNAL (decl) || init))
{
cleanups = make_tree_vector ();
init = check_initializer (decl, init, flags, &cleanups);
@@ -12400,6 +12503,81 @@ create_array_type_for_decl (tree name, tree type, tree size, location_t loc)
return build_cplus_array_type (type, itype);
}
+/* Build an anonymous array of SIZE elements of ELTYPE. */
+
+static tree
+create_anon_array_type (location_t loc, tree eltype, tree size)
+{
+ if (eltype == error_mark_node || size == error_mark_node)
+ return error_mark_node;
+
+ tree itype = compute_array_index_type_loc (loc, NULL_TREE, size,
+ tf_warning_or_error);
+
+ if (type_uses_auto (eltype)
+ && variably_modified_type_p (itype, /*fn=*/NULL_TREE))
+ {
+ sorry_at (loc, "variable-length array of %<auto%>");
+ return error_mark_node;
+ }
+
+ return build_cplus_array_type (eltype, itype);
+}
+
+/* Derive an array type for an OpenMP array-shaping operator given EXPR, which
+ is an expression that might have array refs or array sections postfixed
+ (e.g. "ptr[0:3:2][3:4]"), and OMP_SHAPE_DIMS, a vector of dimensions. */
+
+tree
+cp_omp_create_arrayshape_type (location_t loc, tree expr,
+ vec<cp_expr> *omp_shape_dims)
+{
+ tree type, strip_sections = expr;
+
+ while (TREE_CODE (strip_sections) == OMP_ARRAY_SECTION
+ || TREE_CODE (strip_sections) == ARRAY_REF)
+ strip_sections = TREE_OPERAND (strip_sections, 0);
+
+ /* Determine the element type, either directly or by using
+ "decltype" of an expression representing an element to
+ figure it out later during template instantiation. */
+ if (type_dependent_expression_p (expr))
+ {
+ type = cxx_make_type (DECLTYPE_TYPE);
+
+ DECLTYPE_TYPE_EXPR (type)
+ = build_min_nt_loc (loc, INDIRECT_REF, strip_sections);
+ DECLTYPE_FOR_OMP_ARRAYSHAPE_CAST (type) = true;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ }
+ else
+ {
+ type = TREE_TYPE (strip_sections);
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ if (TREE_CODE (type) != POINTER_TYPE)
+ {
+ error ("OpenMP array shaping operator with non-pointer argument");
+ return error_mark_node;
+ }
+
+ type = TREE_TYPE (type);
+ }
+
+ int i;
+ cp_expr dim;
+ FOR_EACH_VEC_ELT_REVERSE (*omp_shape_dims, i, dim)
+ {
+ if (!type_dependent_expression_p (dim))
+ dim = fold_convert (sizetype, dim);
+ type = create_anon_array_type (loc, type, dim);
+ }
+
+ return type;
+}
+
/* Returns the smallest location that is not UNKNOWN_LOCATION. */
static location_t