/* Handle parameterized types (templates) for GNU -*- C++ -*-.
- Copyright (C) 1992-2015 Free Software Foundation, Inc.
+ Copyright (C) 1992-2016 Free Software Foundation, Inc.
Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing.
Rewritten by Jason Merrill (jason@cygnus.com).
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
#include "cp-tree.h"
-#include "c-family/c-common.h"
#include "timevar.h"
#include "stringpool.h"
#include "varasm.h"
#include "attribs.h"
#include "stor-layout.h"
#include "intl.h"
-#include "flags.h"
#include "c-family/c-objc.h"
#include "cp-objcp-common.h"
-#include "tree-inline.h"
-#include "decl.h"
#include "toplev.h"
#include "tree-iterator.h"
#include "type-utils.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);
static void template_parm_level_and_index (tree, int*, int*);
static int unify_pack_expansion (tree, tree, tree,
tree, unification_kind_t, bool, bool);
+static tree copy_template_args (tree);
static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
static bool complex_alias_template_p (const_tree tmpl);
+static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
if (!t || t == error_mark_node)
return NULL;
- if (TREE_CODE (t) == NAMESPACE_DECL)
+ if (TREE_CODE (t) == NAMESPACE_DECL
+ || TREE_CODE (t) == PARM_DECL)
return NULL;
if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
{
int depth;
- for (depth = 0;
- type && TREE_CODE (type) != NAMESPACE_DECL;
- type = (TREE_CODE (type) == FUNCTION_DECL)
- ? CP_DECL_CONTEXT (type) : CP_TYPE_CONTEXT (type))
+ for (depth = 0; type && TREE_CODE (type) != NAMESPACE_DECL; )
{
tree tinfo = get_template_info (type);
if (tinfo && PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo))
&& uses_template_parms (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo))))
++depth;
+
+ if (DECL_P (type))
+ type = CP_DECL_CONTEXT (type);
+ else if (LAMBDA_TYPE_P (type))
+ type = LAMBDA_TYPE_EXTRA_SCOPE (type);
+ else
+ type = CP_TYPE_CONTEXT (type);
}
return depth;
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:
if (!current_template_parms)
return NULL_TREE;
+ // The injected-class-name is not a new partial specialization.
+ if (DECL_SELF_REFERENCE_P (TYPE_NAME (type)))
+ return NULL_TREE;
+
// If the constraints are not the same as those of the primary
// then, we can probably create a new specialization.
tree type_constr = current_template_constraints ();
if (type == TREE_TYPE (tmpl))
- if (tree main_constr = get_constraints (tmpl))
+ {
+ tree main_constr = get_constraints (tmpl);
if (equivalent_constraints (type_constr, main_constr))
return NULL_TREE;
+ }
// Also, if there's a pre-existing specialization with matching
// constraints, then this also isn't new.
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))
{
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;
*walk_subtrees = 0;
return NULL_TREE;
+ case DECLTYPE_TYPE:
+ {
+ /* When traversing a DECLTYPE_TYPE_EXPR, we need to set
+ type_pack_expansion_p to false so that any placeholders
+ within the expression don't get marked as parameter packs. */
+ bool type_pack_expansion_p = ppd->type_pack_expansion_p;
+ ppd->type_pack_expansion_p = false;
+ cp_walk_tree (&DECLTYPE_TYPE_EXPR (t), &find_parameter_packs_r,
+ ppd, ppd->visited);
+ ppd->type_pack_expansion_p = type_pack_expansion_p;
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+
default:
return NULL_TREE;
}
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;
class expansion. */
ppd.visited = new hash_set<tree>;
ppd.parameter_packs = ¶meter_packs;
+ ppd.type_pack_expansion_p = true;
+ gcc_assert (TYPE_P (TREE_PURPOSE (arg)));
cp_walk_tree (&TREE_PURPOSE (arg), &find_parameter_packs_r,
&ppd, ppd.visited);
/* Propagate type and const-expression information. */
TREE_TYPE (result) = TREE_TYPE (arg);
TREE_CONSTANT (result) = TREE_CONSTANT (arg);
+ /* Mark this read now, since the expansion might be length 0. */
+ mark_exp_read (arg);
}
else
/* Just use structural equality for these TYPE_PACK_EXPANSIONS;
/* 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;
= TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (maintmpl)));
if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args))
&& (!flag_concepts
- || !subsumes_constraints (current_template_constraints (),
- get_constraints (maintmpl))))
+ || !strictly_subsumes (current_template_constraints (),
+ get_constraints (maintmpl))))
{
if (!flag_concepts)
error ("partial specialization %q+D does not specialize "
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);
as two declarations of the same function, for example. */
if (processing_template_decl
- && !instantiation_dependent_expression_p (expr)
- && potential_constant_expression (expr))
+ && potential_nondependent_constant_expression (expr))
{
processing_template_decl_sentinel s;
expr = instantiate_non_dependent_expr_internal (expr, complain);
return instantiate_non_dependent_expr_sfinae (expr, tf_error);
}
+/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
+ an uninstantiated expression. */
+
+tree
+instantiate_non_dependent_or_null (tree expr)
+{
+ if (expr == NULL_TREE)
+ return NULL_TREE;
+ if (processing_template_decl)
+ {
+ if (!potential_nondependent_constant_expression (expr))
+ expr = NULL_TREE;
+ else
+ {
+ processing_template_decl_sentinel s;
+ expr = instantiate_non_dependent_expr_internal (expr, tf_error);
+ }
+ }
+ return expr;
+}
+
/* True iff T is a specialization of a variable template. */
bool
if (TYPE_REF_OBJ_P (type)
&& has_value_dependent_address (expr))
/* If we want the address and it's value-dependent, don't fold. */;
- else if (!type_unknown_p (expr)
- && processing_template_decl
- && !instantiation_dependent_expression_p (expr)
- && potential_constant_expression (expr))
+ else if (processing_template_decl
+ && potential_nondependent_constant_expression (expr))
non_dep = true;
if (error_operand_p (expr))
return error_mark_node;
/* 14.3.2/5: The null pointer{,-to-member} conversion is applied
to a non-type argument of "nullptr". */
if (expr == nullptr_node && TYPE_PTR_OR_PTRMEM_P (type))
- expr = convert (type, expr);
+ expr = fold_simple (convert (type, expr));
/* In C++11, integral or enumeration non-type template arguments can be
arbitrary constant expressions. Pointer and pointer to
tree canon = strip_typedefs (arg, &removed_attributes);
if (removed_attributes
&& (complain & tf_warning))
- warning (0, "ignoring attributes on template argument %qT", arg);
+ warning (OPT_Wignored_attributes,
+ "ignoring attributes on template argument %qT", arg);
return canon;
}
if (TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (inner))) == FUNCTION_TYPE
&& TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE
+ && 0 < TREE_OPERAND_LENGTH (inner)
&& reject_gcc_builtin (TREE_OPERAND (inner, 0)))
return error_mark_node;
}
}
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;
}
template arguments. Returns 0 otherwise, and updates OLDARG_PTR and
NEWARG_PTR with the offending arguments if they are non-NULL. */
-static int
-comp_template_args_with_info (tree oldargs, tree newargs,
- tree *oldarg_ptr, tree *newarg_ptr)
+int
+comp_template_args (tree oldargs, tree newargs,
+ tree *oldarg_ptr, tree *newarg_ptr)
{
int i;
return 1;
}
-/* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets
- of template arguments. Returns 0 otherwise. */
-
-int
-comp_template_args (tree oldargs, tree newargs)
-{
- return comp_template_args_with_info (oldargs, newargs, NULL, NULL);
-}
-
static void
add_pending_template (tree d)
{
t = start_enum (TYPE_IDENTIFIER (template_type), NULL_TREE,
tsubst (ENUM_UNDERLYING_TYPE (template_type),
arglist, complain, in_decl),
+ tsubst_attributes (TYPE_ATTRIBUTES (template_type),
+ arglist, complain, in_decl),
SCOPED_ENUM_P (template_type), NULL);
if (t == error_mark_node)
tree attributes
= lookup_attribute (tags[ix], TYPE_ATTRIBUTES (template_type));
- if (!attributes)
- ;
- else if (!TREE_CHAIN (attributes) && !TYPE_ATTRIBUTES (t))
- TYPE_ATTRIBUTES (t) = attributes;
- else
+ if (attributes)
TYPE_ATTRIBUTES (t)
= tree_cons (TREE_PURPOSE (attributes),
TREE_VALUE (attributes),
arglist, complain, NULL_TREE);
--processing_template_decl;
TREE_VEC_LENGTH (arglist)++;
+ if (partial_inst_args == error_mark_node)
+ return error_mark_node;
use_partial_inst_tmpl =
/*...and we must not be looking at the partial instantiation
itself. */
return instantiate_template (templ, arglist, complain);
}
+
+/* Construct a TEMPLATE_ID_EXPR for the given variable template TEMPL having
+ TARGS template args, and instantiate it if it's not dependent. */
+
+static tree
+lookup_and_finish_template_variable (tree templ, tree targs,
+ tsubst_flags_t complain)
+{
+ templ = lookup_template_variable (templ, targs);
+ if (!any_dependent_template_arguments_p (targs))
+ {
+ templ = finish_template_variable (templ, complain);
+ mark_used (templ);
+ }
+
+ return convert_from_reference (templ);
+}
+
\f
struct pair_fn_data
{
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;
+ /* A template-id in a TYPENAME_TYPE might be a deduced context after
+ partial instantiation. */
+ 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, bool, tree, tsubst_flags_t, tree);
+static tree tsubst_omp_clauses (tree, enum c_omp_region_type, tree,
+ tsubst_flags_t, tree);
+
+/* Instantiate a single dependent attribute T (a TREE_LIST), and return either
+ T or a new TREE_LIST, possibly a chain in the case of a pack expansion. */
+
+static tree
+tsubst_attribute (tree t, tree *decl_p, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ gcc_assert (ATTR_IS_DEPENDENT (t));
+
+ tree val = TREE_VALUE (t);
+ if (val == NULL_TREE)
+ /* Nothing to do. */;
+ else if ((flag_openmp || flag_openmp_simd || flag_cilkplus)
+ && is_attribute_p ("omp declare simd",
+ get_attribute_name (t)))
+ {
+ tree clauses = TREE_VALUE (val);
+ clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD, args,
+ complain, in_decl);
+ c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
+ clauses = finish_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD);
+ tree parms = DECL_ARGUMENTS (*decl_p);
+ clauses
+ = c_omp_declare_simd_clauses_to_numbers (parms, clauses);
+ if (clauses)
+ val = build_tree_list (NULL_TREE, clauses);
+ else
+ val = NULL_TREE;
+ }
+ /* If the first attribute argument is an identifier, don't
+ pass it through tsubst. Attributes like mode, format,
+ cleanup and several target specific attributes expect it
+ unmodified. */
+ else if (attribute_takes_identifier_p (get_attribute_name (t)))
+ {
+ tree chain
+ = tsubst_expr (TREE_CHAIN (val), args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+ if (chain != TREE_CHAIN (val))
+ val = tree_cons (NULL_TREE, TREE_VALUE (val), chain);
+ }
+ else if (PACK_EXPANSION_P (val))
+ {
+ /* An attribute pack expansion. */
+ tree purp = TREE_PURPOSE (t);
+ tree pack = tsubst_pack_expansion (val, args, complain, in_decl);
+ int len = TREE_VEC_LENGTH (pack);
+ tree list = NULL_TREE;
+ tree *q = &list;
+ for (int i = 0; i < len; ++i)
+ {
+ tree elt = TREE_VEC_ELT (pack, i);
+ *q = build_tree_list (purp, elt);
+ q = &TREE_CHAIN (*q);
+ }
+ return list;
+ }
+ else
+ val = tsubst_expr (val, args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+
+ if (val != TREE_VALUE (t))
+ return build_tree_list (TREE_PURPOSE (t), val);
+ return t;
+}
+
+/* Instantiate any dependent attributes in ATTRIBUTES, returning either it
+ unchanged or a new TREE_LIST chain. */
+
+static tree
+tsubst_attributes (tree attributes, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree last_dep = NULL_TREE;
+
+ for (tree t = attributes; t; t = TREE_CHAIN (t))
+ if (ATTR_IS_DEPENDENT (t))
+ {
+ last_dep = t;
+ attributes = copy_list (attributes);
+ break;
+ }
+
+ if (last_dep)
+ for (tree *p = &attributes; *p; p = &TREE_CHAIN (*p))
+ {
+ tree t = *p;
+ if (ATTR_IS_DEPENDENT (t))
+ {
+ tree subst = tsubst_attribute (t, NULL, args, complain, in_decl);
+ if (subst == t)
+ continue;
+ *p = subst;
+ do
+ p = &TREE_CHAIN (*p);
+ while (*p);
+ *p = TREE_CHAIN (t);
+ }
+ }
+
+ return attributes;
+}
/* Apply any attributes which had to be deferred until instantiation
time. DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes;
{
*p = TREE_CHAIN (t);
TREE_CHAIN (t) = NULL_TREE;
- if ((flag_openmp || flag_openmp_simd || flag_cilkplus)
- && is_attribute_p ("omp declare simd",
- get_attribute_name (t))
- && TREE_VALUE (t))
- {
- tree clauses = TREE_VALUE (TREE_VALUE (t));
- 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, false, true);
- tree parms = DECL_ARGUMENTS (*decl_p);
- clauses
- = c_omp_declare_simd_clauses_to_numbers (parms, clauses);
- if (clauses)
- TREE_VALUE (TREE_VALUE (t)) = clauses;
- else
- TREE_VALUE (t) = NULL_TREE;
- }
- /* If the first attribute argument is an identifier, don't
- pass it through tsubst. Attributes like mode, format,
- cleanup and several target specific attributes expect it
- unmodified. */
- else if (attribute_takes_identifier_p (get_attribute_name (t))
- && TREE_VALUE (t))
- {
- tree chain
- = tsubst_expr (TREE_CHAIN (TREE_VALUE (t)), args, complain,
- in_decl,
- /*integral_constant_expression_p=*/false);
- if (chain != TREE_CHAIN (TREE_VALUE (t)))
- TREE_VALUE (t)
- = tree_cons (NULL_TREE, TREE_VALUE (TREE_VALUE (t)),
- chain);
- }
- else if (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t)))
- {
- /* An attribute pack expansion. */
- tree purp = TREE_PURPOSE (t);
- tree pack = (tsubst_pack_expansion
- (TREE_VALUE (t), args, complain, in_decl));
- int len = TREE_VEC_LENGTH (pack);
- for (int i = 0; i < len; ++i)
- {
- tree elt = TREE_VEC_ELT (pack, i);
- *q = build_tree_list (purp, elt);
- q = &TREE_CHAIN (*q);
- }
- continue;
- }
- else
- TREE_VALUE (t)
- = tsubst_expr (TREE_VALUE (t), args, complain, in_decl,
- /*integral_constant_expression_p=*/false);
- *q = t;
- q = &TREE_CHAIN (t);
+ *q = tsubst_attribute (t, decl_p, args, complain, in_decl);
+ do
+ q = &TREE_CHAIN (*q);
+ while (*q);
}
else
p = &TREE_CHAIN (t);
DECL_SOURCE_LOCATION (typedecl);
TYPE_PACKED (type) = TYPE_PACKED (pattern);
- TYPE_ALIGN (type) = TYPE_ALIGN (pattern);
+ SET_TYPE_ALIGN (type, TYPE_ALIGN (pattern));
TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (pattern);
TYPE_FOR_JAVA (type) = TYPE_FOR_JAVA (pattern); /* For libjava's JArray<T> */
if (ANON_AGGR_TYPE_P (pattern))
if (can_complete_type_without_circularity (rtype))
complete_type (rtype);
- if (!COMPLETE_TYPE_P (rtype))
+ if (TREE_CODE (r) == FIELD_DECL
+ && TREE_CODE (rtype) == ARRAY_TYPE
+ && COMPLETE_TYPE_P (TREE_TYPE (rtype))
+ && !COMPLETE_TYPE_P (rtype))
+ {
+ /* Flexible array mmembers of elements
+ of complete type have an incomplete type
+ and that's okay. */
+ }
+ else if (!COMPLETE_TYPE_P (rtype))
{
cxx_incomplete_type_error (r, rtype);
TREE_TYPE (r) = error_mark_node;
template <class U> friend class T::C;
otherwise. */
+ /* Bump processing_template_decl in case this is something like
+ template <class T> friend struct A<T>::B. */
+ ++processing_template_decl;
friend_type = tsubst (friend_type, args,
tf_warning_or_error, NULL_TREE);
- /* Bump processing_template_decl for correct
- dependent_type_p calculation. */
- ++processing_template_decl;
if (dependent_type_p (friend_type))
adjust_processing_template_decl = true;
--processing_template_decl;
{
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
sequence, the value of the expression is as follows; the program is
ill-formed if the operator is not listed in this table.
- * 1
- + 0
- & -1
- | 0
&& true
|| false
, void() */
if (!FOLD_EXPR_MODIFY_P (t))
switch (code)
{
- case MULT_EXPR:
- return integer_one_node;
- case PLUS_EXPR:
- return integer_zero_node;
- case BIT_AND_EXPR:
- return integer_minus_one_node;
- case BIT_IOR_EXPR:
- return integer_zero_node;
case TRUTH_ANDIF_EXPR:
return boolean_true_node;
case TRUTH_ORIF_EXPR:
if (PACK_EXPANSION_LOCAL_P (t) || CONSTRAINT_VAR_P (parm_pack))
arg_pack = retrieve_local_specialization (parm_pack);
else
+ /* We can't rely on local_specializations for a parameter
+ name used later in a function declaration (such as in a
+ late-specified return type). Even if it exists, it might
+ have the wrong value for a recursive call. */
+ need_local_specializations = true;
+
+ if (!arg_pack)
{
- /* We can't rely on local_specializations for a parameter
- name used later in a function declaration (such as in a
- late-specified return type). Even if it exists, it might
- have the wrong value for a recursive call. Just make a
- dummy decl, since it's only used for its type. */
+ /* This parameter pack was used in an unevaluated context. Just
+ make a dummy decl, since it's only used for its type. */
arg_pack = tsubst_decl (parm_pack, args, complain);
if (arg_pack && DECL_PACK_P (arg_pack))
/* Partial instantiation of the parm_pack, we can't build
arg_pack = NULL_TREE;
else
arg_pack = make_fnparm_pack (arg_pack);
- need_local_specializations = true;
}
}
else if (TREE_CODE (parm_pack) == FIELD_DECL)
/* We can't substitute for this parameter pack. We use a flag as
well as the missing_level counter because function parameter
packs don't have a level. */
+ gcc_assert (processing_template_decl);
unsubstituted_packs = true;
}
}
- /* If the expansion is just T..., return the matching argument pack. */
+ /* If the expansion is just T..., return the matching argument pack, unless
+ we need to call convert_from_reference on all the elements. This is an
+ important optimization; see c++/68422. */
if (!unsubstituted_packs
&& TREE_PURPOSE (packs) == pattern)
{
tree args = ARGUMENT_PACK_ARGS (TREE_VALUE (packs));
+ /* Types need no adjustment, nor does sizeof..., and if we still have
+ some pack expansion args we won't do anything yet. */
if (TREE_CODE (t) == TYPE_PACK_EXPANSION
+ || PACK_EXPANSION_SIZEOF_P (t)
|| pack_expansion_args_count (args))
return args;
+ /* Also optimize expression pack expansions if we can tell that the
+ elements won't have reference type. */
+ tree type = TREE_TYPE (pattern);
+ if (type && TREE_CODE (type) != REFERENCE_TYPE
+ && !PACK_EXPANSION_P (type)
+ && !WILDCARD_TYPE_P (type))
+ return args;
/* Otherwise use the normal path so we get convert_from_reference. */
}
/* For each argument in each argument pack, substitute into the
pattern. */
result = make_tree_vec (len);
+ tree elem_args = copy_template_args (args);
for (i = 0; i < len; ++i)
{
t = gen_elem_of_pack_expansion_instantiation (pattern, packs,
i,
- args, complain,
+ elem_args, complain,
in_decl);
TREE_VEC_ELT (result, i) = t;
if (t == error_mark_node)
return patparm;
}
+/* Make an argument pack out of the TREE_VEC VEC. */
+
+static tree
+make_argument_pack (tree vec)
+{
+ tree pack;
+ tree elt = TREE_VEC_ELT (vec, 0);
+ if (TYPE_P (elt))
+ pack = cxx_make_type (TYPE_ARGUMENT_PACK);
+ else
+ {
+ pack = make_node (NONTYPE_ARGUMENT_PACK);
+ TREE_TYPE (pack) = TREE_TYPE (elt);
+ TREE_CONSTANT (pack) = 1;
+ }
+ SET_ARGUMENT_PACK_ARGS (pack, vec);
+ return pack;
+}
+
+/* Return an exact copy of template args T that can be modified
+ independently. */
+
+static tree
+copy_template_args (tree t)
+{
+ if (t == error_mark_node)
+ return t;
+
+ int len = TREE_VEC_LENGTH (t);
+ tree new_vec = make_tree_vec (len);
+
+ for (int i = 0; i < len; ++i)
+ {
+ tree elt = TREE_VEC_ELT (t, i);
+ if (elt && TREE_CODE (elt) == TREE_VEC)
+ elt = copy_template_args (elt);
+ TREE_VEC_ELT (new_vec, i) = elt;
+ }
+
+ NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_vec)
+ = NON_DEFAULT_TEMPLATE_ARGS_COUNT (t);
+
+ return new_vec;
+}
+
/* Substitute ARGS into the vector or list of template arguments T. */
static tree
if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
{
tree spec;
- bool dependent_p;
- /* If T is not dependent, just return it. We have to
- increment PROCESSING_TEMPLATE_DECL because
- value_dependent_expression_p assumes that nothing is
- dependent when PROCESSING_TEMPLATE_DECL is zero. */
- ++processing_template_decl;
- dependent_p = value_dependent_expression_p (t);
- --processing_template_decl;
- if (!dependent_p)
+ /* If T is not dependent, just return it. */
+ if (!uses_template_parms (DECL_TI_ARGS (t)))
RETURN (t);
/* Calculate the most general template of which R is a
/* The initializer must not be expanded until it is required;
see [temp.inst]. */
DECL_INITIAL (r) = NULL_TREE;
+ if (VAR_P (r))
+ DECL_MODE (r) = VOIDmode;
if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_WRTL))
SET_DECL_RTL (r, NULL);
DECL_SIZE (r) = DECL_SIZE_UNIT (r) = 0;
SET_DECL_IMPLICIT_INSTANTIATION (r);
register_specialization (r, gen_tmpl, argvec, false, hash);
}
- else if (!cp_unevaluated_operand)
- register_local_specialization (r, t);
+ else
+ {
+ if (DECL_LANG_SPECIFIC (r))
+ DECL_TEMPLATE_INFO (r) = NULL_TREE;
+ if (!cp_unevaluated_operand)
+ register_local_specialization (r, t);
+ }
DECL_CHAIN (r) = NULL_TREE;
return t;
if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
- && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
- return t;
+ && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
+ return t;
{
tree max, omax = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
TYPE_POINTER_TO (r) = NULL_TREE;
TYPE_REFERENCE_TO (r) = NULL_TREE;
+ /* Propagate constraints on placeholders. */
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+ if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (t))
+ PLACEHOLDER_TYPE_CONSTRAINTS (r)
+ = tsubst_constraint (constr, args, complain, in_decl);
+
if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM)
/* We have reduced the level of the template
template parameter, but not the levels of its
else
TYPE_CANONICAL (r) = canonical_type_parameter (r);
- /* Propagate constraints on placeholders. */
- if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
- if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (t))
- PLACEHOLDER_TYPE_CONSTRAINTS (r)
- = tsubst_constraint (constr, args, complain, in_decl);
-
if (code == BOUND_TEMPLATE_TEMPLATE_PARM)
{
tree argvec = tsubst (TYPE_TI_ARGS (t), args,
if (TYPE_USER_ALIGN (t))
{
- TYPE_ALIGN (r) = TYPE_ALIGN (t);
+ SET_TYPE_ALIGN (r, TYPE_ALIGN (t));
TYPE_USER_ALIGN (r) = 1;
}
name = mangle_conv_op_name_for_type (optype);
baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
if (!baselink)
- return error_mark_node;
+ {
+ if (constructor_name_p (name, qualifying_scope))
+ {
+ if (complain & tf_error)
+ error ("cannot call constructor %<%T::%D%> directly",
+ qualifying_scope, name);
+ }
+ return error_mark_node;
+ }
/* If lookup found a single function, mark it as used at this
point. (If it lookup found multiple functions the one selected
/* Add back the template arguments, if present. */
if (BASELINK_P (baselink) && template_id_p)
BASELINK_FUNCTIONS (baselink)
- = build_nt (TEMPLATE_ID_EXPR,
- BASELINK_FUNCTIONS (baselink),
- template_args);
+ = build2 (TEMPLATE_ID_EXPR,
+ unknown_type_node,
+ BASELINK_FUNCTIONS (baselink),
+ template_args);
/* Update the conversion operator type. */
BASELINK_OPTYPE (baselink) = optype;
}
if (is_template)
- expr = lookup_template_function (expr, template_args);
+ {
+ if (variable_template_p (expr))
+ expr = lookup_and_finish_template_variable (expr, template_args,
+ complain);
+ else
+ expr = lookup_template_function (expr, template_args);
+ }
if (expr == error_mark_node && complain & tf_error)
qualified_name_lookup_error (scope, TREE_OPERAND (qualified_id, 1),
if (r == NULL_TREE)
{
- /* We get here for a use of 'this' in an NSDMI. */
+ /* We get here for a use of 'this' in an NSDMI as part of a
+ constructor call or as part of an aggregate initialization. */
if (DECL_NAME (t) == this_identifier
- && current_function_decl
- && DECL_CONSTRUCTOR_P (current_function_decl))
+ && ((current_function_decl
+ && DECL_CONSTRUCTOR_P (current_function_decl))
+ || (current_class_ref
+ && TREE_CODE (current_class_ref) == PLACEHOLDER_EXPR)))
return current_class_ptr;
/* This can happen for a parameter name used later in a function
}
case SIZEOF_EXPR:
- if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+ if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))
+ || ARGUMENT_PACK_P (TREE_OPERAND (t, 0)))
{
-
tree expanded, op = TREE_OPERAND (t, 0);
int len = 0;
++cp_unevaluated_operand;
++c_inhibit_evaluation_warnings;
/* We only want to compute the number of arguments. */
- expanded = tsubst_pack_expansion (op, args, complain, in_decl);
+ if (PACK_EXPANSION_P (op))
+ expanded = tsubst_pack_expansion (op, args, complain, in_decl);
+ else
+ expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op),
+ args, complain, in_decl);
--cp_unevaluated_operand;
--c_inhibit_evaluation_warnings;
if (TREE_CODE (expanded) == TREE_VEC)
- len = TREE_VEC_LENGTH (expanded);
+ {
+ len = TREE_VEC_LENGTH (expanded);
+ /* Set TREE_USED for the benefit of -Wunused. */
+ for (int i = 0; i < len; i++)
+ TREE_USED (TREE_VEC_ELT (expanded, i)) = true;
+ }
if (expanded == error_mark_node)
return error_mark_node;
else if (PACK_EXPANSION_P (expanded)
|| (TREE_CODE (expanded) == TREE_VEC
- && len > 0
- && PACK_EXPANSION_P (TREE_VEC_ELT (expanded, len-1))))
+ && pack_expansion_args_count (expanded)))
+
{
- if (TREE_CODE (expanded) == TREE_VEC)
- expanded = TREE_VEC_ELT (expanded, len - 1);
+ if (PACK_EXPANSION_P (expanded))
+ /* OK. */;
+ else if (TREE_VEC_LENGTH (expanded) == 1)
+ expanded = TREE_VEC_ELT (expanded, 0);
+ else
+ expanded = make_argument_pack (expanded);
if (TYPE_P (expanded))
return cxx_sizeof_or_alignof_type (expanded, SIZEOF_EXPR,
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;
}
}
/* Like tsubst_copy, but specifically for OpenMP clauses. */
static tree
-tsubst_omp_clauses (tree clauses, bool declare_simd, bool allow_fields,
+tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
tree args, tsubst_flags_t complain, tree in_decl)
{
tree new_clauses = NULL_TREE, nc, oc;
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);
= 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_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
OMP_CLAUSE_OPERAND (nc, 1)
= tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain,
in_decl, /*integral_constant_expression_p=*/false);
- if (OMP_CLAUSE_CODE (oc) == OMP_CLAUSE_LINEAR
- && OMP_CLAUSE_LINEAR_STEP (oc) == NULL_TREE)
+ 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_DEFAULT:
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)
+ if ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP)
switch (OMP_CLAUSE_CODE (nc))
{
+ case OMP_CLAUSE_SHARED:
case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_LASTPRIVATE:
}
new_clauses = nreverse (new_clauses);
- if (!declare_simd)
+ if (ort != C_ORT_OMP_DECLARE_SIMD)
{
- new_clauses = finish_omp_clauses (new_clauses, allow_fields);
+ new_clauses = finish_omp_clauses (new_clauses, ort);
if (linear_no_step)
for (nc = new_clauses; nc; nc = OMP_CLAUSE_CHAIN (nc))
if (nc == linear_no_step)
&& DECL_NAME (v) == this_identifier)
{
decl = TREE_OPERAND (decl, 1);
- decl = omp_privatize_field (decl);
+ decl = omp_privatize_field (decl, false);
}
/* FALLTHRU */
default:
{
tree c = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
OMP_CLAUSE_DECL (c) = decl;
- c = finish_omp_clauses (c, true);
+ c = finish_omp_clauses (c, C_ORT_OMP);
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. */
{
tree scope = USING_DECL_SCOPE (decl);
tree name = DECL_NAME (decl);
- tree decl;
scope = tsubst (scope, args, complain, in_decl);
decl = lookup_qualified_name (scope, name,
}
break;
+ case OACC_KERNELS:
+ case OACC_PARALLEL:
+ tmp = tsubst_omp_clauses (OMP_CLAUSES (t), C_ORT_ACC, args, complain,
+ in_decl);
+ stmt = begin_omp_parallel ();
+ RECUR (OMP_BODY (t));
+ finish_omp_construct (TREE_CODE (t), stmt, tmp);
+ break;
+
case OMP_PARALLEL:
r = push_omp_privatization_clauses (OMP_PARALLEL_COMBINED (t));
- tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, true,
- args, complain, in_decl);
+ tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), C_ORT_OMP, args,
+ complain, in_decl);
if (OMP_PARALLEL_COMBINED (t))
omp_parallel_combined_clauses = &tmp;
stmt = begin_omp_parallel ();
case OMP_TASK:
r = push_omp_privatization_clauses (false);
- tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, true,
- args, complain, in_decl);
+ tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), C_ORT_OMP, args,
+ complain, in_decl);
stmt = begin_omp_task ();
RECUR (OMP_TASK_BODY (t));
finish_omp_task (tmp, stmt);
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;
+ enum c_omp_region_type ort = C_ORT_OMP;
int i;
+ if (TREE_CODE (t) == CILK_SIMD || TREE_CODE (t) == CILK_FOR)
+ ort = C_ORT_CILK;
+ else if (TREE_CODE (t) == OACC_LOOP)
+ ort = C_ORT_ACC;
+
r = push_omp_privatization_clauses (OMP_FOR_INIT (t) == NULL_TREE);
- clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, true,
- args, complain, in_decl);
+ clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), ort, args, complain,
+ in_decl);
if (OMP_FOR_INIT (t) != NULL_TREE)
{
declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
- if (TREE_CODE (t) == OMP_FOR && OMP_FOR_ORIG_DECLS (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)));
if (OMP_FOR_INIT (t) != NULL_TREE)
t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv,
orig_declv, initv, condv, incrv, body, pre_body,
- clauses);
+ NULL, clauses);
else
{
t = make_node (TREE_CODE (t));
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);
+ tmp = tsubst_omp_clauses (OMP_CLAUSES (t), C_ORT_OMP, args, complain,
+ in_decl);
stmt = push_stmt_list ();
RECUR (OMP_BODY (t));
stmt = pop_stmt_list (stmt);
pop_omp_privatization_clauses (r);
break;
+ case OACC_DATA:
case OMP_TARGET_DATA:
case OMP_TARGET:
- tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, true,
- args, complain, in_decl);
+ tmp = tsubst_omp_clauses (OMP_CLAUSES (t), (TREE_CODE (t) == OACC_DATA)
+ ? C_ORT_ACC : C_ORT_OMP, 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), C_ORT_ACC, args,
+ complain, in_decl);
+ OACC_DECLARE_CLAUSES (t) = tmp;
add_stmt (t);
break;
case OMP_TARGET_UPDATE:
case OMP_TARGET_ENTER_DATA:
case OMP_TARGET_EXIT_DATA:
- tmp = tsubst_omp_clauses (OMP_STANDALONE_CLAUSES (t), false, true,
- args, complain, in_decl);
+ tmp = tsubst_omp_clauses (OMP_STANDALONE_CLAUSES (t), C_ORT_OMP, 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), C_ORT_ACC, args,
+ complain, in_decl);
t = copy_node (t);
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);
+ tmp = tsubst_omp_clauses (OMP_ORDERED_CLAUSES (t), C_ORT_OMP, args,
+ complain, in_decl);
stmt = push_stmt_list ();
RECUR (OMP_BODY (t));
stmt = pop_stmt_list (stmt);
return error_mark_node;
if (variable_template_p (templ))
- {
- templ = lookup_template_variable (templ, targs);
- if (!any_dependent_template_arguments_p (targs))
- {
- templ = finish_template_variable (templ, complain);
- mark_used (templ);
- }
- RETURN (convert_from_reference (templ));
- }
+ RETURN (lookup_and_finish_template_variable (templ, targs, complain));
if (TREE_CODE (templ) == COMPONENT_REF)
{
else
r = build_x_indirect_ref (input_location, r, RO_UNARY_STAR,
complain|decltype_flag);
+
+ if (TREE_CODE (r) == INDIRECT_REF)
+ REF_PARENTHESIZED_P (r) = REF_PARENTHESIZED_P (t);
+
RETURN (r);
}
length, stride, TREE_TYPE (op1)));
}
case SIZEOF_EXPR:
- if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+ if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))
+ || ARGUMENT_PACK_P (TREE_OPERAND (t, 0)))
RETURN (tsubst_copy (t, args, complain, in_decl));
/* Fall through */
else
gcc_unreachable ();
LAMBDA_EXPR_EXTRA_SCOPE (r) = scope;
- LAMBDA_EXPR_RETURN_TYPE (r)
- = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl);
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
&& LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
declaration of the op() for later calls to lambda_function. */
complete_type (type);
+ if (tree fn = lambda_function (type))
+ LAMBDA_EXPR_RETURN_TYPE (r) = TREE_TYPE (TREE_TYPE (fn));
+
LAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;
insert_pending_capture_proxies ();
/* Check to see if we already have this specialization. */
gen_tmpl = most_general_template (tmpl);
- if (tmpl != gen_tmpl)
- /* The TMPL is a partial instantiation. To get a full set of
- arguments we must add the arguments used to perform the
- partial instantiation. */
- targ_ptr = add_outermost_template_args (DECL_TI_ARGS (tmpl),
- targ_ptr);
+ if (TMPL_ARGS_DEPTH (targ_ptr)
+ < TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (gen_tmpl)))
+ /* targ_ptr only has the innermost template args, so add the outer ones
+ from tmpl, which could be either a partial instantiation or gen_tmpl (in
+ the case of a non-dependent call within a template definition). */
+ targ_ptr = (add_outermost_template_args
+ (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (tmpl)),
+ targ_ptr));
/* It would be nice to avoid hashing here and then again in tsubst_decl,
but it doesn't seem to be on the hot path. */
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);
}
lvalue for the function template specialization. */
tree
-resolve_nondeduced_context (tree orig_expr)
+resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain)
{
tree expr, offset, baselink;
bool addr;
{
tree base
= TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (offset, 0)));
- expr = build_offset_ref (base, expr, addr, tf_warning_or_error);
+ expr = build_offset_ref (base, expr, addr, complain);
}
if (addr)
- expr = cp_build_addr_expr (expr, tf_warning_or_error);
+ expr = cp_build_addr_expr (expr, complain);
return expr;
}
- else if (good == 0 && badargs)
+ else if (good == 0 && badargs && (complain & tf_error))
/* There were no good options and at least one bad one, so let the
user know what the problem is. */
- instantiate_template (badfn, badargs, tf_warning_or_error);
+ instantiate_template (badfn, badargs, complain);
}
return orig_expr;
}
template args used in the function parm list with our own
template parms. Discard them. */
TREE_VEC_ELT (tempargs, i) = NULL_TREE;
+ else if (oldelt && ARGUMENT_PACK_P (oldelt))
+ {
+ /* Check that the argument at each index of the deduced argument pack
+ is equivalent to the corresponding explicitly specified argument.
+ We may have deduced more arguments than were explicitly specified,
+ and that's OK. */
+ gcc_assert (ARGUMENT_PACK_INCOMPLETE_P (oldelt));
+ gcc_assert (ARGUMENT_PACK_ARGS (oldelt)
+ == ARGUMENT_PACK_EXPLICIT_ARGS (oldelt));
+
+ tree explicit_pack = ARGUMENT_PACK_ARGS (oldelt);
+ tree deduced_pack = ARGUMENT_PACK_ARGS (elt);
+
+ if (TREE_VEC_LENGTH (deduced_pack)
+ < TREE_VEC_LENGTH (explicit_pack))
+ return 0;
+
+ for (int j = 0; j < TREE_VEC_LENGTH (explicit_pack); j++)
+ if (!template_args_equal (TREE_VEC_ELT (explicit_pack, j),
+ TREE_VEC_ELT (deduced_pack, j)))
+ return 0;
+ }
else if (oldelt && !template_args_equal (oldelt, elt))
return 0;
}
tree bad_old_arg = NULL_TREE, bad_new_arg = NULL_TREE;
tree old_args = ARGUMENT_PACK_ARGS (old_pack);
- if (!comp_template_args_with_info (old_args, new_args,
- &bad_old_arg, &bad_new_arg))
+ if (!comp_template_args (old_args, new_args,
+ &bad_old_arg, &bad_new_arg))
/* Inconsistent unification of this parameter pack. */
return unify_parameter_pack_inconsistent (explain_p,
bad_old_arg,
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)
return unify_template_argument_mismatch (explain_p, parm, arg);
case VAR_DECL:
- /* A non-type template parameter that is a variable should be a
- an integral constant, in which case, it whould have been
- folded into its (constant) value. So we should not be getting
- a variable here. */
- gcc_unreachable ();
+ /* We might get a variable as a non-type template argument in parm if the
+ corresponding parameter is type-dependent. Make any necessary
+ adjustments based on whether arg is a reference. */
+ if (CONSTANT_CLASS_P (arg))
+ parm = fold_non_dependent_expr (parm);
+ else if (REFERENCE_REF_P (arg))
+ {
+ tree sub = TREE_OPERAND (arg, 0);
+ STRIP_NOPS (sub);
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ arg = TREE_OPERAND (sub, 0);
+ }
+ /* Now use the normal expression code to check whether they match. */
+ goto expr;
case TYPE_ARGUMENT_PACK:
case NONTYPE_ARGUMENT_PACK:
if (is_overloaded_fn (parm) || type_unknown_p (parm))
return unify_success (explain_p);
gcc_assert (EXPR_P (parm));
-
+ expr:
/* We must be looking at an expression. This can happen with
something like:
if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION)
{
- int i, len2 = list_length (args2);
+ int i, len2 = remaining_arguments (args2);
tree parmvec = make_tree_vec (1);
tree argvec = make_tree_vec (len2);
tree ta = args2;
}
else if (TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
{
- int i, len1 = list_length (args1);
+ int i, len1 = remaining_arguments (args1);
tree parmvec = make_tree_vec (1);
tree argvec = make_tree_vec (len1);
tree ta = args1;
return decl;
}
+/* True iff the TEMPLATE_DECL tmpl is a partial specialization. */
+
+static bool
+partial_specialization_p (tree tmpl)
+{
+ /* Any specialization has DECL_TEMPLATE_SPECIALIZATION. */
+ if (!DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ return false;
+ tree t = DECL_TI_TEMPLATE (tmpl);
+ /* A specialization that fully specializes one of the containing classes is
+ not a partial specialization. */
+ return (list_length (DECL_TEMPLATE_PARMS (tmpl))
+ == list_length (DECL_TEMPLATE_PARMS (t)));
+}
+
+/* If TMPL is a partial specialization, return the arguments for its primary
+ template. */
+
+static tree
+impartial_args (tree tmpl, tree args)
+{
+ if (!partial_specialization_p (tmpl))
+ return args;
+
+ /* If TMPL is a partial specialization, we need to substitute to get
+ the args for the primary template. */
+ return tsubst_template_args (DECL_TI_ARGS (tmpl), args,
+ tf_warning_or_error, tmpl);
+}
+
/* Return the most specialized of the template partial specializations
which can produce TARGET, a specialization of some class or variable
template. The value returned is actually a TREE_LIST; the TREE_VALUE is
return d;
gen_tmpl = most_general_template (tmpl);
- gen_args = DECL_TI_ARGS (d);
+ gen_args = impartial_args (tmpl, DECL_TI_ARGS (d));
if (tmpl != gen_tmpl)
/* We should already have the extra args. */
if (TREE_CODE (d) == FUNCTION_DECL)
{
deleted_p = DECL_DELETED_FN (code_pattern);
- pattern_defined = (DECL_SAVED_TREE (code_pattern) != NULL_TREE
+ pattern_defined = ((DECL_SAVED_TREE (code_pattern) != NULL_TREE
+ && DECL_INITIAL (code_pattern) != error_mark_node)
|| DECL_DEFAULTED_OUTSIDE_CLASS_P (code_pattern)
|| deleted_p);
}
if (enter_context)
pop_nested_class ();
- if (variable_template_p (td))
+ if (variable_template_p (gen_tmpl))
note_variable_template_instantiation (d);
}
else if (TREE_CODE (d) == FUNCTION_DECL && DECL_DEFAULTED_FN (code_pattern))
switch (TREE_CODE (expression))
{
+ case BASELINK:
+ /* A dependent member function of the current instantiation. */
+ return dependent_type_p (BINFO_TYPE (BASELINK_BINFO (expression)));
+
+ case FUNCTION_DECL:
+ /* A dependent member function of the current instantiation. */
+ if (DECL_CLASS_SCOPE_P (expression)
+ && dependent_type_p (DECL_CONTEXT (expression)))
+ return true;
+ break;
+
case IDENTIFIER_NODE:
/* A name that has not been looked up -- must be dependent. */
return true;
&& (TREE_CODE (DECL_INITIAL (expression)) == TREE_LIST
/* cp_finish_decl doesn't fold reference initializers. */
|| TREE_CODE (TREE_TYPE (expression)) == REFERENCE_TYPE
+ || type_dependent_expression_p (DECL_INITIAL (expression))
|| value_dependent_expression_p (DECL_INITIAL (expression))))
return true;
return false;
return true;
else if (TYPE_P (expression))
return dependent_type_p (expression);
- return instantiation_dependent_expression_p (expression);
+ return instantiation_dependent_uneval_expression_p (expression);
case AT_ENCODE_EXPR:
/* An 'encode' expression is value-dependent if the operand is
case NOEXCEPT_EXPR:
expression = TREE_OPERAND (expression, 0);
- return instantiation_dependent_expression_p (expression);
+ return instantiation_dependent_uneval_expression_p (expression);
case SCOPE_REF:
/* All instantiation-dependent expressions should also be considered
case CALL_EXPR:
{
+ if (value_dependent_expression_p (CALL_EXPR_FN (expression)))
+ return true;
tree fn = get_callee_fndecl (expression);
int i, nargs;
- if (!fn && value_dependent_expression_p (CALL_EXPR_FN (expression)))
- return true;
nargs = call_expr_nargs (expression);
for (i = 0; i < nargs; ++i)
{
|| dependent_scope_p (scope));
}
- if (TREE_CODE (expression) == FUNCTION_DECL
- && DECL_LANG_SPECIFIC (expression)
- && DECL_TEMPLATE_INFO (expression)
- && (any_dependent_template_arguments_p
- (INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
- return true;
-
if (TREE_CODE (expression) == TEMPLATE_DECL
&& !DECL_TEMPLATE_TEMPLATE_PARM_P (expression))
return false;
&& DECL_INITIAL (expression))
return true;
- /* A variable template specialization is type-dependent if it has any
- dependent template arguments. */
- if (VAR_P (expression)
+ /* A function or variable template-id is type-dependent if it has any
+ dependent template arguments. Note that we only consider the innermost
+ template arguments here, since those are the ones that come from the
+ template-id; the template arguments for the enclosing class do not make it
+ type-dependent, they only make a member function value-dependent. */
+ if (VAR_OR_FUNCTION_DECL_P (expression)
&& DECL_LANG_SPECIFIC (expression)
&& DECL_TEMPLATE_INFO (expression)
- && variable_template_p (DECL_TI_TEMPLATE (expression)))
- return any_dependent_template_arguments_p (DECL_TI_ARGS (expression));
+ && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (expression))
+ && (any_dependent_template_arguments_p
+ (INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
+ return true;
/* Always dependent, on the number of arguments if nothing else. */
if (TREE_CODE (expression) == EXPR_PACK_EXPANSION)
return (dependent_type_p (TREE_TYPE (expression)));
}
+/* [temp.dep.expr]/5: A class member access expression (5.2.5) is
+ type-dependent if the expression refers to a member of the current
+ instantiation and the type of the referenced member is dependent, or the
+ class member access expression refers to a member of an unknown
+ specialization.
+
+ This function returns true if the OBJECT in such a class member access
+ expression is of an unknown specialization. */
+
+bool
+type_dependent_object_expression_p (tree object)
+{
+ tree scope = TREE_TYPE (object);
+ return (!scope || dependent_scope_p (scope));
+}
+
/* walk_tree callback function for instantiation_dependent_expression_p,
below. Returns non-zero if a dependent subexpression is found. */
case TREE_VEC:
return NULL_TREE;
- case VAR_DECL:
- case CONST_DECL:
- /* A constant with a dependent initializer is dependent. */
- if (value_dependent_expression_p (*tp))
- return *tp;
- break;
-
case TEMPLATE_PARM_INDEX:
return *tp;
break;
}
- case TRAIT_EXPR:
- if (value_dependent_expression_p (*tp))
- return *tp;
- *walk_subtrees = false;
- return NULL_TREE;
-
case COMPONENT_REF:
if (identifier_p (TREE_OPERAND (*tp, 1)))
/* In a template, finish_class_member_access_expr creates a
"An expression is instantiation-dependent if it is type-dependent
or value-dependent, or it has a subexpression that is type-dependent
- or value-dependent." */
+ or value-dependent."
+
+ Except don't actually check value-dependence for unevaluated expressions,
+ because in sizeof(i) we don't care about the value of i. Checking
+ type-dependence will in turn check value-dependence of array bounds/template
+ arguments as needed. */
bool
-instantiation_dependent_expression_p (tree expression)
+instantiation_dependent_uneval_expression_p (tree expression)
{
tree result;
return result != NULL_TREE;
}
+/* As above, but also check value-dependence of the expression as a whole. */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+ return (instantiation_dependent_uneval_expression_p (expression)
+ || value_dependent_expression_p (expression));
+}
+
/* Like type_dependent_expression_p, but it also works while not processing
a template definition, i.e. during substitution or mangling. */
if (TREE_CODE (arg) == ARGUMENT_PACK_SELECT)
arg = ARGUMENT_PACK_SELECT_ARG (arg);
- if (TREE_CODE (arg) == TEMPLATE_DECL
- || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
- return dependent_template_p (arg);
+ if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+ return true;
+ if (TREE_CODE (arg) == TEMPLATE_DECL)
+ {
+ if (DECL_TEMPLATE_PARM_P (arg))
+ return true;
+ /* A member template of a dependent class is not necessarily
+ type-dependent, but it is a dependent template argument because it
+ will be a member of an unknown specialization to that template. */
+ tree scope = CP_DECL_CONTEXT (arg);
+ return TYPE_P (scope) && dependent_type_p (scope);
+ }
else if (ARGUMENT_PACK_P (arg))
{
tree args = ARGUMENT_PACK_ARGS (arg);
return false;
}
-/* Returns TRUE if the template TMPL is dependent. */
+/* Returns TRUE if the template TMPL is type-dependent. */
bool
dependent_template_p (tree tmpl)
/* So are names that have not been looked up. */
if (TREE_CODE (tmpl) == SCOPE_REF || identifier_p (tmpl))
return true;
- /* So are member templates of dependent classes. */
- if (TYPE_P (CP_DECL_CONTEXT (tmpl)))
- return dependent_type_p (DECL_CONTEXT (tmpl));
return false;
}
{
/* Ill-formed programs can cause infinite recursion here, so we
must catch that. */
- TYPENAME_IS_RESOLVING_P (type) = 1;
+ TYPENAME_IS_RESOLVING_P (result) = 1;
result = resolve_typename_type (result, only_current_p);
- TYPENAME_IS_RESOLVING_P (type) = 0;
+ TYPENAME_IS_RESOLVING_P (result) = 0;
}
/* Qualify the resulting type. */
{
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)
+ /* When checking, try to get a constant value for all non-dependent
+ expressions in order to expose bugs in *_dependent_expression_p
+ and constexpr. This can affect code generation, see PR70704, so
+ only do this for -fchecking=2. */
+ if (flag_checking > 1
+ && cxx_dialect >= cxx11
+ /* Don't do this during nsdmi parsing as it can lead to
+ unexpected recursive instantiations. */
+ && !parsing_nsdmi ())
fold_non_dependent_expr (expr);
-#endif
/* Preserve OVERLOADs; the functions must be available to resolve
types. */
/* Returns a type which represents 'auto' or 'decltype(auto)'. We use a
TEMPLATE_TYPE_PARM with a level one deeper than the actual template
- parms. */
+ parms. If set_canonical is true, we set TYPE_CANONICAL on it. */
static tree
-make_auto_1 (tree name)
+make_auto_1 (tree name, bool set_canonical)
{
tree au = cxx_make_type (TEMPLATE_TYPE_PARM);
TYPE_NAME (au) = build_decl (input_location,
TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
(0, processing_template_decl + 1, processing_template_decl + 1,
TYPE_NAME (au), NULL_TREE);
- TYPE_CANONICAL (au) = canonical_type_parameter (au);
+ if (set_canonical)
+ TYPE_CANONICAL (au) = canonical_type_parameter (au);
DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
SET_DECL_TEMPLATE_PARM_P (TYPE_NAME (au));
tree
make_decltype_auto (void)
{
- return make_auto_1 (get_identifier ("decltype(auto)"));
+ return make_auto_1 (get_identifier ("decltype(auto)"), true);
}
tree
make_auto (void)
{
- return make_auto_1 (get_identifier ("auto"));
+ return make_auto_1 (get_identifier ("auto"), true);
+}
+
+/* Make a "constrained auto" type-specifier. This is an
+ auto type with constraints that must be associated after
+ deduction. The constraint is formed from the given
+ CONC and its optional sequence of arguments, which are
+ non-null if written as partial-concept-id. */
+
+tree
+make_constrained_auto (tree con, tree args)
+{
+ tree type = make_auto_1 (get_identifier ("auto"), false);
+
+ /* Build the constraint. */
+ tree tmpl = DECL_TI_TEMPLATE (con);
+ tree expr;
+ if (VAR_P (con))
+ expr = build_concept_check (tmpl, type, args);
+ else
+ expr = build_concept_check (build_overload (tmpl, NULL_TREE), type, args);
+
+ tree constr = make_predicate_constraint (expr);
+ PLACEHOLDER_TYPE_CONSTRAINTS (type) = constr;
+
+ /* Our canonical type depends on the constraint. */
+ TYPE_CANONICAL (type) = canonical_type_parameter (type);
+
+ /* Attach the constraint to the type declaration. */
+ tree decl = TYPE_NAME (type);
+ return decl;
}
/* Given type ARG, return std::initializer_list<ARG>. */
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);
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ init = resolve_nondeduced_context (init, complain);
- 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;
}
}
- /* If the list of declarators contains more than one declarator, the type
- 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)
- && !same_type_p (TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)))
- {
- if (cfun && auto_node == current_function_auto_return_pattern
- && LAMBDA_FUNCTION_P (current_function_decl))
- error ("inconsistent types %qT and %qT deduced for "
- "lambda return type", TREE_TYPE (auto_node),
- TREE_VEC_ELT (targs, 0));
- else
- error ("inconsistent deduction for %qT: %qT and then %qT",
- auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0));
- return error_mark_node;
- }
- if (context != adc_requirement)
- TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0);
-
/* Check any placeholder constraints against the deduced type. */
if (flag_concepts && !processing_template_decl)
if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (auto_node))
/* In an abbreviated function template we didn't know we were dealing
with a function template when we saw the auto return type, so update
it to have the correct level. */
- return make_auto_1 (TYPE_IDENTIFIER (type));
+ return make_auto_1 (TYPE_IDENTIFIER (type), true);
}
return 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 (type == NULL_TREE)
+ return NULL_TREE;
+ else 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',