#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "alias.h"
-#include "tree.h"
+#include "cp-tree.h"
+#include "timevar.h"
#include "stringpool.h"
#include "varasm.h"
#include "attribs.h"
#include "stor-layout.h"
#include "intl.h"
-#include "flags.h"
-#include "cp-tree.h"
-#include "c-family/c-common.h"
#include "c-family/c-objc.h"
#include "cp-objcp-common.h"
-#include "tree-inline.h"
-#include "decl.h"
#include "toplev.h"
-#include "timevar.h"
#include "tree-iterator.h"
#include "type-utils.h"
#include "gimplify.h"
static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
static tree convert_template_argument (tree, tree, tree,
tsubst_flags_t, int, tree);
-static int for_each_template_parm (tree, tree_fn_t, void*,
- hash_set<tree> *, bool);
+static tree for_each_template_parm (tree, tree_fn_t, void*,
+ hash_set<tree> *, bool);
static tree expand_template_argument_pack (tree);
static tree build_template_parm_index (int, int, int, tree, tree);
static bool inline_needs_template_parms (tree, bool);
break;
case PARM_DECL:
- {
- /* Make a CONST_DECL as is done in process_template_parm.
- It is ugly that we recreate this here; the original
- version built in process_template_parm is no longer
- available. */
- tree decl = build_decl (DECL_SOURCE_LOCATION (parm),
- CONST_DECL, DECL_NAME (parm),
- TREE_TYPE (parm));
- DECL_ARTIFICIAL (decl) = 1;
- TREE_CONSTANT (decl) = 1;
- TREE_READONLY (decl) = 1;
- DECL_INITIAL (decl) = DECL_INITIAL (parm);
- SET_DECL_TEMPLATE_PARM_P (decl);
- pushdecl (decl);
- }
+ /* Push the CONST_DECL. */
+ pushdecl (TEMPLATE_PARM_DECL (DECL_INITIAL (parm)));
break;
default:
gone through coerce_template_parms by now. */
static void
-check_unstripped_args (tree args ATTRIBUTE_UNUSED)
+verify_unstripped_args (tree args)
{
-#ifdef ENABLE_CHECKING
++processing_template_decl;
if (!any_dependent_template_arguments_p (args))
{
}
}
--processing_template_decl;
-#endif
}
/* Retrieve the specialization (in the sense of [temp.spec] - a
? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
: template_class_depth (DECL_CONTEXT (tmpl))));
- check_unstripped_args (args);
+ if (flag_checking)
+ verify_unstripped_args (args);
if (optimize_specialization_lookup_p (tmpl))
{
static hashval_t
hash_tmpl_and_args (tree tmpl, tree args)
{
- hashval_t val = DECL_UID (tmpl);
+ hashval_t val = iterative_hash_object (DECL_UID (tmpl), 0);
return iterative_hash_template_arg (args, val);
}
error ("%qD is not a template function", dname);
fns = error_mark_node;
}
- else
- {
- tree fn = OVL_CURRENT (fns);
- if (!is_associated_namespace (CP_DECL_CONTEXT (decl),
- CP_DECL_CONTEXT (fn)))
- error ("%qD is not declared in %qD",
- decl, current_namespace);
- }
}
declarator = lookup_template_function (fns, NULL_TREE);
return error_mark_node;
else
{
+ if (!ctype && !was_template_id
+ && (specialization || member_specialization
+ || explicit_instantiation)
+ && !is_associated_namespace (CP_DECL_CONTEXT (decl),
+ CP_DECL_CONTEXT (tmpl)))
+ error ("%qD is not declared in %qD",
+ tmpl, current_namespace);
+
tree gen_tmpl = most_general_template (tmpl);
if (explicit_instantiation)
/* Set of AST nodes that have been visited by the traversal. */
hash_set<tree> *visited;
+
+ /* True iff we're making a type pack expansion. */
+ bool type_pack_expansion_p;
};
/* Identifies all of the argument packs that occur in a template
case TEMPLATE_TYPE_PARM:
t = TYPE_MAIN_VARIANT (t);
case TEMPLATE_TEMPLATE_PARM:
+ /* If the placeholder appears in the decl-specifier-seq of a function
+ parameter pack (14.6.3), or the type-specifier-seq of a type-id that
+ is a pack expansion, the invented template parameter is a template
+ parameter pack. */
+ if (ppd->type_pack_expansion_p && is_auto_or_concept (t))
+ TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
if (TEMPLATE_TYPE_PARAMETER_PACK (t))
parameter_pack_p = true;
break;
struct find_parameter_pack_data ppd;
ppd.parameter_packs = ¶meter_packs;
ppd.visited = new hash_set<tree>;
+ ppd.type_pack_expansion_p = false;
cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
delete ppd.visited;
return parameter_packs != NULL_TREE;
/* Determine which parameter packs will be expanded. */
ppd.parameter_packs = ¶meter_packs;
ppd.visited = new hash_set<tree>;
+ ppd.type_pack_expansion_p = TYPE_P (arg);
cp_walk_tree (&arg, &find_parameter_packs_r, &ppd, ppd.visited);
delete ppd.visited;
ppd.parameter_packs = ¶meter_packs;
ppd.visited = new hash_set<tree>;
+ ppd.type_pack_expansion_p = false;
cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
delete ppd.visited;
/* Turn this argument into a TYPE_ARGUMENT_PACK
with a single element, which expands T. */
tree vec = make_tree_vec (1);
-#ifdef ENABLE_CHECKING
- SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT
- (vec, TREE_VEC_LENGTH (vec));
-#endif
+ if (CHECKING_P)
+ SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
+
TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
t = cxx_make_type (TYPE_ARGUMENT_PACK);
with a single element, which expands T. */
tree vec = make_tree_vec (1);
tree type = TREE_TYPE (TEMPLATE_PARM_DECL (t));
-#ifdef ENABLE_CHECKING
- SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT
- (vec, TREE_VEC_LENGTH (vec));
-#endif
+ if (CHECKING_P)
+ SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
+
t = convert_from_reference (t);
TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
-#ifdef ENABLE_CHECKING
- SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
-#endif
+ if (CHECKING_P)
+ SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
if (length > 1)
TREE_VEC_ELT (args, --l) = a;
: DECL_TEMPLATE_INSTANTIATION (instance))
{
tree spec = most_specialized_partial_spec (instance, tf_none);
- if (spec && TREE_VALUE (spec) == tmpl)
- {
- tree inst_decl = (DECL_P (instance)
- ? instance : TYPE_NAME (instance));
- permerror (input_location,
- "partial specialization of %qD after instantiation "
- "of %qD", decl, inst_decl);
- }
+ tree inst_decl = (DECL_P (instance)
+ ? instance : TYPE_NAME (instance));
+ if (!spec)
+ /* OK */;
+ else if (spec == error_mark_node)
+ permerror (input_location,
+ "declaration of %qD ambiguates earlier template "
+ "instantiation for %qD", decl, inst_decl);
+ else if (TREE_VALUE (spec) == tmpl)
+ permerror (input_location,
+ "partial specialization of %qD after instantiation "
+ "of %qD", decl, inst_decl);
}
}
struct find_parameter_pack_data ppd;
ppd.parameter_packs = ¶meter_packs;
ppd.visited = new hash_set<tree>;
+ ppd.type_pack_expansion_p = false;
fixed_parameter_pack_p_1 (parm, &ppd);
else if (is_partial)
msg = G_("default template arguments may not be used in "
"partial specializations");
- else
+ else if (current_class_type && CLASSTYPE_IS_TEMPLATE (current_class_type))
msg = G_("default argument for template parameter for class enclosing %qD");
+ else
+ /* Per [temp.param]/9, "A default template-argument shall not be
+ specified in the template-parameter-lists of the definition of
+ a member of a class template that appears outside of the member's
+ class.", thus if we aren't handling a member of a class template
+ there is no need to examine the parameters. */
+ return true;
if (current_class_type && TYPE_BEING_DEFINED (current_class_type))
/* If we're inside a class definition, there's no need to
if (is_primary)
{
+ warning (OPT_Wtemplates, "template %qD declared", decl);
+
if (DECL_CLASS_SCOPE_P (decl))
member_template_p = true;
if (TREE_CODE (decl) == TYPE_DECL
CONSTRUCTOR. */;
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
expr = maybe_constant_value (expr);
+ else if (cxx_dialect >= cxx1z)
+ {
+ if (TREE_CODE (type) != REFERENCE_TYPE)
+ expr = maybe_constant_value (expr);
+ else if (REFERENCE_REF_P (expr))
+ {
+ expr = TREE_OPERAND (expr, 0);
+ expr = maybe_constant_value (expr);
+ expr = convert_from_reference (expr);
+ }
+ }
else if (TYPE_PTR_OR_PTRMEM_P (type))
{
tree folded = maybe_constant_value (expr);
}
SET_ARGUMENT_PACK_ARGS (argument_pack, packed_args);
-#ifdef ENABLE_CHECKING
- SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (packed_args,
- TREE_VEC_LENGTH (packed_args));
-#endif
+ if (CHECKING_P)
+ SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (packed_args,
+ TREE_VEC_LENGTH (packed_args));
return argument_pack;
}
if (lost)
return error_mark_node;
-#ifdef ENABLE_CHECKING
- if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args))
+ if (CHECKING_P && !NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args))
SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args,
TREE_VEC_LENGTH (new_inner_args));
-#endif
return new_inner_args;
}
struct pair_fn_data *pfd = (struct pair_fn_data *) d;
tree_fn_t fn = pfd->fn;
void *data = pfd->data;
+ tree result = NULL_TREE;
+
+#define WALK_SUBTREE(NODE) \
+ do \
+ { \
+ result = for_each_template_parm (NODE, fn, data, pfd->visited, \
+ pfd->include_nondeduced_p); \
+ if (result) goto out; \
+ } \
+ while (0)
if (TYPE_P (t)
- && (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE)
- && for_each_template_parm (TYPE_CONTEXT (t), fn, data, pfd->visited,
- pfd->include_nondeduced_p))
- return error_mark_node;
+ && (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE))
+ WALK_SUBTREE (TYPE_CONTEXT (t));
switch (TREE_CODE (t))
{
case ENUMERAL_TYPE:
if (!TYPE_TEMPLATE_INFO (t))
*walk_subtrees = 0;
- else if (for_each_template_parm (TYPE_TI_ARGS (t),
- fn, data, pfd->visited,
- pfd->include_nondeduced_p))
- return error_mark_node;
+ else
+ WALK_SUBTREE (TYPE_TI_ARGS (t));
break;
case INTEGER_TYPE:
- if (for_each_template_parm (TYPE_MIN_VALUE (t),
- fn, data, pfd->visited,
- pfd->include_nondeduced_p)
- || for_each_template_parm (TYPE_MAX_VALUE (t),
- fn, data, pfd->visited,
- pfd->include_nondeduced_p))
- return error_mark_node;
+ WALK_SUBTREE (TYPE_MIN_VALUE (t));
+ WALK_SUBTREE (TYPE_MAX_VALUE (t));
break;
case METHOD_TYPE:
/* Since we're not going to walk subtrees, we have to do this
explicitly here. */
- if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data,
- pfd->visited, pfd->include_nondeduced_p))
- return error_mark_node;
+ WALK_SUBTREE (TYPE_METHOD_BASETYPE (t));
/* Fall through. */
case FUNCTION_TYPE:
/* Check the return type. */
- if (for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited,
- pfd->include_nondeduced_p))
- return error_mark_node;
+ WALK_SUBTREE (TREE_TYPE (t));
/* Check the parameter types. Since default arguments are not
instantiated until they are needed, the TYPE_ARG_TYPES may
tree parm;
for (parm = TYPE_ARG_TYPES (t); parm; parm = TREE_CHAIN (parm))
- if (for_each_template_parm (TREE_VALUE (parm), fn, data,
- pfd->visited, pfd->include_nondeduced_p))
- return error_mark_node;
+ WALK_SUBTREE (TREE_VALUE (parm));
/* Since we've already handled the TYPE_ARG_TYPES, we don't
want walk_tree walking into them itself. */
case FUNCTION_DECL:
case VAR_DECL:
- if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
- && for_each_template_parm (DECL_TI_ARGS (t), fn, data,
- pfd->visited, pfd->include_nondeduced_p))
- return error_mark_node;
+ if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
+ WALK_SUBTREE (DECL_TI_ARGS (t));
/* Fall through. */
case PARM_DECL:
case CONST_DECL:
- if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t)
- && for_each_template_parm (DECL_INITIAL (t), fn, data,
- pfd->visited, pfd->include_nondeduced_p))
- return error_mark_node;
+ if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t))
+ WALK_SUBTREE (DECL_INITIAL (t));
if (DECL_CONTEXT (t)
- && pfd->include_nondeduced_p
- && for_each_template_parm (DECL_CONTEXT (t), fn, data,
- pfd->visited, pfd->include_nondeduced_p))
- return error_mark_node;
+ && pfd->include_nondeduced_p)
+ WALK_SUBTREE (DECL_CONTEXT (t));
break;
case BOUND_TEMPLATE_TEMPLATE_PARM:
/* Record template parameters such as `T' inside `TT<T>'. */
- if (for_each_template_parm (TYPE_TI_ARGS (t), fn, data, pfd->visited,
- pfd->include_nondeduced_p))
- return error_mark_node;
+ WALK_SUBTREE (TYPE_TI_ARGS (t));
/* Fall through. */
case TEMPLATE_TEMPLATE_PARM:
case TEMPLATE_TYPE_PARM:
case TEMPLATE_PARM_INDEX:
if (fn && (*fn)(t, data))
- return error_mark_node;
+ return t;
else if (!fn)
- return error_mark_node;
+ return t;
break;
case TEMPLATE_DECL:
/* A template template parameter is encountered. */
- if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)
- && for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited,
- pfd->include_nondeduced_p))
- return error_mark_node;
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
+ WALK_SUBTREE (TREE_TYPE (t));
/* Already substituted template template parameter */
*walk_subtrees = 0;
break;
case TYPENAME_TYPE:
- if (!fn
- || for_each_template_parm (TYPENAME_TYPE_FULLNAME (t), fn,
- data, pfd->visited,
- pfd->include_nondeduced_p))
- return error_mark_node;
+ if (!fn)
+ WALK_SUBTREE (TYPENAME_TYPE_FULLNAME (t));
break;
case CONSTRUCTOR:
if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))
- && pfd->include_nondeduced_p
- && for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE
- (TREE_TYPE (t)), fn, data,
- pfd->visited, pfd->include_nondeduced_p))
- return error_mark_node;
+ && pfd->include_nondeduced_p)
+ WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)));
break;
case INDIRECT_REF:
break;
}
+ #undef WALK_SUBTREE
+
/* We didn't find any template parameters we liked. */
- return NULL_TREE;
+ out:
+ return result;
}
/* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM,
parameters that occur in non-deduced contexts. When false, only
visits those template parameters that can be deduced. */
-static int
+static tree
for_each_template_parm (tree t, tree_fn_t fn, void* data,
hash_set<tree> *visited,
bool include_nondeduced_p)
{
struct pair_fn_data pfd;
- int result;
+ tree result;
/* Set up. */
pfd.fn = fn;
result = cp_walk_tree (&t,
for_each_template_parm_r,
&pfd,
- pfd.visited) != NULL_TREE;
+ pfd.visited);
/* Clean up. */
if (!visited)
/* Returns true if T depends on any template parameter with level LEVEL. */
-int
+bool
uses_template_parms_level (tree t, int level)
{
return for_each_template_parm (t, template_parm_this_level_p, &level, NULL,
return 1;
}
-static tree tsubst_omp_clauses (tree, bool, tree, tsubst_flags_t, tree);
+static tree tsubst_omp_clauses (tree, bool, bool, tree, tsubst_flags_t, tree);
/* Apply any attributes which had to be deferred until instantiation
time. DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes;
&& TREE_VALUE (t))
{
tree clauses = TREE_VALUE (TREE_VALUE (t));
- clauses = tsubst_omp_clauses (clauses, true, args,
+ clauses = tsubst_omp_clauses (clauses, true, false, args,
complain, in_decl);
c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
- clauses = finish_omp_clauses (clauses);
+ clauses = finish_omp_clauses (clauses, false, true);
tree parms = DECL_ARGUMENTS (*decl_p);
clauses
= c_omp_declare_simd_clauses_to_numbers (parms, clauses);
{
if (!DECL_TEMPLATE_INFO (decl)
|| DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (decl)) != decl)
- instantiate_decl (decl, false, false);
+ {
+ /* Set function_depth to avoid garbage collection. */
+ ++function_depth;
+ instantiate_decl (decl, false, false);
+ --function_depth;
+ }
/* We need to instantiate the capture list from the template
after we've instantiated the closure members, but before we
tree in_decl)
{
tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
+ if (pack == error_mark_node)
+ return error_mark_node;
if (TREE_VEC_LENGTH (pack) == 0)
return expand_empty_fold (t, complain);
else
tree in_decl)
{
tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
+ if (pack == error_mark_node)
+ return error_mark_node;
tree init = tsubst_fold_expr_init (t, args, complain, in_decl);
+ if (init == error_mark_node)
+ return error_mark_node;
tree vec = make_tree_vec (TREE_VEC_LENGTH (pack) + 1);
TREE_VEC_ELT (vec, 0) = init;
tree in_decl)
{
tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
+ if (pack == error_mark_node)
+ return error_mark_node;
if (TREE_VEC_LENGTH (pack) == 0)
return expand_empty_fold (t, complain);
else
tree in_decl)
{
tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
+ if (pack == error_mark_node)
+ return error_mark_node;
tree init = tsubst_fold_expr_init (t, args, complain, in_decl);
+ if (init == error_mark_node)
+ return error_mark_node;
int n = TREE_VEC_LENGTH (pack);
tree vec = make_tree_vec (n + 1);
return tsubst_binary_right_fold (t, args, complain, in_decl);
default:
- /* We shouldn't get here, but keep going if !ENABLE_CHECKING. */
- gcc_checking_assert (false);
+ /* We shouldn't get here, but keep going if !flag_checking. */
+ if (flag_checking)
+ gcc_unreachable ();
return t;
}
}
/* Helper function for tsubst_omp_clauses, used for instantiation of
- OMP_CLAUSE_DECL of clauses that handles also OpenMP array sections
- represented with TREE_LIST. */
+ OMP_CLAUSE_DECL of clauses. */
static tree
tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain,
tree in_decl)
{
+ if (decl == NULL_TREE)
+ return NULL_TREE;
+
+ /* Handle an OpenMP array section represented as a TREE_LIST (or
+ OMP_CLAUSE_DEPEND_KIND). An OMP_CLAUSE_DEPEND (with a depend
+ kind of OMP_CLAUSE_DEPEND_SINK) can also be represented as a
+ TREE_LIST. We can handle it exactly the same as an array section
+ (purpose, value, and a chain), even though the nomenclature
+ (low_bound, length, etc) is different. */
if (TREE_CODE (decl) == TREE_LIST)
{
tree low_bound
&& TREE_VALUE (decl) == length
&& TREE_CHAIN (decl) == chain)
return decl;
- return tree_cons (low_bound, length, chain);
- }
- return tsubst_copy (decl, args, complain, in_decl);
+ tree ret = tree_cons (low_bound, length, chain);
+ OMP_CLAUSE_DEPEND_SINK_NEGATIVE (ret)
+ = OMP_CLAUSE_DEPEND_SINK_NEGATIVE (decl);
+ return ret;
+ }
+ tree ret = tsubst_expr (decl, args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+ /* Undo convert_from_reference tsubst_expr could have called. */
+ if (decl
+ && REFERENCE_REF_P (ret)
+ && !REFERENCE_REF_P (decl))
+ ret = TREE_OPERAND (ret, 0);
+ return ret;
}
/* Like tsubst_copy, but specifically for OpenMP clauses. */
static tree
-tsubst_omp_clauses (tree clauses, bool declare_simd,
+tsubst_omp_clauses (tree clauses, bool declare_simd, bool allow_fields,
tree args, tsubst_flags_t complain, tree in_decl)
{
- tree new_clauses = NULL, nc, oc;
+ tree new_clauses = NULL_TREE, nc, oc;
+ tree linear_no_step = NULL_TREE;
for (oc = clauses; oc ; oc = OMP_CLAUSE_CHAIN (oc))
{
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:
case OMP_CLAUSE_UNIFORM:
- OMP_CLAUSE_DECL (nc) = tsubst_copy (OMP_CLAUSE_DECL (oc), args,
- complain, in_decl);
- break;
case OMP_CLAUSE_DEPEND:
case OMP_CLAUSE_FROM:
case OMP_CLAUSE_TO:
case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_USE_DEVICE_PTR:
+ case OMP_CLAUSE_IS_DEVICE_PTR:
OMP_CLAUSE_DECL (nc)
= tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
in_decl);
case OMP_CLAUSE_THREAD_LIMIT:
case OMP_CLAUSE_SAFELEN:
case OMP_CLAUSE_SIMDLEN:
+ case OMP_CLAUSE_NUM_TASKS:
+ case OMP_CLAUSE_GRAINSIZE:
+ case OMP_CLAUSE_PRIORITY:
+ case OMP_CLAUSE_ORDERED:
+ case OMP_CLAUSE_HINT:
+ case OMP_CLAUSE_NUM_GANGS:
+ case OMP_CLAUSE_NUM_WORKERS:
+ case OMP_CLAUSE_VECTOR_LENGTH:
+ case OMP_CLAUSE_WORKER:
+ case OMP_CLAUSE_VECTOR:
+ case OMP_CLAUSE_ASYNC:
+ case OMP_CLAUSE_WAIT:
OMP_CLAUSE_OPERAND (nc, 0)
= tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain,
in_decl, /*integral_constant_expression_p=*/false);
else
gcc_assert (identifier_p (placeholder));
}
- OMP_CLAUSE_DECL (nc) = tsubst_copy (OMP_CLAUSE_DECL (oc), args,
- complain, in_decl);
+ OMP_CLAUSE_DECL (nc)
+ = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
+ in_decl);
break;
- case OMP_CLAUSE_LINEAR:
+ case OMP_CLAUSE_GANG:
case OMP_CLAUSE_ALIGNED:
- OMP_CLAUSE_DECL (nc) = tsubst_copy (OMP_CLAUSE_DECL (oc), args,
- complain, in_decl);
+ OMP_CLAUSE_DECL (nc)
+ = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
+ in_decl);
OMP_CLAUSE_OPERAND (nc, 1)
= tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain,
in_decl, /*integral_constant_expression_p=*/false);
break;
+ case OMP_CLAUSE_LINEAR:
+ OMP_CLAUSE_DECL (nc)
+ = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
+ in_decl);
+ if (OMP_CLAUSE_LINEAR_STEP (oc) == NULL_TREE)
+ {
+ gcc_assert (!linear_no_step);
+ linear_no_step = nc;
+ }
+ else if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (oc))
+ OMP_CLAUSE_LINEAR_STEP (nc)
+ = tsubst_omp_clause_decl (OMP_CLAUSE_LINEAR_STEP (oc), args,
+ complain, in_decl);
+ else
+ OMP_CLAUSE_LINEAR_STEP (nc)
+ = tsubst_expr (OMP_CLAUSE_LINEAR_STEP (oc), args, complain,
+ in_decl,
+ /*integral_constant_expression_p=*/false);
+ break;
case OMP_CLAUSE_NOWAIT:
- case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_MERGEABLE:
case OMP_CLAUSE_PARALLEL:
case OMP_CLAUSE_SECTIONS:
case OMP_CLAUSE_TASKGROUP:
+ case OMP_CLAUSE_NOGROUP:
+ case OMP_CLAUSE_THREADS:
+ case OMP_CLAUSE_SIMD:
+ case OMP_CLAUSE_DEFAULTMAP:
+ case OMP_CLAUSE_INDEPENDENT:
+ case OMP_CLAUSE_AUTO:
+ case OMP_CLAUSE_SEQ:
+ break;
+ case OMP_CLAUSE_TILE:
+ {
+ tree lnc, loc;
+ for (lnc = OMP_CLAUSE_TILE_LIST (nc),
+ loc = OMP_CLAUSE_TILE_LIST (oc);
+ loc;
+ loc = TREE_CHAIN (loc), lnc = TREE_CHAIN (lnc))
+ {
+ TREE_VALUE (lnc) = tsubst_expr (TREE_VALUE (loc), args,
+ complain, in_decl, false);
+ }
+ }
break;
default:
gcc_unreachable ();
}
+ if (allow_fields)
+ switch (OMP_CLAUSE_CODE (nc))
+ {
+ case OMP_CLAUSE_SHARED:
+ case OMP_CLAUSE_PRIVATE:
+ case OMP_CLAUSE_FIRSTPRIVATE:
+ case OMP_CLAUSE_LASTPRIVATE:
+ case OMP_CLAUSE_COPYPRIVATE:
+ case OMP_CLAUSE_LINEAR:
+ case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_USE_DEVICE_PTR:
+ case OMP_CLAUSE_IS_DEVICE_PTR:
+ /* tsubst_expr on SCOPE_REF results in returning
+ finish_non_static_data_member result. Undo that here. */
+ if (TREE_CODE (OMP_CLAUSE_DECL (oc)) == SCOPE_REF
+ && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (oc), 1))
+ == IDENTIFIER_NODE))
+ {
+ tree t = OMP_CLAUSE_DECL (nc);
+ tree v = t;
+ while (v)
+ switch (TREE_CODE (v))
+ {
+ case COMPONENT_REF:
+ case MEM_REF:
+ case INDIRECT_REF:
+ CASE_CONVERT:
+ case POINTER_PLUS_EXPR:
+ v = TREE_OPERAND (v, 0);
+ continue;
+ case PARM_DECL:
+ if (DECL_CONTEXT (v) == current_function_decl
+ && DECL_ARTIFICIAL (v)
+ && DECL_NAME (v) == this_identifier)
+ OMP_CLAUSE_DECL (nc) = TREE_OPERAND (t, 1);
+ /* FALLTHRU */
+ default:
+ v = NULL_TREE;
+ break;
+ }
+ }
+ else if (VAR_P (OMP_CLAUSE_DECL (oc))
+ && DECL_HAS_VALUE_EXPR_P (OMP_CLAUSE_DECL (oc))
+ && DECL_ARTIFICIAL (OMP_CLAUSE_DECL (oc))
+ && DECL_LANG_SPECIFIC (OMP_CLAUSE_DECL (oc))
+ && DECL_OMP_PRIVATIZED_MEMBER (OMP_CLAUSE_DECL (oc)))
+ {
+ tree decl = OMP_CLAUSE_DECL (nc);
+ if (VAR_P (decl))
+ {
+ if (!DECL_LANG_SPECIFIC (decl))
+ retrofit_lang_decl (decl);
+ DECL_OMP_PRIVATIZED_MEMBER (decl) = 1;
+ }
+ }
+ break;
+ default:
+ break;
+ }
}
new_clauses = nreverse (new_clauses);
if (!declare_simd)
- new_clauses = finish_omp_clauses (new_clauses);
+ {
+ new_clauses = finish_omp_clauses (new_clauses, allow_fields);
+ if (linear_no_step)
+ for (nc = new_clauses; nc; nc = OMP_CLAUSE_CHAIN (nc))
+ if (nc == linear_no_step)
+ {
+ OMP_CLAUSE_LINEAR_STEP (nc) = NULL_TREE;
+ break;
+ }
+ }
return new_clauses;
}
#undef RECUR
}
+/* Used to temporarily communicate the list of #pragma omp parallel
+ clauses to #pragma omp for instantiation if they are combined
+ together. */
+
+static tree *omp_parallel_combined_clauses;
+
/* Substitute one OMP_FOR iterator. */
static void
-tsubst_omp_for_iterator (tree t, int i, tree declv, tree initv,
- tree condv, tree incrv, tree *clauses,
+tsubst_omp_for_iterator (tree t, int i, tree declv, tree orig_declv,
+ tree initv, tree condv, tree incrv, tree *clauses,
tree args, tsubst_flags_t complain, tree in_decl,
bool integral_constant_expression_p)
{
init = TREE_VEC_ELT (OMP_FOR_INIT (t), i);
gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
+
+ if (orig_declv && OMP_FOR_ORIG_DECLS (t))
+ {
+ tree o = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i);
+ TREE_VEC_ELT (orig_declv, i) = RECUR (o);
+ }
+
decl = TREE_OPERAND (init, 0);
init = TREE_OPERAND (init, 1);
tree decl_expr = NULL_TREE;
decl = tsubst_decl (decl, args, complain);
}
else
- decl = RECUR (decl);
+ {
+ if (TREE_CODE (decl) == SCOPE_REF)
+ {
+ decl = RECUR (decl);
+ if (TREE_CODE (decl) == COMPONENT_REF)
+ {
+ tree v = decl;
+ while (v)
+ switch (TREE_CODE (v))
+ {
+ case COMPONENT_REF:
+ case MEM_REF:
+ case INDIRECT_REF:
+ CASE_CONVERT:
+ case POINTER_PLUS_EXPR:
+ v = TREE_OPERAND (v, 0);
+ continue;
+ case PARM_DECL:
+ if (DECL_CONTEXT (v) == current_function_decl
+ && DECL_ARTIFICIAL (v)
+ && DECL_NAME (v) == this_identifier)
+ {
+ decl = TREE_OPERAND (decl, 1);
+ decl = omp_privatize_field (decl, false);
+ }
+ /* FALLTHRU */
+ default:
+ v = NULL_TREE;
+ break;
+ }
+ }
+ }
+ else
+ decl = RECUR (decl);
+ }
init = RECUR (init);
tree auto_node = type_uses_auto (TREE_TYPE (decl));
}
else if (init)
{
- tree c;
- for (c = *clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+ tree *pc;
+ int j;
+ for (j = (omp_parallel_combined_clauses == NULL ? 1 : 0); j < 2; j++)
{
- if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
- || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
- && OMP_CLAUSE_DECL (c) == decl)
+ for (pc = j ? clauses : omp_parallel_combined_clauses; *pc; )
+ {
+ if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_PRIVATE
+ && OMP_CLAUSE_DECL (*pc) == decl)
+ break;
+ else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LASTPRIVATE
+ && OMP_CLAUSE_DECL (*pc) == decl)
+ {
+ if (j)
+ break;
+ /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */
+ tree c = *pc;
+ *pc = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (c) = *clauses;
+ *clauses = c;
+ }
+ else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_FIRSTPRIVATE
+ && OMP_CLAUSE_DECL (*pc) == decl)
+ {
+ error ("iteration variable %qD should not be firstprivate",
+ decl);
+ *pc = OMP_CLAUSE_CHAIN (*pc);
+ }
+ else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_REDUCTION
+ && OMP_CLAUSE_DECL (*pc) == decl)
+ {
+ error ("iteration variable %qD should not be reduction",
+ decl);
+ *pc = OMP_CLAUSE_CHAIN (*pc);
+ }
+ else
+ pc = &OMP_CLAUSE_CHAIN (*pc);
+ }
+ if (*pc)
break;
- else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
- && OMP_CLAUSE_DECL (c) == decl)
- error ("iteration variable %qD should not be firstprivate", decl);
- else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
- && OMP_CLAUSE_DECL (c) == decl)
- error ("iteration variable %qD should not be reduction", decl);
}
- if (c == NULL)
+ if (*pc == NULL_TREE)
{
- c = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
+ tree c = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
OMP_CLAUSE_DECL (c) = decl;
- c = finish_omp_clauses (c);
+ c = finish_omp_clauses (c, true);
if (c)
{
OMP_CLAUSE_CHAIN (c) = *clauses;
#undef RECUR
}
+/* Helper function of tsubst_expr, find OMP_TEAMS inside
+ of OMP_TARGET's body. */
+
+static tree
+tsubst_find_omp_teams (tree *tp, int *walk_subtrees, void *)
+{
+ *walk_subtrees = 0;
+ switch (TREE_CODE (*tp))
+ {
+ case OMP_TEAMS:
+ return *tp;
+ case BIND_EXPR:
+ case STATEMENT_LIST:
+ *walk_subtrees = 1;
+ break;
+ default:
+ break;
+ }
+ return NULL_TREE;
+}
+
/* Like tsubst_copy for expressions, etc. but also does semantic
processing. */
}
break;
+ case OACC_KERNELS:
+ case OACC_PARALLEL:
+ tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, false, args, complain,
+ in_decl);
+ stmt = begin_omp_parallel ();
+ RECUR (OMP_BODY (t));
+ finish_omp_construct (TREE_CODE (t), stmt, tmp);
+ break;
+
case OMP_PARALLEL:
- tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false,
+ r = push_omp_privatization_clauses (OMP_PARALLEL_COMBINED (t));
+ tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, true,
args, complain, in_decl);
+ if (OMP_PARALLEL_COMBINED (t))
+ omp_parallel_combined_clauses = &tmp;
stmt = begin_omp_parallel ();
RECUR (OMP_PARALLEL_BODY (t));
+ gcc_assert (omp_parallel_combined_clauses == NULL);
OMP_PARALLEL_COMBINED (finish_omp_parallel (tmp, stmt))
= OMP_PARALLEL_COMBINED (t);
+ pop_omp_privatization_clauses (r);
break;
case OMP_TASK:
- tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false,
+ r = push_omp_privatization_clauses (false);
+ tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, true,
args, complain, in_decl);
stmt = begin_omp_task ();
RECUR (OMP_TASK_BODY (t));
finish_omp_task (tmp, stmt);
+ pop_omp_privatization_clauses (r);
break;
case OMP_FOR:
case CILK_SIMD:
case CILK_FOR:
case OMP_DISTRIBUTE:
+ case OMP_TASKLOOP:
+ case OACC_LOOP:
{
tree clauses, body, pre_body;
tree declv = NULL_TREE, initv = NULL_TREE, condv = NULL_TREE;
+ tree orig_declv = NULL_TREE;
tree incrv = NULL_TREE;
int i;
+ r = push_omp_privatization_clauses (OMP_FOR_INIT (t) == NULL_TREE);
clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false,
+ TREE_CODE (t) != OACC_LOOP,
args, complain, in_decl);
if (OMP_FOR_INIT (t) != NULL_TREE)
{
declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
+ if (OMP_FOR_ORIG_DECLS (t))
+ orig_declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
if (OMP_FOR_INIT (t) != NULL_TREE)
for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
- tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv,
- &clauses, args, complain, in_decl,
+ tsubst_omp_for_iterator (t, i, declv, orig_declv, initv, condv,
+ incrv, &clauses, args, complain, in_decl,
integral_constant_expression_p);
+ omp_parallel_combined_clauses = NULL;
body = push_stmt_list ();
RECUR (OMP_FOR_BODY (t));
body = pop_stmt_list (body);
if (OMP_FOR_INIT (t) != NULL_TREE)
- t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, initv,
- condv, incrv, body, pre_body, clauses);
+ t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv,
+ orig_declv, initv, condv, incrv, body, pre_body,
+ NULL, clauses);
else
{
t = make_node (TREE_CODE (t));
}
add_stmt (finish_omp_structured_block (stmt));
+ pop_omp_privatization_clauses (r);
}
break;
case OMP_SECTIONS:
+ omp_parallel_combined_clauses = NULL;
+ /* FALLTHRU */
case OMP_SINGLE:
case OMP_TEAMS:
- tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false,
+ case OMP_CRITICAL:
+ r = push_omp_privatization_clauses (TREE_CODE (t) == OMP_TEAMS
+ && OMP_TEAMS_COMBINED (t));
+ tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, true,
args, complain, in_decl);
stmt = push_stmt_list ();
RECUR (OMP_BODY (t));
OMP_BODY (t) = stmt;
OMP_CLAUSES (t) = tmp;
add_stmt (t);
+ pop_omp_privatization_clauses (r);
break;
+ case OACC_DATA:
case OMP_TARGET_DATA:
case OMP_TARGET:
tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false,
+ TREE_CODE (t) != OACC_DATA,
args, complain, in_decl);
keep_next_level (true);
stmt = begin_omp_structured_block ();
t = copy_node (t);
OMP_BODY (t) = stmt;
OMP_CLAUSES (t) = tmp;
+ if (TREE_CODE (t) == OMP_TARGET && OMP_TARGET_COMBINED (t))
+ {
+ tree teams = cp_walk_tree (&stmt, tsubst_find_omp_teams, NULL, NULL);
+ if (teams)
+ {
+ /* For combined target teams, ensure the num_teams and
+ thread_limit clause expressions are evaluated on the host,
+ before entering the target construct. */
+ tree c;
+ for (c = OMP_TEAMS_CLAUSES (teams);
+ c; c = OMP_CLAUSE_CHAIN (c))
+ if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREAD_LIMIT)
+ && TREE_CODE (OMP_CLAUSE_OPERAND (c, 0)) != INTEGER_CST)
+ {
+ tree expr = OMP_CLAUSE_OPERAND (c, 0);
+ expr = force_target_expr (TREE_TYPE (expr), expr, tf_none);
+ if (expr == error_mark_node)
+ continue;
+ tmp = TARGET_EXPR_SLOT (expr);
+ add_stmt (expr);
+ OMP_CLAUSE_OPERAND (c, 0) = expr;
+ tree tc = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+ OMP_CLAUSE_FIRSTPRIVATE);
+ OMP_CLAUSE_DECL (tc) = tmp;
+ OMP_CLAUSE_CHAIN (tc) = OMP_TARGET_CLAUSES (t);
+ OMP_TARGET_CLAUSES (t) = tc;
+ }
+ }
+ }
+ add_stmt (t);
+ break;
+
+ case OACC_DECLARE:
+ t = copy_node (t);
+ tmp = tsubst_omp_clauses (OACC_DECLARE_CLAUSES (t), false, false,
+ args, complain, in_decl);
+ OACC_DECLARE_CLAUSES (t) = tmp;
add_stmt (t);
break;
case OMP_TARGET_UPDATE:
- tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false,
+ case OMP_TARGET_ENTER_DATA:
+ case OMP_TARGET_EXIT_DATA:
+ tmp = tsubst_omp_clauses (OMP_STANDALONE_CLAUSES (t), false, true,
+ args, complain, in_decl);
+ t = copy_node (t);
+ OMP_STANDALONE_CLAUSES (t) = tmp;
+ add_stmt (t);
+ break;
+
+ case OACC_ENTER_DATA:
+ case OACC_EXIT_DATA:
+ case OACC_UPDATE:
+ tmp = tsubst_omp_clauses (OMP_STANDALONE_CLAUSES (t), false, false,
args, complain, in_decl);
t = copy_node (t);
- OMP_TARGET_UPDATE_CLAUSES (t) = tmp;
+ OMP_STANDALONE_CLAUSES (t) = tmp;
+ add_stmt (t);
+ break;
+
+ case OMP_ORDERED:
+ tmp = tsubst_omp_clauses (OMP_ORDERED_CLAUSES (t), false, true,
+ args, complain, in_decl);
+ stmt = push_stmt_list ();
+ RECUR (OMP_BODY (t));
+ stmt = pop_stmt_list (stmt);
+
+ t = copy_node (t);
+ OMP_BODY (t) = stmt;
+ OMP_ORDERED_CLAUSES (t) = tmp;
add_stmt (t);
break;
case OMP_SECTION:
- case OMP_CRITICAL:
case OMP_MASTER:
case OMP_TASKGROUP:
- case OMP_ORDERED:
stmt = push_stmt_list ();
RECUR (OMP_BODY (t));
stmt = pop_stmt_list (stmt);
DEDUCE_CALL:
We are deducing arguments for a function call, as in
- [temp.deduct.call].
+ [temp.deduct.call]. If RETURN_TYPE is non-null, we are
+ deducing arguments for a call to the result of a conversion
+ function template, as in [over.call.object].
DEDUCE_CONV:
We are deducing arguments for a conversion function, as in
/* Never do unification on the 'this' parameter. */
parms = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (fntype));
- if (return_type)
+ if (return_type && strict == DEDUCE_CALL)
+ {
+ /* We're deducing for a call to the result of a template conversion
+ function. The parms we really want are in return_type. */
+ if (POINTER_TYPE_P (return_type))
+ return_type = TREE_TYPE (return_type);
+ parms = TYPE_ARG_TYPES (return_type);
+ }
+ else if (return_type)
{
tree *new_args;
if (saw_undeduced++ == 1)
goto again;
}
-#ifdef ENABLE_CHECKING
- if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
+
+ if (CHECKING_P && !NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, TREE_VEC_LENGTH (targs));
-#endif
return unify_success (explain_p);
}
explain_p, &t);
if (!t)
- return unify_no_common_base (explain_p, r, parm, arg);
+ {
+ /* Don't give the derived diagnostic if we're
+ already dealing with the same template. */
+ bool same_template
+ = (CLASSTYPE_TEMPLATE_INFO (arg)
+ && (CLASSTYPE_TI_TEMPLATE (parm)
+ == CLASSTYPE_TI_TEMPLATE (arg)));
+ return unify_no_common_base (explain_p && !same_template,
+ r, parm, arg);
+ }
}
}
else if (CLASSTYPE_TEMPLATE_INFO (arg)
bool external_p;
bool deleted_p;
tree fn_context;
- bool nested;
+ bool nested = false;
/* This function should only be used to instantiate templates for
functions and static member variables. */
fn_context = decl_function_context (d);
nested = (current_function_decl != NULL_TREE);
+ vec<tree> omp_privatization_save;
+ if (nested)
+ save_omp_privatization_clauses (omp_privatization_save);
+
if (!fn_context)
push_to_top_level ();
else
c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings;
pop_deferring_access_checks ();
pop_tinst_level ();
+ if (nested)
+ restore_omp_privatization_clauses (omp_privatization_save);
timevar_pop (TV_TEMPLATE_INST);
}
/* Returns TRUE if OMP_FOR with DECLV, INITV, CONDV and INCRV vectors
- is dependent. */
+ are dependent. */
bool
dependent_omp_for_p (tree declv, tree initv, tree condv, tree incrv)
tree cond = TREE_VEC_ELT (condv, i);
tree incr = TREE_VEC_ELT (incrv, i);
- if (type_dependent_expression_p (decl))
+ if (type_dependent_expression_p (decl)
+ || TREE_CODE (decl) == SCOPE_REF)
return true;
if (init && type_dependent_expression_p (init))
{
tree inner_expr;
-#ifdef ENABLE_CHECKING
/* Try to get a constant value for all non-dependent expressions in
order to expose bugs in *_dependent_expression_p and constexpr. */
- if (cxx_dialect >= cxx11)
+ if (flag_checking && cxx_dialect >= cxx11)
fold_non_dependent_expr (expr);
-#endif
/* Preserve OVERLOADs; the functions must be available to resolve
types. */
return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
}
+/* Hash traits for hashing possibly constrained 'auto'
+ TEMPLATE_TYPE_PARMs for use by do_auto_deduction. */
+
+struct auto_hash : default_hash_traits<tree>
+{
+ static inline hashval_t hash (tree);
+ static inline bool equal (tree, tree);
+};
+
+/* Hash the 'auto' T. */
+
+inline hashval_t
+auto_hash::hash (tree t)
+{
+ if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t))
+ /* Matching constrained-type-specifiers denote the same template
+ parameter, so hash the constraint. */
+ return hash_placeholder_constraint (c);
+ else
+ /* But unconstrained autos are all separate, so just hash the pointer. */
+ return iterative_hash_object (t, 0);
+}
+
+/* Compare two 'auto's. */
+
+inline bool
+auto_hash::equal (tree t1, tree t2)
+{
+ if (t1 == t2)
+ return true;
+
+ tree c1 = PLACEHOLDER_TYPE_CONSTRAINTS (t1);
+ tree c2 = PLACEHOLDER_TYPE_CONSTRAINTS (t2);
+
+ /* Two unconstrained autos are distinct. */
+ if (!c1 || !c2)
+ return false;
+
+ return equivalent_placeholder_constraints (c1, c2);
+}
+
+/* for_each_template_parm callback for extract_autos: if t is a (possibly
+ constrained) auto, add it to the vector. */
+
+static int
+extract_autos_r (tree t, void *data)
+{
+ hash_table<auto_hash> &hash = *(hash_table<auto_hash>*)data;
+ if (is_auto_or_concept (t))
+ {
+ /* All the autos were built with index 0; fix that up now. */
+ tree *p = hash.find_slot (t, INSERT);
+ unsigned idx;
+ if (*p)
+ /* If this is a repeated constrained-type-specifier, use the index we
+ chose before. */
+ idx = TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (*p));
+ else
+ {
+ /* Otherwise this is new, so use the current count. */
+ *p = t;
+ idx = hash.elements () - 1;
+ }
+ TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (t)) = idx;
+ }
+
+ /* Always keep walking. */
+ return 0;
+}
+
+/* Return a TREE_VEC of the 'auto's used in type under the Concepts TS, which
+ says they can appear anywhere in the type. */
+
+static tree
+extract_autos (tree type)
+{
+ hash_set<tree> visited;
+ hash_table<auto_hash> hash (2);
+
+ for_each_template_parm (type, extract_autos_r, &hash, &visited, true);
+
+ tree tree_vec = make_tree_vec (hash.elements());
+ for (hash_table<auto_hash>::iterator iter = hash.begin();
+ iter != hash.end(); ++iter)
+ {
+ tree elt = *iter;
+ unsigned i = TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (elt));
+ TREE_VEC_ELT (tree_vec, i)
+ = build_tree_list (NULL_TREE, TYPE_NAME (elt));
+ }
+
+ return tree_vec;
+}
+
/* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. */
init = resolve_nondeduced_context (init);
- targs = make_tree_vec (1);
if (AUTO_IS_DECLTYPE (auto_node))
{
bool id = (DECL_P (init) || (TREE_CODE (init) == COMPONENT_REF
&& !REF_PARENTHESIZED_P (init)));
+ targs = make_tree_vec (1);
TREE_VEC_ELT (targs, 0)
= finish_decltype_type (init, id, tf_warning_or_error);
if (type != auto_node)
else
{
tree parms = build_tree_list (NULL_TREE, type);
- tree tparms = make_tree_vec (1);
- int val;
-
- TREE_VEC_ELT (tparms, 0)
- = build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
- val = type_unification_real (tparms, targs, parms, &init, 1, 0,
- DEDUCE_CALL, LOOKUP_NORMAL,
- NULL, /*explain_p=*/false);
+ tree tparms;
+
+ if (flag_concepts)
+ tparms = extract_autos (type);
+ else
+ {
+ tparms = make_tree_vec (1);
+ TREE_VEC_ELT (tparms, 0)
+ = build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
+ }
+
+ targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
+ int val = type_unification_real (tparms, targs, parms, &init, 1, 0,
+ DEDUCE_CALL, LOOKUP_NORMAL,
+ NULL, /*explain_p=*/false);
if (val > 0)
{
if (processing_template_decl)
error ("unable to deduce lambda return type from %qE", init);
else
error ("unable to deduce %qT from %qE", type, init);
+ type_unification_real (tparms, targs, parms, &init, 1, 0,
+ DEDUCE_CALL, LOOKUP_NORMAL,
+ NULL, /*explain_p=*/true);
}
return error_mark_node;
}
of each declared variable is determined as described above. If the
type deduced for the template parameter U is not the same in each
deduction, the program is ill-formed. */
- if (TREE_TYPE (auto_node)
+ if (!flag_concepts && TREE_TYPE (auto_node)
&& !same_type_p (TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)))
{
if (cfun && auto_node == current_function_auto_return_pattern
auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0));
return error_mark_node;
}
- if (context != adc_requirement)
+ if (!flag_concepts)
TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0);
/* Check any placeholder constraints against the deduced type. */
return false;
}
+/* for_each_template_parm callback for type_uses_auto. */
+
+int
+is_auto_r (tree tp, void */*data*/)
+{
+ return is_auto_or_concept (tp);
+}
+
/* Returns the TEMPLATE_TYPE_PARM in TYPE representing `auto' iff TYPE contains
a use of `auto'. Returns NULL_TREE otherwise. */
tree
type_uses_auto (tree type)
{
- return find_type_usage (type, is_auto);
+ if (flag_concepts)
+ {
+ /* The Concepts TS allows multiple autos in one type-specifier; just
+ return the first one we find, do_auto_deduction will collect all of
+ them. */
+ if (uses_template_parms (type))
+ return for_each_template_parm (type, is_auto_r, /*data*/NULL,
+ /*visited*/NULL, /*nondeduced*/true);
+ else
+ return NULL_TREE;
+ }
+ else
+ return find_type_usage (type, is_auto);
}
/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto',