returning an int. */
typedef int (*tree_fn_t) (tree, void*);
-/* The PENDING_TEMPLATES is a TREE_LIST of templates whose
- instantiations have been deferred, either because their definitions
- were not yet available, or because we were putting off doing the work. */
+/* The PENDING_TEMPLATES is a list of templates whose instantiations
+ have been deferred, either because their definitions were not yet
+ available, or because we were putting off doing the work. */
struct GTY ((chain_next ("%h.next"))) pending_template
{
struct pending_template *next;
static bool equal (spec_entry *, spec_entry *);
};
-static GTY (()) hash_table<spec_hasher> *decl_specializations;
-
-static GTY (()) hash_table<spec_hasher> *type_specializations;
+/* The general template is not in these tables. */
+typedef hash_table<spec_hasher> spec_hash_table;
+static GTY (()) spec_hash_table *decl_specializations;
+static GTY (()) spec_hash_table *type_specializations;
/* Contains canonical template parameter types. The vector is indexed by
the TEMPLATE_TYPE_IDX of the template parameter. Each element is a
static bool dependent_type_p_r (tree);
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
static tree tsubst_decl (tree, tree, tsubst_flags_t);
-static void perform_typedefs_access_check (tree tmpl, tree targs);
-static void append_type_to_template_for_access_check_1 (tree, tree, tree,
- location_t);
+static void perform_instantiation_time_access_checks (tree, tree);
static tree listify (tree);
static tree listify_autos (tree, tree);
static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
{
spec_entry *found;
spec_entry elt;
- hash_table<spec_hasher> *specializations;
+ spec_hash_table *specializations;
elt.tmpl = tmpl;
elt.args = args;
if (hash == 0)
hash = spec_hasher::hash (&elt);
- slot =
- decl_specializations->find_slot_with_hash (&elt, hash, INSERT);
+ slot = decl_specializations->find_slot_with_hash (&elt, hash, INSERT);
if (*slot)
- fn = ((spec_entry *) *slot)->spec;
+ fn = (*slot)->spec;
else
fn = NULL_TREE;
}
static tree
canonical_type_parameter (tree type)
{
- tree list;
int idx = TEMPLATE_TYPE_IDX (type);
gcc_assert (TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM);
- if (!canonical_template_parms)
- vec_alloc (canonical_template_parms, idx + 1);
-
- if (canonical_template_parms->length () <= (unsigned) idx)
+ if (vec_safe_length (canonical_template_parms) <= (unsigned) idx)
vec_safe_grow_cleared (canonical_template_parms, idx + 1);
- list = (*canonical_template_parms)[idx];
- while (list && !comptypes (type, TREE_VALUE (list), COMPARE_STRUCTURAL))
- list = TREE_CHAIN (list);
+ for (tree list = (*canonical_template_parms)[idx];
+ list; list = TREE_CHAIN (list))
+ if (comptypes (type, TREE_VALUE (list), COMPARE_STRUCTURAL))
+ return TREE_VALUE (list);
- if (list)
- return TREE_VALUE (list);
- else
- {
- (*canonical_template_parms)[idx]
- = tree_cons (NULL_TREE, type, (*canonical_template_parms)[idx]);
- return type;
- }
+ (*canonical_template_parms)[idx]
+ = tree_cons (NULL_TREE, type, (*canonical_template_parms)[idx]);
+ return type;
}
/* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
type);
TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl);
TREE_READONLY (decl) = TREE_READONLY (orig_decl);
+ DECL_VIRTUAL_P (decl) = DECL_VIRTUAL_P (orig_decl);
DECL_ARTIFICIAL (decl) = 1;
SET_DECL_TEMPLATE_PARM_P (decl);
TEMPLATE_PARM_PARAMETER_PACK (tpi)
= TEMPLATE_PARM_PARAMETER_PACK (index);
- /* Template template parameters need this. */
+ /* Template template parameters need this. */
tree inner = decl;
if (TREE_CODE (decl) == TEMPLATE_DECL)
{
/* This is for distinguishing between real templates and template
template parameters */
TREE_TYPE (parm) = t;
- TREE_TYPE (DECL_TEMPLATE_RESULT (parm)) = t;
+
+ /* any_template_parm_r expects to be able to get the targs of a
+ DECL_TEMPLATE_RESULT. */
+ tree result = DECL_TEMPLATE_RESULT (parm);
+ TREE_TYPE (result) = t;
+ tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (parm));
+ tree tinfo = build_template_info (parm, args);
+ retrofit_lang_decl (result);
+ DECL_TEMPLATE_INFO (result) = tinfo;
+
decl = parm;
}
else
tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
SET_DECL_LANGUAGE (tmpl, DECL_LANGUAGE (decl));
DECL_TEMPLATE_PARMS (tmpl) = parms;
+ DECL_TEMPLATE_RESULT (tmpl) = decl;
DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
+ TREE_TYPE (tmpl) = TREE_TYPE (decl);
DECL_SOURCE_LOCATION (tmpl) = DECL_SOURCE_LOCATION (decl);
DECL_MEMBER_TEMPLATE_P (tmpl) = member_template_p;
if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args))
&& (!flag_concepts
|| !strictly_subsumes (current_template_constraints (),
- inner_args, maintmpl)))
+ main_args, maintmpl)))
{
if (!flag_concepts)
error ("partial specialization %q+D does not specialize "
// Build the template decl.
tree tmpl = build_template_decl (decl, current_template_parms,
DECL_MEMBER_TEMPLATE_P (maintmpl));
- TREE_TYPE (tmpl) = type;
- DECL_TEMPLATE_RESULT (tmpl) = decl;
SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
DECL_TEMPLATE_INFO (tmpl) = build_template_info (maintmpl, specargs);
DECL_PRIMARY_TEMPLATE (tmpl) = maintmpl;
template <typename T> friend void A<T>::f();
is not primary. */
is_primary = false;
- else if (TREE_CODE (decl) == TYPE_DECL
- && LAMBDA_TYPE_P (TREE_TYPE (decl)))
+ else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (TREE_TYPE (decl)))
is_primary = false;
else
is_primary = template_parm_scope_p ();
if (!ctx
|| TREE_CODE (ctx) == FUNCTION_DECL
|| (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))
- || (TREE_CODE (decl) == TYPE_DECL
- && LAMBDA_TYPE_P (TREE_TYPE (decl)))
+ || (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (TREE_TYPE (decl)))
|| (is_friend && !DECL_TEMPLATE_INFO (decl)))
{
if (DECL_LANG_SPECIFIC (decl)
new_tmpl
= build_template_decl (decl, current_template_parms,
member_template_p);
- DECL_TEMPLATE_RESULT (new_tmpl) = decl;
- TREE_TYPE (new_tmpl) = TREE_TYPE (decl);
DECL_TI_TEMPLATE (decl) = new_tmpl;
SET_DECL_TEMPLATE_SPECIALIZATION (new_tmpl);
DECL_TEMPLATE_INFO (new_tmpl)
}
}
- DECL_TEMPLATE_RESULT (tmpl) = decl;
- TREE_TYPE (tmpl) = TREE_TYPE (decl);
+ gcc_checking_assert (DECL_TEMPLATE_RESULT (tmpl) == decl);
- /* Push template declarations for global functions and types. Note
- that we do not try to push a global template friend declared in a
- template class; such a thing may well depend on the template
- parameters of the class. */
- if (new_template_p && !ctx
- && !(is_friend && template_class_depth (current_class_type) > 0))
+ if (new_template_p)
{
- tmpl = pushdecl_namespace_level (tmpl, is_friend);
- if (tmpl == error_mark_node)
- return error_mark_node;
-
- /* Hide template friend classes that haven't been declared yet. */
- if (is_friend && TREE_CODE (decl) == TYPE_DECL)
+ /* Push template declarations for global functions and types.
+ Note that we do not try to push a global template friend
+ declared in a template class; such a thing may well depend on
+ the template parameters of the class and we'll push it when
+ instantiating the befriending class. */
+ if (!ctx
+ && !(is_friend && template_class_depth (current_class_type) > 0))
{
- DECL_ANTICIPATED (tmpl) = 1;
- DECL_FRIEND_P (tmpl) = 1;
+ tmpl = pushdecl_namespace_level (tmpl, is_friend);
+ if (tmpl == error_mark_node)
+ return error_mark_node;
+
+ /* Hide template friend classes that haven't been declared yet. */
+ if (is_friend && TREE_CODE (decl) == TYPE_DECL)
+ {
+ DECL_ANTICIPATED (tmpl) = 1;
+ DECL_FRIEND_P (tmpl) = 1;
+ }
}
}
+ else
+ /* The type may have been completed, or (erroneously) changed. */
+ TREE_TYPE (tmpl) = TREE_TYPE (decl);
if (is_primary)
{
tree tmpl = build_template_decl (fn, parms, /*member*/true);
tree args = template_parms_to_args (parms);
DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args);
- TREE_TYPE (tmpl) = TREE_TYPE (fn);
- DECL_TEMPLATE_RESULT (tmpl) = fn;
DECL_ARTIFICIAL (tmpl) = true;
DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
return tmpl;
}
/* Subroutine of convert_nontype_argument, to check whether EXPR, as an
- argument for TYPE, points to an unsuitable object. */
+ argument for TYPE, points to an unsuitable object.
+
+ Also adjust the type of the index in C++20 array subobject references. */
static bool
invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
{
tree decl = TREE_OPERAND (expr, 0);
+ if (cxx_dialect >= cxx20)
+ while (TREE_CODE (decl) == COMPONENT_REF
+ || TREE_CODE (decl) == ARRAY_REF)
+ {
+ tree &op = TREE_OPERAND (decl, 1);
+ if (TREE_CODE (decl) == ARRAY_REF
+ && TREE_CODE (op) == INTEGER_CST)
+ /* Canonicalize array offsets to ptrdiff_t; how they were
+ written doesn't matter for subobject identity. */
+ op = fold_convert (ptrdiff_type_node, op);
+ decl = TREE_OPERAND (decl, 0);
+ }
+
if (!VAR_P (decl))
{
if (complain & tf_error)
decl);
return true;
}
- else if (!same_type_ignoring_top_level_qualifiers_p
- (strip_array_types (TREE_TYPE (type)),
- strip_array_types (TREE_TYPE (decl))))
+ else if (cxx_dialect < cxx20
+ && !(same_type_ignoring_top_level_qualifiers_p
+ (strip_array_types (TREE_TYPE (type)),
+ strip_array_types (TREE_TYPE (decl)))))
{
if (complain & tf_error)
error ("the address of the %qT subobject of %qD is not a "
For a non-type template-parameter of integral or enumeration type,
integral promotions (_conv.prom_) and integral conversions
(_conv.integral_) are applied. */
- if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+ if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
+ || TREE_CODE (type) == REAL_TYPE)
{
if (cxx_dialect < cxx11)
{
/* Notice that there are constant expressions like '4 % 0' which
do not fold into integer constants. */
- if (TREE_CODE (expr) != INTEGER_CST && !val_dep_p)
+ if (!CONSTANT_CLASS_P (expr) && !val_dep_p)
{
if (complain & tf_error)
{
return NULL_TREE;
/* else cxx_constant_value complained but gave us
a real constant, so go ahead. */
- if (TREE_CODE (expr) != INTEGER_CST)
+ if (!CONSTANT_CLASS_P (expr))
{
/* Some assemble time constant expressions like
(intptr_t)&&lab1 - (intptr_t)&&lab2 or
compile time. Refuse them here. */
gcc_checking_assert (reduced_constant_expression_p (expr));
error_at (loc, "template argument %qE for type %qT not "
- "a constant integer", expr, type);
+ "a compile-time constant", expr, type);
return NULL_TREE;
}
}
if (class_nttp_const_wrapper_p (ot))
ot = TREE_OPERAND (ot, 0);
- if (TREE_CODE (nt) == TREE_VEC)
+ if (TREE_CODE (nt) == TREE_VEC || TREE_CODE (ot) == TREE_VEC)
/* For member templates */
- return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
- else if (PACK_EXPANSION_P (ot))
- return (PACK_EXPANSION_P (nt)
+ return TREE_CODE (ot) == TREE_CODE (nt) && comp_template_args (ot, nt);
+ else if (PACK_EXPANSION_P (ot) || PACK_EXPANSION_P (nt))
+ return (PACK_EXPANSION_P (ot) && PACK_EXPANSION_P (nt)
&& template_args_equal (PACK_EXPANSION_PATTERN (ot),
PACK_EXPANSION_PATTERN (nt))
&& template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot),
PACK_EXPANSION_EXTRA_ARGS (nt)));
else if (ARGUMENT_PACK_P (ot) || ARGUMENT_PACK_P (nt))
return cp_tree_equal (ot, nt);
- else if (ot && TREE_CODE (ot) == ARGUMENT_PACK_SELECT)
+ else if (TREE_CODE (ot) == ARGUMENT_PACK_SELECT)
gcc_unreachable ();
- else if (TYPE_P (nt))
+ else if (TYPE_P (nt) || TYPE_P (ot))
{
- if (!TYPE_P (ot))
+ if (!(TYPE_P (nt) && TYPE_P (ot)))
return false;
/* Don't treat an alias template specialization with dependent
arguments as equivalent to its underlying type when used as a
else
return same_type_p (ot, nt);
}
- else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
- return 0;
else
{
/* Try to treat a template non-type argument that has been converted
|| code1 == NON_LVALUE_EXPR;
code1 = TREE_CODE (ot))
ot = TREE_OPERAND (ot, 0);
+
for (enum tree_code code2 = TREE_CODE (nt);
CONVERT_EXPR_CODE_P (code2)
|| code2 == NON_LVALUE_EXPR;
/* If we called start_enum or pushtag above, this information
will already be set up. */
- if (!TYPE_NAME (t))
+ type_decl = TYPE_NAME (t);
+ if (!type_decl)
{
TYPE_CONTEXT (t) = FROB_CONTEXT (context);
DECL_SOURCE_LOCATION (type_decl)
= DECL_SOURCE_LOCATION (TYPE_STUB_DECL (template_type));
}
- else
- type_decl = TYPE_NAME (t);
if (CLASS_TYPE_P (template_type))
{
arglist = coerce_innermost_template_parms (parms, arglist, templ, complain,
/*req_all*/true,
/*use_default*/true);
+ if (arglist == error_mark_node)
+ return error_mark_node;
if (flag_concepts && !constraints_satisfied_p (templ, arglist))
{
}
new_friend = tsubst (decl, args, tf_warning_or_error, NULL_TREE);
+ if (new_friend == error_mark_node)
+ return error_mark_node;
/* The NEW_FRIEND will look like an instantiation, to the
compiler, but is not an instantiation from the point of view of
Then, in S<int>, template <class U> void f(int, U) is not an
instantiation of anything. */
- if (new_friend == error_mark_node)
- return error_mark_node;
DECL_USE_TEMPLATE (new_friend) = 0;
- if (TREE_CODE (decl) == TEMPLATE_DECL)
+ if (TREE_CODE (new_friend) == TEMPLATE_DECL)
{
DECL_USE_TEMPLATE (DECL_TEMPLATE_RESULT (new_friend)) = 0;
DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (new_friend))
if (DECL_NAMESPACE_SCOPE_P (new_friend))
{
tree old_decl;
- tree new_friend_template_info;
- tree new_friend_result_template_info;
tree ns;
- int new_friend_is_defn;
/* We must save some information from NEW_FRIEND before calling
duplicate decls since that function will free NEW_FRIEND if
possible. */
- new_friend_template_info = DECL_TEMPLATE_INFO (new_friend);
- new_friend_is_defn =
- (DECL_INITIAL (DECL_TEMPLATE_RESULT
- (template_for_substitution (new_friend)))
- != NULL_TREE);
+ tree new_friend_template_info = DECL_TEMPLATE_INFO (new_friend);
+ tree new_friend_result_template_info = NULL_TREE;
+ bool new_friend_is_defn =
+ (DECL_INITIAL (DECL_TEMPLATE_RESULT
+ (template_for_substitution (new_friend)))
+ != NULL_TREE);
+ tree not_tmpl = new_friend;
+
if (TREE_CODE (new_friend) == TEMPLATE_DECL)
{
/* This declaration is a `primary' template. */
DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
- new_friend_result_template_info
- = DECL_TEMPLATE_INFO (DECL_TEMPLATE_RESULT (new_friend));
+ not_tmpl = DECL_TEMPLATE_RESULT (new_friend);
+ new_friend_result_template_info = DECL_TEMPLATE_INFO (not_tmpl);
}
- else
- new_friend_result_template_info = NULL_TREE;
/* Inside pushdecl_namespace_level, we will push into the
current namespace. However, the friend function should go
DECL_ANTICIPATED (tmpl)
= DECL_ANTICIPATED (DECL_TEMPLATE_RESULT (tmpl)) = true;
+ /* Substitute into and set the constraints on the new declaration. */
+ if (tree ci = get_constraints (friend_tmpl))
+ {
+ ++processing_template_decl;
+ ci = tsubst_constraint_info (ci, args, tf_warning_or_error,
+ DECL_FRIEND_CONTEXT (friend_tmpl));
+ --processing_template_decl;
+ set_constraints (tmpl, ci);
+ }
+
/* Inject this template into the enclosing namspace scope. */
tmpl = pushdecl_namespace_level (tmpl, true);
}
}
}
-/* Perform (or defer) access check for typedefs that were referenced
- from within the template TMPL code.
- This is a subroutine of instantiate_decl and instantiate_class_template.
- TMPL is the template to consider and TARGS is the list of arguments of
- that template. */
+/* The template TMPL is being instantiated with the template arguments TARGS.
+ Perform the access checks that we deferred when parsing the template. */
static void
-perform_typedefs_access_check (tree tmpl, tree targs)
+perform_instantiation_time_access_checks (tree tmpl, tree targs)
{
unsigned i;
- qualified_typedef_usage_t *iter;
+ deferred_access_check *chk;
- if (!tmpl
- || (!CLASS_TYPE_P (tmpl)
- && TREE_CODE (tmpl) != FUNCTION_DECL))
+ if (!CLASS_TYPE_P (tmpl) && TREE_CODE (tmpl) != FUNCTION_DECL)
return;
- FOR_EACH_VEC_SAFE_ELT (get_types_needing_access_check (tmpl), i, iter)
- {
- tree type_decl = iter->typedef_decl;
- tree type_scope = iter->context;
-
- if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
- continue;
-
- if (uses_template_parms (type_decl))
- type_decl = tsubst (type_decl, targs, tf_error, NULL_TREE);
- if (uses_template_parms (type_scope))
- type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
-
- /* Make access check error messages point to the location
- of the use of the typedef. */
- iloc_sentinel ils (iter->locus);
- perform_or_defer_access_check (TYPE_BINFO (type_scope),
- type_decl, type_decl,
- tf_warning_or_error);
- }
+ if (vec<deferred_access_check, va_gc> *access_checks
+ = TI_DEFERRED_ACCESS_CHECKS (get_template_info (tmpl)))
+ FOR_EACH_VEC_ELT (*access_checks, i, chk)
+ {
+ tree decl = chk->decl;
+ tree diag_decl = chk->diag_decl;
+ tree type_scope = TREE_TYPE (chk->binfo);
+
+ if (uses_template_parms (type_scope))
+ type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
+
+ /* Make access check error messages point to the location
+ of the use of the typedef. */
+ iloc_sentinel ils (chk->loc);
+ perform_or_defer_access_check (TYPE_BINFO (type_scope),
+ decl, diag_decl, tf_warning_or_error);
+ }
}
static tree
continue;
/* Build new CLASSTYPE_NESTED_UTDS. */
+ bool class_template_p = (TREE_CODE (t) != ENUMERAL_TYPE
+ && TYPE_LANG_SPECIFIC (t)
+ && CLASSTYPE_IS_TEMPLATE (t));
- tree newtag;
- bool class_template_p;
-
- class_template_p = (TREE_CODE (t) != ENUMERAL_TYPE
- && TYPE_LANG_SPECIFIC (t)
- && CLASSTYPE_IS_TEMPLATE (t));
/* If the member is a class template, then -- even after
substitution -- there may be dependent types in the
template argument list for the class. We increment
when outside of a template. */
if (class_template_p)
++processing_template_decl;
- newtag = tsubst (t, args, tf_error, NULL_TREE);
+ tree newtag = tsubst (t, args, tf_error, NULL_TREE);
if (class_template_p)
--processing_template_decl;
if (newtag == error_mark_node)
tree vec = NULL_TREE;
int len = 1;
+ gcc_checking_assert (TREE_CODE (t) != CONST_DECL);
/* The file and line for this declaration, to
assist in error message reporting. Since we
called push_tinst_level above, we don't need to
definitions or default arguments, of the class member functions,
member classes, static data members and member templates.... */
- /* Some typedefs referenced from within the template code need to be access
- checked at template instantiation time, i.e now. These types were
- added to the template at parsing time. Let's get those and perform
- the access checks then. */
- perform_typedefs_access_check (pattern, args);
+ perform_instantiation_time_access_checks (pattern, args);
perform_deferred_access_checks (tf_warning_or_error);
pop_nested_class ();
maximum_field_alignment = saved_maximum_field_alignment;
template_parm_level_and_index (parm_pack, &level, &idx);
if (level <= levels)
arg_pack = TMPL_ARG (args, level, idx);
+
+ if (arg_pack && TREE_CODE (arg_pack) == TEMPLATE_TYPE_PARM
+ && TEMPLATE_TYPE_PARAMETER_PACK (arg_pack))
+ arg_pack = NULL_TREE;
}
orig_arg = arg_pack;
make_argument_pack (tree vec)
{
tree pack;
- tree elt = TREE_VEC_ELT (vec, 0);
- if (TYPE_P (elt))
+
+ if (TYPE_P (TREE_VEC_ELT (vec, 0)))
pack = cxx_make_type (TYPE_ARGUMENT_PACK);
else
{
if (TREE_CODE (arg) == DEFERRED_PARSE)
return arg;
+ /* Shortcut {}. */
+ if (BRACE_ENCLOSED_INITIALIZER_P (arg)
+ && CONSTRUCTOR_NELTS (arg) == 0)
+ return arg;
+
tree parm = FUNCTION_FIRST_USER_PARM (fn);
parm = chain_index (parmnum, parm);
tree parmtype = TREE_TYPE (parm);
don't substitute through the constraints; that's only done when
they are checked. */
if (tree ci = get_constraints (t))
- set_constraints (r, ci);
+ /* Unless we're regenerating a lambda, in which case we'll set the
+ lambda's constraints in tsubst_lambda_expr. */
+ if (!lambda_fntype)
+ set_constraints (r, ci);
if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
SET_DECL_FRIEND_CONTEXT (r,
If it isn't, that'll be handled by
clone_constructors_and_destructors. */
if (PRIMARY_TEMPLATE_P (gen_tmpl))
- clone_function_decl (r, /*update_methods=*/false);
+ clone_cdtor (r, /*update_methods=*/false);
}
else if ((complain & tf_error) != 0
&& IDENTIFIER_ANY_OP_P (DECL_NAME (r))
= tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
complain);
- if (TREE_CODE (decl) == TYPE_DECL
- && !TYPE_DECL_ALIAS_P (decl))
+ bool class_p = false;
+ tree inner = decl;
+ ++processing_template_decl;
+ if (TREE_CODE (inner) == FUNCTION_DECL)
+ inner = tsubst_function_decl (inner, args, complain, lambda_fntype);
+ else
{
- tree new_type;
- ++processing_template_decl;
- new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- --processing_template_decl;
- if (new_type == error_mark_node)
- return error_mark_node;
+ if (TREE_CODE (inner) == TYPE_DECL && !TYPE_DECL_ALIAS_P (inner))
+ {
+ class_p = true;
+ inner = TREE_TYPE (inner);
+ }
+ inner = tsubst (inner, args, complain, in_decl);
+ }
+ --processing_template_decl;
+ if (inner == error_mark_node)
+ return error_mark_node;
- TREE_TYPE (r) = new_type;
+ if (class_p)
+ {
/* For a partial specialization, we need to keep pointing to
the primary template. */
if (!DECL_TEMPLATE_SPECIALIZATION (t))
- CLASSTYPE_TI_TEMPLATE (new_type) = r;
- DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
- DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
- DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
+ CLASSTYPE_TI_TEMPLATE (inner) = r;
+
+ DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (inner);
+ inner = TYPE_MAIN_DECL (inner);
+ }
+ else if (lambda_fntype)
+ {
+ tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r));
+ DECL_TEMPLATE_INFO (inner) = build_template_info (r, args);
}
else
{
- tree new_decl;
- ++processing_template_decl;
- if (TREE_CODE (decl) == FUNCTION_DECL)
- new_decl = tsubst_function_decl (decl, args, complain, lambda_fntype);
- else
- new_decl = tsubst (decl, args, complain, in_decl);
- --processing_template_decl;
- if (new_decl == error_mark_node)
- return error_mark_node;
-
- DECL_TEMPLATE_RESULT (r) = new_decl;
- TREE_TYPE (r) = TREE_TYPE (new_decl);
- DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
- if (lambda_fntype)
- {
- tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r));
- DECL_TEMPLATE_INFO (new_decl) = build_template_info (r, args);
- }
- else
- {
- DECL_TI_TEMPLATE (new_decl) = r;
- DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
- }
+ if (TREE_CODE (decl) != TYPE_DECL || !TYPE_DECL_ALIAS_P (decl))
+ DECL_TI_TEMPLATE (inner) = r;
+ DECL_TI_ARGS (r) = DECL_TI_ARGS (inner);
}
+ DECL_TEMPLATE_RESULT (r) = inner;
+ TREE_TYPE (r) = TREE_TYPE (inner);
+ DECL_CONTEXT (r) = DECL_CONTEXT (inner);
+
DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
&& DECL_BIT_FIELD_TYPE (TREE_OPERAND (ve, 1)) == type)
type = TREE_TYPE (ve);
else
- gcc_checking_assert (TREE_TYPE (ve) == type);
+ gcc_checking_assert (TYPE_MAIN_VARIANT (TREE_TYPE (ve))
+ == TYPE_MAIN_VARIANT (type));
SET_DECL_VALUE_EXPR (r, ve);
}
if (CP_DECL_THREAD_LOCAL_P (r)
return new_specs;
}
+/* Substitute through a TREE_LIST of types or expressions, handling pack
+ expansions. */
+
+tree
+tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ if (t == void_list_node)
+ return t;
+
+ tree purpose = TREE_PURPOSE (t);
+ tree purposevec = NULL_TREE;
+ if (!purpose)
+ ;
+ else if (PACK_EXPANSION_P (purpose))
+ {
+ purpose = tsubst_pack_expansion (purpose, args, complain, in_decl);
+ if (TREE_CODE (purpose) == TREE_VEC)
+ purposevec = purpose;
+ }
+ else if (TYPE_P (purpose))
+ purpose = tsubst (purpose, args, complain, in_decl);
+ else
+ purpose = tsubst_copy_and_build (purpose, args, complain, in_decl);
+ if (purpose == error_mark_node || purposevec == error_mark_node)
+ return error_mark_node;
+
+ tree value = TREE_VALUE (t);
+ tree valuevec = NULL_TREE;
+ if (!value)
+ ;
+ else if (PACK_EXPANSION_P (value))
+ {
+ value = tsubst_pack_expansion (value, args, complain, in_decl);
+ if (TREE_CODE (value) == TREE_VEC)
+ valuevec = value;
+ }
+ else if (TYPE_P (value))
+ value = tsubst (value, args, complain, in_decl);
+ else
+ value = tsubst_copy_and_build (value, args, complain, in_decl);
+ if (value == error_mark_node || valuevec == error_mark_node)
+ return error_mark_node;
+
+ tree chain = TREE_CHAIN (t);
+ if (!chain)
+ ;
+ else if (TREE_CODE (chain) == TREE_LIST)
+ chain = tsubst_tree_list (chain, args, complain, in_decl);
+ else if (TYPE_P (chain))
+ chain = tsubst (chain, args, complain, in_decl);
+ else
+ chain = tsubst_copy_and_build (chain, args, complain, in_decl);
+ if (chain == error_mark_node)
+ return error_mark_node;
+
+ if (purpose == TREE_PURPOSE (t)
+ && value == TREE_VALUE (t)
+ && chain == TREE_CHAIN (t))
+ return t;
+
+ int len;
+ /* Determine the number of arguments. */
+ if (purposevec)
+ {
+ len = TREE_VEC_LENGTH (purposevec);
+ gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
+ }
+ else if (valuevec)
+ len = TREE_VEC_LENGTH (valuevec);
+ else
+ len = 1;
+
+ for (int i = len; i-- > 0; )
+ {
+ if (purposevec)
+ purpose = TREE_VEC_ELT (purposevec, i);
+ if (valuevec)
+ value = TREE_VEC_ELT (valuevec, i);
+
+ if (value && TYPE_P (value))
+ chain = hash_tree_cons (purpose, value, chain);
+ else
+ chain = tree_cons (purpose, value, chain);
+ }
+
+ return chain;
+}
+
/* Take the tree structure T and replace template parameters used
therein with the argument vector ARGS. IN_DECL is an associated
decl for diagnostics. If an error occurs, returns ERROR_MARK_NODE.
}
case TREE_LIST:
- {
- tree purpose, value, chain;
-
- if (t == void_list_node)
- return t;
-
- if ((TREE_PURPOSE (t) && PACK_EXPANSION_P (TREE_PURPOSE (t)))
- || (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t))))
- {
- /* We have pack expansions, so expand those and
- create a new list out of it. */
-
- /* Expand the argument expressions. */
- tree purposevec = NULL_TREE;
- if (TREE_PURPOSE (t))
- purposevec = tsubst_pack_expansion (TREE_PURPOSE (t), args,
- complain, in_decl);
- if (purposevec == error_mark_node)
- return error_mark_node;
-
- tree valuevec = NULL_TREE;
- if (TREE_VALUE (t))
- valuevec = tsubst_pack_expansion (TREE_VALUE (t), args,
- complain, in_decl);
- if (valuevec == error_mark_node)
- return error_mark_node;
-
- /* Build the rest of the list. */
- tree chain = TREE_CHAIN (t);
- if (chain && chain != void_type_node)
- chain = tsubst (chain, args, complain, in_decl);
- if (chain == error_mark_node)
- return error_mark_node;
-
- /* Determine the number of arguments. */
- int len = -1;
- if (purposevec && TREE_CODE (purposevec) == TREE_VEC)
- {
- len = TREE_VEC_LENGTH (purposevec);
- gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
- }
- else if (TREE_CODE (valuevec) == TREE_VEC)
- len = TREE_VEC_LENGTH (valuevec);
- else
- {
- /* Since we only performed a partial substitution into
- the argument pack, we only RETURN (a single list
- node. */
- if (purposevec == TREE_PURPOSE (t)
- && valuevec == TREE_VALUE (t)
- && chain == TREE_CHAIN (t))
- return t;
-
- return tree_cons (purposevec, valuevec, chain);
- }
-
- /* Convert the argument vectors into a TREE_LIST. */
- for (int i = len; i-- > 0; )
- {
- purpose = (purposevec ? TREE_VEC_ELT (purposevec, i)
- : NULL_TREE);
- value = (valuevec ? TREE_VEC_ELT (valuevec, i)
- : NULL_TREE);
-
- /* Build the list (backwards). */
- chain = hash_tree_cons (purpose, value, chain);
- }
-
- return chain;
- }
-
- purpose = TREE_PURPOSE (t);
- if (purpose)
- {
- purpose = tsubst (purpose, args, complain, in_decl);
- if (purpose == error_mark_node)
- return error_mark_node;
- }
- value = TREE_VALUE (t);
- if (value)
- {
- value = tsubst (value, args, complain, in_decl);
- if (value == error_mark_node)
- return error_mark_node;
- }
- chain = TREE_CHAIN (t);
- if (chain && chain != void_type_node)
- {
- chain = tsubst (chain, args, complain, in_decl);
- if (chain == error_mark_node)
- return error_mark_node;
- }
- if (purpose == TREE_PURPOSE (t)
- && value == TREE_VALUE (t)
- && chain == TREE_CHAIN (t))
- return t;
- return hash_tree_cons (purpose, value, chain);
- }
+ return tsubst_tree_list (t, args, complain, in_decl);
case TREE_BINFO:
/* We should never be tsubsting a binfo. */
/* Treat as-if non-dependent below. */
dependent_p = false;
- baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
+ baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1,
+ complain);
if (!baselink)
{
if ((complain & tf_error)
else
decl = RECUR (decl);
}
- init = RECUR (init);
+ if (init && TREE_CODE (init) == TREE_VEC)
+ {
+ init = copy_node (init);
+ TREE_VEC_ELT (init, 0)
+ = tsubst_decl (TREE_VEC_ELT (init, 0), args, complain);
+ TREE_VEC_ELT (init, 1) = RECUR (TREE_VEC_ELT (init, 1));
+ TREE_VEC_ELT (init, 2) = RECUR (TREE_VEC_ELT (init, 2));
+ }
+ else
+ init = RECUR (init);
if (orig_declv && OMP_FOR_ORIG_DECLS (t))
{
if (!range_for)
{
- cond = RECUR (TREE_VEC_ELT (OMP_FOR_COND (t), i));
+ cond = TREE_VEC_ELT (OMP_FOR_COND (t), i);
+ if (COMPARISON_CLASS_P (cond)
+ && TREE_CODE (TREE_OPERAND (cond, 1)) == TREE_VEC)
+ {
+ tree lhs = RECUR (TREE_OPERAND (cond, 0));
+ tree rhs = copy_node (TREE_OPERAND (cond, 1));
+ TREE_VEC_ELT (rhs, 0)
+ = tsubst_decl (TREE_VEC_ELT (rhs, 0), args, complain);
+ TREE_VEC_ELT (rhs, 1) = RECUR (TREE_VEC_ELT (rhs, 1));
+ TREE_VEC_ELT (rhs, 2) = RECUR (TREE_VEC_ELT (rhs, 2));
+ cond = build2 (TREE_CODE (cond), TREE_TYPE (cond),
+ lhs, rhs);
+ }
+ else
+ cond = RECUR (cond);
incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i);
if (TREE_CODE (incr) == MODIFY_EXPR)
{
if (ndecl != error_mark_node)
cp_maybe_mangle_decomp (ndecl, first, cnt);
+ /* In a non-template function, VLA type declarations are
+ handled in grokdeclarator; for templates, handle them
+ now. */
+ predeclare_vla (decl);
+
cp_finish_decl (decl, init, const_init, NULL_TREE,
constinit_p ? LOOKUP_CONSTINIT : 0);
stmt = pop_stmt_list (stmt);
}
+ if (TREE_CODE (t) == OMP_CRITICAL
+ && tmp != NULL_TREE
+ && integer_nonzerop (OMP_CLAUSE_HINT_EXPR (tmp)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (tmp),
+ "%<#pragma omp critical%> with %<hint%> clause requires "
+ "a name, except when %<omp_sync_hint_none%> is used");
+ RETURN (error_mark_node);
+ }
t = copy_node (t);
OMP_BODY (t) = stmt;
OMP_CLAUSES (t) = tmp;
finish_member_declaration (fn);
}
+ if (tree ci = get_constraints (oldfn))
+ {
+ /* Substitute into the lambda's constraints. */
+ if (oldtmpl)
+ ++processing_template_decl;
+ ci = tsubst_constraint_info (ci, args, complain, in_decl);
+ if (oldtmpl)
+ --processing_template_decl;
+ set_constraints (fn, ci);
+ }
+
/* Let finish_function set this. */
DECL_DECLARED_CONSTEXPR_P (fn) = false;
break;
case STATIC_CAST_EXPR:
r = build_static_cast (input_location, type, op, complain);
+ if (IMPLICIT_RVALUE_P (t))
+ set_implicit_rvalue_p (r);
break;
default:
gcc_unreachable ();
if (placement == NULL_TREE)
placement_vec = NULL;
+ else if (placement == error_mark_node)
+ RETURN (error_mark_node);
else
{
placement_vec = make_tree_vector ();
}
case TREE_LIST:
- {
- tree purpose, value, chain;
-
- if (t == void_list_node)
- RETURN (t);
-
- if ((TREE_PURPOSE (t) && PACK_EXPANSION_P (TREE_PURPOSE (t)))
- || (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t))))
- {
- /* We have pack expansions, so expand those and
- create a new list out of it. */
- tree purposevec = NULL_TREE;
- tree valuevec = NULL_TREE;
- tree chain;
- int i, len = -1;
-
- /* Expand the argument expressions. */
- if (TREE_PURPOSE (t))
- purposevec = tsubst_pack_expansion (TREE_PURPOSE (t), args,
- complain, in_decl);
- if (TREE_VALUE (t))
- valuevec = tsubst_pack_expansion (TREE_VALUE (t), args,
- complain, in_decl);
-
- /* Build the rest of the list. */
- chain = TREE_CHAIN (t);
- if (chain && chain != void_type_node)
- chain = RECUR (chain);
-
- /* Determine the number of arguments. */
- if (purposevec && TREE_CODE (purposevec) == TREE_VEC)
- {
- len = TREE_VEC_LENGTH (purposevec);
- gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
- }
- else if (TREE_CODE (valuevec) == TREE_VEC)
- len = TREE_VEC_LENGTH (valuevec);
- else
- {
- /* Since we only performed a partial substitution into
- the argument pack, we only RETURN (a single list
- node. */
- if (purposevec == TREE_PURPOSE (t)
- && valuevec == TREE_VALUE (t)
- && chain == TREE_CHAIN (t))
- RETURN (t);
-
- RETURN (tree_cons (purposevec, valuevec, chain));
- }
-
- /* Convert the argument vectors into a TREE_LIST */
- i = len;
- while (i > 0)
- {
- /* Grab the Ith values. */
- i--;
- purpose = purposevec ? TREE_VEC_ELT (purposevec, i)
- : NULL_TREE;
- value
- = valuevec ? convert_from_reference (TREE_VEC_ELT (valuevec, i))
- : NULL_TREE;
-
- /* Build the list (backwards). */
- chain = tree_cons (purpose, value, chain);
- }
-
- RETURN (chain);
- }
-
- purpose = TREE_PURPOSE (t);
- if (purpose)
- purpose = RECUR (purpose);
- value = TREE_VALUE (t);
- if (value)
- value = RECUR (value);
- chain = TREE_CHAIN (t);
- if (chain && chain != void_type_node)
- chain = RECUR (chain);
- if (purpose == TREE_PURPOSE (t)
- && value == TREE_VALUE (t)
- && chain == TREE_CHAIN (t))
- RETURN (t);
- RETURN (tree_cons (purpose, value, chain));
- }
+ RETURN (tsubst_tree_list (t, args, complain, in_decl));
case COMPONENT_REF:
{
but it doesn't seem to be on the hot path. */
spec = retrieve_specialization (gen_tmpl, targ_ptr, 0);
- gcc_assert (tmpl == gen_tmpl
- || ((fndecl = retrieve_specialization (tmpl, orig_args, 0))
- == spec)
- || fndecl == NULL_TREE);
+ gcc_checking_assert (tmpl == gen_tmpl
+ || ((fndecl
+ = retrieve_specialization (tmpl, orig_args, 0))
+ == spec)
+ || fndecl == NULL_TREE);
if (spec != NULL_TREE)
{
instantiating the template clones. */
if (tree chain = DECL_CHAIN (gen_tmpl))
if (DECL_P (chain) && DECL_CLONED_FUNCTION_P (chain))
- clone_function_decl (fndecl, /*update_methods=*/false);
+ clone_cdtor (fndecl, /*update_methods=*/false);
if (!access_ok)
{
/* Adjust any explicit template arguments before entering the
substitution context. */
explicit_targs
- = (coerce_template_parms (tparms, explicit_targs, NULL_TREE,
+ = (coerce_template_parms (tparms, explicit_targs, fn,
complain|tf_partial,
/*require_all_args=*/false,
/*use_default_args=*/false));
TREE_CONSTANT (result) = 1;
}
else
- result = cxx_make_type (TYPE_ARGUMENT_PACK);
+ result = cxx_make_type (TYPE_ARGUMENT_PACK);
SET_ARGUMENT_PACK_ARGS (result, new_args);
{
tree bad_old_arg = NULL_TREE, bad_new_arg = NULL_TREE;
tree old_args = ARGUMENT_PACK_ARGS (old_pack);
-
+ temp_override<int> ovl (TREE_VEC_LENGTH (old_args));
+ /* During template argument deduction for the aggregate deduction
+ candidate, the number of elements in a trailing parameter pack
+ is only deduced from the number of remaining function
+ arguments if it is not otherwise deduced. */
+ if (cxx_dialect >= cxx20
+ && TREE_VEC_LENGTH (new_args) < TREE_VEC_LENGTH (old_args)
+ && builtin_guide_p (TPARMS_PRIMARY_TEMPLATE (tparms)))
+ TREE_VEC_LENGTH (old_args) = TREE_VEC_LENGTH (new_args);
if (!comp_template_args (old_args, new_args,
&bad_old_arg, &bad_new_arg))
/* Inconsistent unification of this parameter pack. */
/* If both deductions succeed, the partial ordering selects the more
constrained template. */
- if (!lose1 && !lose2)
+ /* P2113: If the corresponding template-parameters of the
+ template-parameter-lists are not equivalent ([temp.over.link]) or if
+ the function parameters that positionally correspond between the two
+ templates are not of the same type, neither template is more
+ specialized than the other. */
+ if (!lose1 && !lose2
+ && comp_template_parms (DECL_TEMPLATE_PARMS (pat1),
+ DECL_TEMPLATE_PARMS (pat2))
+ && compparms (origs1, origs2))
{
int winner = more_constrained (decl1, decl2);
if (winner > 0)
for (t = DECL_TEMPLATE_SPECIALIZATIONS (main_tmpl); t; t = TREE_CHAIN (t))
{
- tree spec_args;
- tree spec_tmpl = TREE_VALUE (t);
+ const tree ospec_tmpl = TREE_VALUE (t);
+ tree spec_tmpl;
if (outer_args)
{
/* Substitute in the template args from the enclosing class. */
++processing_template_decl;
- spec_tmpl = tsubst (spec_tmpl, outer_args, tf_none, NULL_TREE);
+ spec_tmpl = tsubst (ospec_tmpl, outer_args, tf_none, NULL_TREE);
--processing_template_decl;
+ if (spec_tmpl == error_mark_node)
+ return error_mark_node;
}
+ else
+ spec_tmpl = ospec_tmpl;
- if (spec_tmpl == error_mark_node)
- return error_mark_node;
-
- spec_args = get_partial_spec_bindings (tmpl, spec_tmpl, args);
+ tree spec_args = get_partial_spec_bindings (tmpl, spec_tmpl, args);
if (spec_args)
{
if (outer_args)
/* Keep the candidate only if the constraints are satisfied,
or if we're not compiling with concepts. */
if (!flag_concepts
- || constraints_satisfied_p (spec_tmpl, spec_args))
+ || constraints_satisfied_p (ospec_tmpl, spec_args))
{
- list = tree_cons (spec_args, TREE_VALUE (t), list);
+ list = tree_cons (spec_args, ospec_tmpl, list);
TREE_TYPE (list) = TREE_TYPE (t);
}
}
[temp.explicit]
- The explicit instantiation of a class template specialization
- implies the instantiation of all of its members not
- previously explicitly specialized in the translation unit
- containing the explicit instantiation.
-
- Of course, we can't instantiate member template classes, since we
- don't have any arguments for them. Note that the standard is
- unclear on whether the instantiation of the members are
- *explicit* instantiations or not. However, the most natural
- interpretation is that it should be an explicit
- instantiation. */
+ An explicit instantiation that names a class template
+ specialization is also an explicit instantiation of the same
+ kind (declaration or definition) of each of its members (not
+ including members inherited from base classes and members
+ that are templates) that has not been previously explicitly
+ specialized in the translation unit containing the explicit
+ instantiation, provided that the associated constraints, if
+ any, of that member are satisfied by the template arguments
+ of the explicit instantiation. */
for (tree fld = TYPE_FIELDS (t); fld; fld = DECL_CHAIN (fld))
if ((VAR_P (fld)
|| (TREE_CODE (fld) == FUNCTION_DECL
&& !static_p
&& user_provided_p (fld)))
- && DECL_TEMPLATE_INSTANTIATION (fld))
+ && DECL_TEMPLATE_INSTANTIATION (fld)
+ && constraints_satisfied_p (fld))
{
mark_decl_instantiated (fld, extern_p);
if (! extern_p)
bool
maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
{
- tree fntype, spec, noex, clone;
+ tree fntype, spec, noex;
/* Don't instantiate a noexcept-specification from template context. */
if (processing_template_decl
return !DECL_MAYBE_DELETED (fn);
}
- if (DECL_CLONED_FUNCTION_P (fn))
- fn = DECL_CLONED_FUNCTION (fn);
+ fntype = TREE_TYPE (fn);
+ spec = TYPE_RAISES_EXCEPTIONS (fntype);
+
+ if (!spec || !TREE_PURPOSE (spec))
+ return true;
+
+ noex = TREE_PURPOSE (spec);
+ if (TREE_CODE (noex) != DEFERRED_NOEXCEPT
+ && TREE_CODE (noex) != DEFERRED_PARSE)
+ return true;
tree orig_fn = NULL_TREE;
/* For a member friend template we can get a TEMPLATE_DECL. Let's use
fn = DECL_TEMPLATE_RESULT (fn);
}
- fntype = TREE_TYPE (fn);
- spec = TYPE_RAISES_EXCEPTIONS (fntype);
-
- if (!spec || !TREE_PURPOSE (spec))
- return true;
-
- noex = TREE_PURPOSE (spec);
-
- if (TREE_CODE (noex) == DEFERRED_NOEXCEPT)
+ if (DECL_CLONED_FUNCTION_P (fn))
+ {
+ tree prime = DECL_CLONED_FUNCTION (fn);
+ if (!maybe_instantiate_noexcept (prime, complain))
+ return false;
+ spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (prime));
+ }
+ else if (TREE_CODE (noex) == DEFERRED_NOEXCEPT)
{
static hash_set<tree>* fns = new hash_set<tree>;
bool added = false;
if (added)
fns->remove (fn);
-
- if (spec == error_mark_node)
- {
- /* This failed with a hard error, so let's go with false. */
- gcc_assert (seen_error ());
- spec = noexcept_false_spec;
- }
-
- TREE_TYPE (fn) = build_exception_variant (fntype, spec);
- if (orig_fn)
- TREE_TYPE (orig_fn) = TREE_TYPE (fn);
}
- FOR_EACH_CLONE (clone, fn)
+ if (spec == error_mark_node)
{
- if (TREE_TYPE (clone) == fntype)
- TREE_TYPE (clone) = TREE_TYPE (fn);
- else
- TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), spec);
+ /* This failed with a hard error, so let's go with false. */
+ gcc_assert (seen_error ());
+ spec = noexcept_false_spec;
}
+ TREE_TYPE (fn) = build_exception_variant (fntype, spec);
+ if (orig_fn)
+ TREE_TYPE (orig_fn) = TREE_TYPE (fn);
+
return true;
}
d = DECL_CLONED_FUNCTION (d);
if (DECL_TEMPLATE_INSTANTIATED (d)
+ || TREE_TYPE (d) == error_mark_node
|| (TREE_CODE (d) == FUNCTION_DECL
&& DECL_DEFAULTED_FN (d) && DECL_INITIAL (d))
|| DECL_TEMPLATE_SPECIALIZATION (d))
gen_tmpl = most_general_template (tmpl);
gen_args = DECL_TI_ARGS (d);
- if (tmpl != gen_tmpl)
- /* We should already have the extra args. */
- gcc_assert (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (gen_tmpl))
- == TMPL_ARGS_DEPTH (gen_args));
+ /* We should already have the extra args. */
+ gcc_checking_assert (tmpl == gen_tmpl
+ || (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (gen_tmpl))
+ == TMPL_ARGS_DEPTH (gen_args)));
/* And what's in the hash table should match D. */
- gcc_assert ((spec = retrieve_specialization (gen_tmpl, gen_args, 0)) == d
- || spec == NULL_TREE);
+ gcc_checking_assert ((spec = retrieve_specialization (gen_tmpl, gen_args, 0))
+ == d
+ || spec == NULL_TREE);
/* This needs to happen before any tsubsting. */
if (! push_tinst_level (d))
else
start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
- /* Some typedefs referenced from within the template code need to be
- access checked at template instantiation time, i.e now. These
- types were added to the template at parsing time. Let's get those
- and perform the access checks then. */
- perform_typedefs_access_check (DECL_TEMPLATE_RESULT (td),
- args);
+ perform_instantiation_time_access_checks (DECL_TEMPLATE_RESULT (td),
+ args);
/* Create substitution entries for the parameters. */
register_parameter_specializations (code_pattern, d);
else if (cxx_dialect >= cxx11
&& TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
return false;
- else if (CLASS_TYPE_P (type))
+ else if (VOID_TYPE_P (type))
+ /* Fall through. */;
+ else if (cxx_dialect >= cxx20)
{
- if (cxx_dialect < cxx20)
- {
- if (complain & tf_error)
- error ("non-type template parameters of class type only available "
- "with %<-std=c++20%> or %<-std=gnu++20%>");
- return true;
- }
if (dependent_type_p (type))
return false;
- if (!complete_type_or_else (type, NULL_TREE))
+ if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
return true;
- if (!structural_type_p (type))
+ if (structural_type_p (type))
+ return false;
+ if (complain & tf_error)
{
- if (complain & tf_error)
- {
- auto_diagnostic_group d;
- error ("%qT is not a valid type for a template non-type "
- "parameter because it is not structural", type);
- structural_type_p (type, true);
- }
- return true;
+ auto_diagnostic_group d;
+ error ("%qT is not a valid type for a template non-type "
+ "parameter because it is not structural", type);
+ structural_type_p (type, true);
}
- return false;
+ return true;
+ }
+ else if (CLASS_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ error ("non-type template parameters of class type only available "
+ "with %<-std=c++20%> or %<-std=gnu++20%>");
+ return true;
}
if (complain & tf_error)
return true;
/* Some expression forms are never type-dependent. */
- if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR
- || TREE_CODE (expression) == SIZEOF_EXPR
+ if (TREE_CODE (expression) == SIZEOF_EXPR
|| TREE_CODE (expression) == ALIGNOF_EXPR
|| TREE_CODE (expression) == AT_ENCODE_EXPR
|| TREE_CODE (expression) == NOEXCEPT_EXPR
gcc_checking_assert (uses_template_parms (scope));
/* Usually the non-qualified identifier of a TYPENAME_TYPE is
- TYPE_IDENTIFIER (type). But when 'type' is a typedef variant of
- a TYPENAME_TYPE node, then TYPE_NAME (type) is set to the TYPE_DECL representing
- the typedef. In that case TYPE_IDENTIFIER (type) is not the non-qualified
- identifier of the TYPENAME_TYPE anymore.
- So by getting the TYPE_IDENTIFIER of the _main declaration_ of the
- TYPENAME_TYPE instead, we avoid messing up with a possible
+ TYPE_IDENTIFIER (type). But when 'type' is a typedef variant of a
+ TYPENAME_TYPE node, then TYPE_NAME (type) is set to the TYPE_DECL
+ representing the typedef. In that case TYPE_IDENTIFIER (type) is
+ not the non-qualified identifier of the TYPENAME_TYPE anymore.
+ So by getting the TYPE_IDENTIFIER of the _main declaration_ of
+ the TYPENAME_TYPE instead, we avoid messing up with a possible
typedef variant case. */
name = TYPE_IDENTIFIER (TYPE_MAIN_VARIANT (type));
return error_mark_node;
}
- /* Initially build the concept declaration; it's type is bool. */
+ /* Initially build the concept declaration; its type is bool. */
tree decl = build_lang_decl_loc (loc, CONCEPT_DECL, *id, boolean_type_node);
DECL_CONTEXT (decl) = current_scope ();
DECL_INITIAL (decl) = init;
return false;
}
+/* True if FN is an aggregate initialization guide or the copy deduction
+ guide. */
+
+bool
+builtin_guide_p (const_tree fn)
+{
+ if (!deduction_guide_p (fn))
+ return false;
+ if (!DECL_ARTIFICIAL (fn))
+ /* Explicitly declared. */
+ return false;
+ if (DECL_ABSTRACT_ORIGIN (fn))
+ /* Derived from a constructor. */
+ return false;
+ return true;
+}
+
/* OLDDECL is a _DECL for a template parameter. Return a similar parameter at
LEVEL:INDEX, using tsubst_args and complain for substitution into non-type
template parameter types. Note that the handling of template template
DECL_NONCONVERTING_P (ded_fn) = explicit_p;
tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false);
DECL_ARTIFICIAL (ded_tmpl) = true;
- DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn;
- TREE_TYPE (ded_tmpl) = TREE_TYPE (ded_fn);
DECL_TEMPLATE_INFO (ded_fn) = build_template_info (ded_tmpl, targs);
DECL_PRIMARY_TEMPLATE (ded_tmpl) = ded_tmpl;
if (DECL_P (ctor))
/* Add to LIST the member types for the reshaped initializer CTOR. */
static tree
-collect_ctor_idx_types (tree ctor, tree list)
+collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE)
{
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (ctor);
tree idx, val; unsigned i;
FOR_EACH_CONSTRUCTOR_ELT (v, i, idx, val)
{
+ tree ftype = elt ? elt : TREE_TYPE (idx);
if (BRACE_ENCLOSED_INITIALIZER_P (val)
- && CONSTRUCTOR_NELTS (val))
- if (tree subidx = CONSTRUCTOR_ELT (val, 0)->index)
- if (TREE_CODE (subidx) == FIELD_DECL)
- {
- list = collect_ctor_idx_types (val, list);
- continue;
- }
- tree ftype = finish_decltype_type (idx, true, tf_none);
- list = tree_cons (NULL_TREE, ftype, list);
+ && CONSTRUCTOR_NELTS (val)
+ /* As in reshape_init_r, a non-aggregate or array-of-dependent-bound
+ type gets a single initializer. */
+ && CP_AGGREGATE_TYPE_P (ftype)
+ && !(TREE_CODE (ftype) == ARRAY_TYPE
+ && uses_template_parms (TYPE_DOMAIN (ftype))))
+ {
+ tree subelt = NULL_TREE;
+ if (TREE_CODE (ftype) == ARRAY_TYPE)
+ subelt = TREE_TYPE (ftype);
+ list = collect_ctor_idx_types (val, list, subelt);
+ continue;
+ }
+ tree arg = NULL_TREE;
+ if (i == v->length() - 1
+ && PACK_EXPANSION_P (ftype))
+ /* Give the trailing pack expansion parameter a default argument to
+ match aggregate initialization behavior, even if we deduce the
+ length of the pack separately to more than we have initializers. */
+ arg = build_constructor (init_list_type_node, NULL);
+ /* if ei is of array type and xi is a braced-init-list or string literal,
+ Ti is an rvalue reference to the declared type of ei */
+ STRIP_ANY_LOCATION_WRAPPER (val);
+ if (TREE_CODE (ftype) == ARRAY_TYPE
+ && (BRACE_ENCLOSED_INITIALIZER_P (val)
+ || TREE_CODE (val) == STRING_CST))
+ {
+ if (TREE_CODE (val) == STRING_CST)
+ ftype = cp_build_qualified_type
+ (ftype, cp_type_quals (ftype) | TYPE_QUAL_CONST);
+ ftype = (cp_build_reference_type
+ (ftype, BRACE_ENCLOSED_INITIALIZER_P (val)));
+ }
+ list = tree_cons (arg, ftype, list);
}
return list;
}
if (ci)
- set_constraints (fprime, ci);
+ {
+ remove_constraints (fprime);
+ set_constraints (fprime, ci);
+ }
}
else
{
error ("%qT as type rather than plain %<decltype(auto)%>", type);
return error_mark_node;
}
+ else if (TYPE_QUALS (type) != TYPE_UNQUALIFIED)
+ {
+ if (complain & tf_error)
+ error ("%<decltype(auto)%> cannot be cv-qualified");
+ return error_mark_node;
+ }
}
else
{
return errors;
}
-/* For a given template T, return the vector of typedefs referenced
- in T for which access check is needed at T instantiation time.
- T is either a FUNCTION_DECL or a RECORD_TYPE.
- Those typedefs were added to T by the function
- append_type_to_template_for_access_check. */
-
-vec<qualified_typedef_usage_t, va_gc> *
-get_types_needing_access_check (tree t)
-{
- tree ti;
- vec<qualified_typedef_usage_t, va_gc> *result = NULL;
-
- if (!t || t == error_mark_node)
- return NULL;
-
- if (!(ti = get_template_info (t)))
- return NULL;
-
- if (CLASS_TYPE_P (t)
- || TREE_CODE (t) == FUNCTION_DECL)
- {
- if (!TI_TEMPLATE (ti))
- return NULL;
-
- result = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti);
- }
-
- return result;
-}
-
-/* Append the typedef TYPE_DECL used in template T to a list of typedefs
- tied to T. That list of typedefs will be access checked at
- T instantiation time.
- T is either a FUNCTION_DECL or a RECORD_TYPE.
- TYPE_DECL is a TYPE_DECL node representing a typedef.
- SCOPE is the scope through which TYPE_DECL is accessed.
- LOCATION is the location of the usage point of TYPE_DECL.
-
- This function is a subroutine of
- append_type_to_template_for_access_check. */
-
-static void
-append_type_to_template_for_access_check_1 (tree t,
- tree type_decl,
- tree scope,
- location_t location)
-{
- qualified_typedef_usage_t typedef_usage;
- tree ti;
-
- if (!t || t == error_mark_node)
- return;
-
- gcc_assert ((TREE_CODE (t) == FUNCTION_DECL
- || CLASS_TYPE_P (t))
- && type_decl
- && TREE_CODE (type_decl) == TYPE_DECL
- && scope);
-
- if (!(ti = get_template_info (t)))
- return;
-
- gcc_assert (TI_TEMPLATE (ti));
-
- typedef_usage.typedef_decl = type_decl;
- typedef_usage.context = scope;
- typedef_usage.locus = location;
-
- vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), typedef_usage);
-}
-
-/* Append TYPE_DECL to the template TEMPL.
- TEMPL is either a class type, a FUNCTION_DECL or a TEMPLATE_DECL.
- At TEMPL instanciation time, TYPE_DECL will be checked to see
- if it can be accessed through SCOPE.
- LOCATION is the location of the usage point of TYPE_DECL.
-
- e.g. consider the following code snippet:
-
- class C
- {
- typedef int myint;
- };
-
- template<class U> struct S
- {
- C::myint mi; // <-- usage point of the typedef C::myint
- };
-
- S<char> s;
-
- At S<char> instantiation time, we need to check the access of C::myint
- In other words, we need to check the access of the myint typedef through
- the C scope. For that purpose, this function will add the myint typedef
- and the scope C through which its being accessed to a list of typedefs
- tied to the template S. That list will be walked at template instantiation
- time and access check performed on each typedefs it contains.
- Note that this particular code snippet should yield an error because
- myint is private to C. */
-
-void
-append_type_to_template_for_access_check (tree templ,
- tree type_decl,
- tree scope,
- location_t location)
-{
- qualified_typedef_usage_t *iter;
- unsigned i;
-
- gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL));
-
- /* Make sure we don't append the type to the template twice. */
- FOR_EACH_VEC_SAFE_ELT (get_types_needing_access_check (templ), i, iter)
- if (iter->typedef_decl == type_decl && scope == iter->context)
- return;
-
- append_type_to_template_for_access_check_1 (templ, type_decl,
- scope, location);
-}
-
/* Recursively walk over && expressions searching for EXPR. Return a reference
to that expression. */
void
init_template_processing (void)
{
- /* FIXME: enable sanitization (PR87847) */
- decl_specializations = hash_table<spec_hasher>::create_ggc (37, false);
- type_specializations = hash_table<spec_hasher>::create_ggc (37, false);
+ decl_specializations = hash_table<spec_hasher>::create_ggc (37);
+ type_specializations = hash_table<spec_hasher>::create_ggc (37);
if (cxx_dialect >= cxx11)
declare_integer_pack ();