references are preserved in the result. */
expr = force_paren_expr_uneval (expr);
- /* When args is NULL, we're evaluating a non-templated requires expression,
- but even those are parsed under processing_template_decl == 1, and so the
- placeholder 'auto' inside this return-type-requirement has level 2. In
- order to have all parms and arguments match up for satisfaction, we need
- to pass an empty level of OUTER_TARGS in this case. */
- if (!args)
- args = make_tree_vec (0);
-
tree deduced_type = do_auto_deduction (type, expr, placeholder,
info.complain, adc_requirement,
/*outer_targs=*/args);
parameters for normalization. */
tree initial_parms = TREE_PURPOSE (ci);
- if (!initial_parms && TEMPLATE_TYPE_LEVEL (t) == 2)
- /* This is a return-type-requirement of a non-templated requires-expression,
- which are parsed under processing_template_decl == 1 and empty
- current_template_parms; hence the 'auto' has level 2 and initial_parms
- is empty. Fix up initial_parms to be consistent with the value of
- processing_template_decl whence the 'auto' was created. */
- initial_parms = build_tree_list (size_int (1), make_tree_vec (0));
-
/* The 'auto' itself is used as the first argument in its own constraints,
and its level is one greater than its template depth. So in order to
capture all used template parameters, we need to add an extra level of
stored in the TREE_VALUE. */
#define current_template_parms scope_chain->template_parms
+#define current_template_depth \
+ (current_template_parms ? TMPL_PARMS_DEPTH (current_template_parms) : 0)
#define processing_template_decl scope_chain->x_processing_template_decl
#define processing_specialization scope_chain->x_processing_specialization
full specialization. */
#define PROCESSING_REAL_TEMPLATE_DECL_P() \
(!processing_template_parmlist \
- && processing_template_decl > template_class_depth (current_scope ()))
+ && current_template_depth > template_class_depth (current_scope ()))
/* Nonzero if this VAR_DECL or FUNCTION_DECL has already been
instantiated, i.e. its definition has been generated from the
if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context)))
{
- bool this_tmpl = (processing_template_decl
+ bool this_tmpl = (current_template_depth
> template_class_depth (context));
if (VAR_P (decl))
{
tree ctx = friendp ? current_class_type : ctype;
bool block_local = TREE_CODE (current_scope ()) == FUNCTION_DECL;
bool memtmpl = (!block_local
- && (processing_template_decl
+ && (current_template_depth
> template_class_depth (ctx)));
if (memtmpl)
{
if (ctype != NULL_TREE && check)
{
tree old_decl = check_classfn (ctype, decl,
- (processing_template_decl
+ (current_template_depth
> template_class_depth (ctype))
? current_template_parms
: NULL_TREE);
}
}
else if (flag_concepts
- && processing_template_decl > template_class_depth (scope))
+ && current_template_depth > template_class_depth (scope))
{
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
tree ci = build_constraints (reqs, NULL_TREE);
}
/* Set the constraints on the declaration. */
- bool memtmpl = (processing_template_decl
+ bool memtmpl = (current_template_depth
> template_class_depth (current_class_type));
if (memtmpl)
{
The friend is a template friend iff FRIEND_DEPTH is nonzero. */
int class_template_depth = template_class_depth (type);
- int friend_depth = processing_template_decl - class_template_depth;
+ int friend_depth = 0;
+ if (current_template_depth)
+ /* When processing a friend declaration at parse time, just compare the
+ current depth to that of the class template. */
+ friend_depth = current_template_depth - class_template_depth;
+ else
+ {
+ /* Otherwise, we got here from instantiate_class_template. Determine
+ the friend depth by looking at the template parameters used within
+ FRIEND_TYPE. */
+ gcc_checking_assert (class_template_depth == 0);
+ while (uses_template_parms_level (friend_type, friend_depth + 1))
+ ++friend_depth;
+ }
if (! MAYBE_CLASS_TYPE_P (friend_type)
&& TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM)
tree name = TYPE_IDENTIFIER (friend_type);
tree decl;
- if (!uses_template_parms_level (ctype, class_template_depth
- + friend_depth))
+ /* We need to distinguish a TYPENAME_TYPE for the non-template
+ class B in
+ template<class T> friend class A<T>::B;
+ vs for the class template B in
+ template<class T> template<class U> friend class A<T>::B; */
+ if (current_template_depth
+ && !uses_template_parms_level (ctype, current_template_depth))
template_member_p = true;
if (class_template_depth)
3. TEMPLATE_MEMBER_P is true (for `W'). */
int class_template_depth = template_class_depth (current_class_type);
- int friend_depth = processing_template_decl - class_template_depth;
+ int friend_depth = current_template_depth - class_template_depth;
/* We will figure this out later. */
bool template_member_p = false;
cp_parser_requires_clause_expression (cp_parser *parser, bool lambda_p)
{
processing_constraint_expression_sentinel parsing_constraint;
- temp_override<int> ovr (processing_template_decl);
- if (!processing_template_decl)
- /* Adjust processing_template_decl so that we always obtain template
- trees here. We don't do the usual ++processing_template_decl
- because that would skew the template parameter depth of a lambda
- within if we're already inside a template. */
- processing_template_decl = 1;
+ ++processing_template_decl;
cp_expr expr = cp_parser_constraint_logical_or_expression (parser, lambda_p);
+ --processing_template_decl;
if (check_for_bare_parameter_packs (expr))
expr = error_mark_node;
return expr;
cp_parser_constraint_expression (cp_parser *parser)
{
processing_constraint_expression_sentinel parsing_constraint;
- temp_override<int> ovr (processing_template_decl);
- if (!processing_template_decl)
- /* As in cp_parser_requires_clause_expression. */
- processing_template_decl = 1;
+ ++processing_template_decl;
cp_expr expr = cp_parser_binary_expression (parser, false, true,
PREC_NOT_OPERATOR, NULL);
+ --processing_template_decl;
if (check_for_bare_parameter_packs (expr))
expr = error_mark_node;
expr.maybe_add_location_wrapper ();
parms = NULL_TREE;
/* Parse the requirement body. */
- temp_override<int> ovr (processing_template_decl);
- if (!processing_template_decl)
- /* As in cp_parser_requires_clause_expression. */
- processing_template_decl = 1;
+ ++processing_template_decl;
reqs = cp_parser_requirement_body (parser);
+ --processing_template_decl;
if (reqs == error_mark_node)
return error_mark_node;
}
gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL);
synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
+ if (become_template)
+ current_template_parms = tree_cons (size_int (current_template_depth + 1),
+ NULL_TREE, current_template_parms);
+
/* Attach the constraint to the parm before processing. */
tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
TREE_TYPE (node) = constr;
tree new_parms = make_tree_vec (1);
TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms;
- current_template_parms = tree_cons (size_int (processing_template_decl),
- new_parms, current_template_parms);
+ TREE_VALUE (current_template_parms) = new_parms;
}
else
{
return false;
return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (most_general_template (decl)))
- > (processing_template_decl + DECL_TEMPLATE_SPECIALIZATION (decl)));
+ > (current_template_depth + DECL_TEMPLATE_SPECIALIZATION (decl)));
}
/* Subroutine of maybe_begin_member_template_processing.
++processing_template_decl;
current_template_parms
- = tree_cons (size_int (processing_template_decl),
+ = tree_cons (size_int (current_template_depth + 1),
parms, current_template_parms);
TEMPLATE_PARMS_FOR_INLINE (current_template_parms) = 1;
if (inline_needs_template_parms (decl, nsdmi))
{
parms = DECL_TEMPLATE_PARMS (most_general_template (decl));
- levels = TMPL_PARMS_DEPTH (parms) - processing_template_decl;
+ levels = TMPL_PARMS_DEPTH (parms) - current_template_depth;
if (DECL_TEMPLATE_SPECIALIZATION (decl))
{
/* Add a dummy parameter level while we process the parameter list. */
current_template_parms
- = tree_cons (size_int (processing_template_decl),
+ = tree_cons (size_int (current_template_depth + 1),
make_tree_vec (0),
current_template_parms);
}
TREE_CONSTANT (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_INITIAL (parm) = DECL_INITIAL (decl)
- = build_template_parm_index (idx, processing_template_decl,
- processing_template_decl,
+ = build_template_parm_index (idx, current_template_depth,
+ current_template_depth,
decl, TREE_TYPE (parm));
TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
TYPE_STUB_DECL (t) = decl;
parm = decl;
TEMPLATE_TYPE_PARM_INDEX (t)
- = build_template_parm_index (idx, processing_template_decl,
- processing_template_decl,
+ = build_template_parm_index (idx, current_template_depth,
+ current_template_depth,
decl, TREE_TYPE (parm));
TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
current_template_parms = TREE_CHAIN (current_template_parms);
current_template_parms
- = tree_cons (size_int (processing_template_decl),
+ = tree_cons (size_int (current_template_depth + 1),
saved_parmlist, current_template_parms);
for (unsigned ix = 0; parms; ix++)
/* See if this is a primary template. */
bool is_primary = false;
if (is_friend && ctx
- && uses_template_parms_level (ctx, processing_template_decl))
+ && uses_template_parms_level (ctx, current_template_depth))
/* A friend template that specifies a class context, i.e.
template <typename T> friend void A<T>::f();
is not primary. */
= INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (inherited));
inner_parms = copy_node (inner_parms);
tree parms
- = tree_cons (size_int (processing_template_decl + 1),
+ = tree_cons (size_int (current_template_depth + 1),
inner_parms, current_template_parms);
tree tmpl = build_template_decl (fn, parms, /*member*/true);
tree args = template_parms_to_args (parms);
/* Build new CLASSTYPE_FRIEND_CLASSES. */
tree friend_type = t;
- bool adjust_processing_template_decl = false;
-
if (TREE_CODE (friend_type) == TEMPLATE_DECL)
{
/* template <class T> friend class C; */
friend_type = tsubst_friend_class (friend_type, args);
- adjust_processing_template_decl = true;
}
else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
{
tf_warning_or_error, NULL_TREE);
if (TREE_CODE (friend_type) == TEMPLATE_DECL)
friend_type = TREE_TYPE (friend_type);
- adjust_processing_template_decl = true;
}
else if (TREE_CODE (friend_type) == TYPENAME_TYPE
|| TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
++processing_template_decl;
friend_type = tsubst (friend_type, args,
tf_warning_or_error, NULL_TREE);
- if (dependent_type_p (friend_type))
- adjust_processing_template_decl = true;
--processing_template_decl;
}
else if (uses_template_parms (friend_type))
We don't have to do anything in these cases. */
- if (adjust_processing_template_decl)
- /* Trick make_friend_class into realizing that the friend
- we're adding is a template, not an ordinary class. It's
- important that we use make_friend_class since it will
- perform some error-checking and output cross-reference
- information. */
- ++processing_template_decl;
-
if (friend_type != error_mark_node)
make_friend_class (type, friend_type, /*complain=*/false);
-
- if (adjust_processing_template_decl)
- --processing_template_decl;
}
else
{
TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au);
TYPE_STUB_DECL (au) = TYPE_NAME (au);
TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
- (0, processing_template_decl + 1, processing_template_decl + 1,
+ (0, current_template_depth + 1, current_template_depth + 1,
TYPE_NAME (au), NULL_TREE);
if (set_canonical)
TYPE_CANONICAL (au) = canonical_type_parameter (au);
}
if (tree auto_node = find_type_usage (type, is_auto))
- if (TEMPLATE_TYPE_LEVEL (auto_node) <= processing_template_decl)
+ if (TEMPLATE_TYPE_LEVEL (auto_node) <= current_template_depth)
{
/* In an abbreviated function template we didn't know we were dealing
with a function template when we saw the auto return type, so rebuild
// the scope we're trying to enter.
tree parms = current_template_parms;
int depth = template_class_depth (type);
- for (int n = processing_template_decl; n > depth && parms; --n)
+ for (int n = current_template_depth; n > depth && parms; --n)
parms = TREE_CHAIN (parms);
if (!parms)
return type;
// PR c++/100055
// { dg-do compile { target concepts } }
-void foo(auto&& arg) requires({}); // { dg-error "statement-expressions are not allowed|braced-groups" }
+void foo(auto&& arg) requires({}); // { dg-error "statement-expressions are not allowed|braced-groups|non-templated" }
template <auto = 0> requires ([]{}()); // { dg-error "expected unqualified-id" }
-auto f() requires ([]{}());
+auto f() requires ([]{}()); // { dg-error "constraints on a non-templated" }
--- /dev/null
+// PR c++/103408
+// { dg-do compile { target c++23 } }
+
+static_assert(requires { auto(0); });
+static_assert(requires { auto{0}; });
+
+static_assert(requires { auto(auto(0)); });
+static_assert(requires { auto{auto{0}}; });
+
+static_assert(requires { auto(auto(auto(0))); });
+static_assert(requires { auto{auto{auto{0}}}; });
+
+static_assert(requires { requires auto(true); });
+static_assert(requires { requires auto(auto(true)); });
+
+static_assert(!requires { requires auto(false); });
+static_assert(!requires { requires auto(auto(false)); });
+
+auto f() requires (auto(false)); // { dg-error "constraints on non-templated" }