done only after the requires clause has been parsed (or not). */
tree
-finish_shorthand_constraint (tree decl, tree constr)
+finish_shorthand_constraint (tree decl, tree constr, bool is_non_type)
{
/* No requirements means no constraints. */
if (!constr)
if (error_operand_p (constr))
return NULL_TREE;
- tree proto = CONSTRAINED_PARM_PROTOTYPE (constr);
- tree con = CONSTRAINED_PARM_CONCEPT (constr);
- tree args = CONSTRAINED_PARM_EXTRA_ARGS (constr);
+ tree proto, con, args;
+ if (is_non_type)
+ {
+ /* This function should not see constrained auto&, auto* NTTPs, and a
+ simple constrained auto NTTP type should by now have been replaced
+ by ordinary auto; see finish_constrained_parameter. */
+ gcc_checking_assert (is_auto (TREE_TYPE (decl))
+ && !is_constrained_auto (TREE_TYPE (decl)));
+ gcc_checking_assert (TREE_CODE (constr) == TEMPLATE_ID_EXPR);
+ tree tmpl = TREE_OPERAND (constr, 0);
+ proto = concept_prototype_parameter (tmpl);
+ con = DECL_TEMPLATE_RESULT (tmpl);
+ args = TREE_OPERAND (constr, 1);
+ }
+ else
+ {
+ proto = CONSTRAINED_PARM_PROTOTYPE (constr);
+ con = CONSTRAINED_PARM_CONCEPT (constr);
+ args = CONSTRAINED_PARM_EXTRA_ARGS (constr);
+ }
bool variadic_concept_p = template_parameter_pack_p (proto);
bool declared_pack_p = template_parameter_pack_p (decl);
/* Build the concept constraint-expression. */
tree tmpl = DECL_TI_TEMPLATE (con);
- tree check = build_concept_check (tmpl, arg, args, tf_warning_or_error);
+ tree check;
+ if (is_non_type)
+ {
+ arg = finish_decltype_type (arg, /*id_expr=*/true, tf_warning_or_error);
+ if (ARGUMENT_PACK_P (TREE_VEC_ELT (args, 0)))
+ args = expand_template_argument_pack (args);
+ else
+ args = copy_template_args (args);
+ TREE_VEC_ELT (args, 0) = arg;
+ check = build_concept_check (tmpl, args, tf_warning_or_error);
+ }
+ else
+ check = build_concept_check (tmpl, arg, args, tf_warning_or_error);
/* Make the check a fold-expression if needed.
Use UNKNOWN_LOCATION so write_template_args can tell the
extern bool comp_template_args (tree, tree, tree * = NULL,
tree * = NULL);
extern int template_args_equal (tree, tree);
+extern tree copy_template_args (tree);
+extern tree expand_template_argument_pack (tree);
extern tree maybe_process_partial_specialization (tree);
extern tree most_specialized_instantiation (tree);
extern tree most_specialized_partial_spec (tree, tsubst_flags_t, bool = false);
extern tree build_constrained_parameter (tree, tree, tree = NULL_TREE);
extern bool equivalent_placeholder_constraints (tree, tree);
extern hashval_t iterative_hash_placeholder_constraint (tree, hashval_t);
-extern tree finish_shorthand_constraint (tree, tree);
+extern tree finish_shorthand_constraint (tree, tree, bool);
extern tree finish_requires_expr (location_t, tree, tree);
extern tree finish_simple_requirement (location_t, tree);
extern tree finish_type_requirement (location_t, tree);
write_string ("Tn");
tree type = TREE_TYPE (decl);
+ /* TODO: We need to also mangle constrained auto*, auto&, etc, but
+ it's not clear how. See finish_constrained_parameter. */
if (tree c = (is_auto (type)
- ? PLACEHOLDER_TYPE_CONSTRAINTS (type)
+ ? TEMPLATE_PARM_CONSTRAINTS (parm)
: NULL_TREE))
{
if (AUTO_IS_DECLTYPE (type))
return true;
}
-/* Finish parsing/processing a template type parameter and checking
- various restrictions. */
-
-static inline tree
-cp_parser_constrained_type_template_parm (cp_parser *parser,
- tree id,
- cp_parameter_declarator* parmdecl)
-{
- if (cp_parser_check_constrained_type_parm (parser, parmdecl))
- return finish_template_type_parm (class_type_node, id);
- else
- return error_mark_node;
-}
-
-/* Create a new non-type template parameter from the given PARM
- declarator. */
-
-static tree
-cp_parser_constrained_non_type_template_parm (bool *is_non_type,
- cp_parameter_declarator *parm)
-{
- *is_non_type = true;
- cp_declarator *decl = parm->declarator;
- cp_decl_specifier_seq *specs = &parm->decl_specifiers;
- specs->type = TREE_TYPE (DECL_INITIAL (specs->type));
- return grokdeclarator (decl, specs, TPARM, 0, NULL);
-}
-
/* Build a constrained template parameter based on the PARMDECL
declarator. The type of PARMDECL is the constrained type, which
refers to the prototype template parameter that ultimately
cp_parameter_declarator *parmdecl,
bool *is_non_type)
{
- tree decl = parmdecl->decl_specifiers.type;
+ tree constr = parmdecl->decl_specifiers.type;
tree id = get_unqualified_id (parmdecl->declarator);
tree def = parmdecl->default_argument;
- tree proto = DECL_INITIAL (decl);
/* Build the parameter. Return an error if the declarator was invalid. */
+ bool set_template_parm_constraints_p = true;
tree parm;
- if (TREE_CODE (proto) == TYPE_DECL)
- parm = cp_parser_constrained_type_template_parm (parser, id, parmdecl);
+ if (is_constrained_auto (constr))
+ {
+ /* Constrained non-type parameter. */
+ *is_non_type = true;
+ if (!parmdecl->declarator
+ || parmdecl->declarator->kind == cdk_id)
+ /* For a simple constrained auto NTTP, move its constraint from
+ PLACEHOLDER_TYPE_CONSTRAINTS to TEMPLATE_PARM_CONSTRAINTS to
+ eventually include them in the template's associated constraints.
+ finish_shorthand_constraint will convert the constraint to its
+ final form. */
+ parmdecl->decl_specifiers.type = (AUTO_IS_DECLTYPE (constr)
+ ? make_decltype_auto ()
+ : make_auto ());
+ else
+ /* ??? For constrained auto*, auto& etc it's not clear how to represent
+ the type-constraint as an associated constraint (we need it in terms
+ of the pointed-to type). We keep it in PLACEHOLDER_TYPE_CONSTRAINTS
+ and effectively treat it like a non-NTTP constrained auto. */
+ set_template_parm_constraints_p = false;
+ parm = grokdeclarator (parmdecl->declarator,
+ &parmdecl->decl_specifiers,
+ TPARM, /*initialized=*/0, /*attrlist=*/NULL);
+ }
else
- parm = cp_parser_constrained_non_type_template_parm (is_non_type, parmdecl);
+ {
+ /* Constrained type parameter. */
+ gcc_checking_assert (CONSTRAINED_PARM_CONCEPT (constr));
+ if (cp_parser_check_constrained_type_parm (parser, parmdecl))
+ parm = finish_template_type_parm (class_type_node, id);
+ else
+ parm = error_mark_node;
+ }
if (parm == error_mark_node)
return error_mark_node;
/* Finish the parameter decl and create a node attaching the
default argument and constraint. */
parm = build_tree_list (def, parm);
- TEMPLATE_PARM_CONSTRAINTS (parm) = decl;
+ if (set_template_parm_constraints_p)
+ {
+ if (*is_non_type)
+ TEMPLATE_PARM_CONSTRAINTS (parm)
+ = PLACEHOLDER_TYPE_CONSTRAINTS (constr);
+ else
+ TEMPLATE_PARM_CONSTRAINTS (parm) = constr;
+ }
return parm;
}
}
/* The parameter may have been constrained type parameter. */
- if (declares_constrained_type_template_parameter (parameter_declarator))
+ tree type = parameter_declarator->decl_specifiers.type;
+ if (declares_constrained_type_template_parameter (parameter_declarator)
+ || (type && is_constrained_auto (type)))
return finish_constrained_parameter (parser,
parameter_declarator,
is_non_type);
tsubst_flags_t, int, tree);
static tree for_each_template_parm (tree, tree_fn_t, void*,
hash_set<tree> *, bool, tree_fn_t = NULL);
-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 push_inline_template_parms_recursive (tree, int);
static int check_cv_quals_for_unify (int, tree, tree);
static int unify_pack_expansion (tree, tree, tree,
tree, unification_kind_t, bool, bool);
-static tree copy_template_args (tree);
static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
static void tsubst_each_template_parm_constraints (tree, tree, tsubst_flags_t);
static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
tree decl = NULL_TREE;
tree defval = TREE_PURPOSE (parm);
- tree constr = TREE_TYPE (parm);
+ tree constr = TEMPLATE_PARM_CONSTRAINTS (parm);
if (is_non_type)
{
/* Build requirements for the type/template parameter.
This must be done after SET_DECL_TEMPLATE_PARM_P or
process_template_parm could fail. */
- tree reqs = finish_shorthand_constraint (parm, constr);
+ tree reqs = finish_shorthand_constraint (parm, constr, is_non_type);
decl = pushdecl (decl);
if (!is_non_type)
/* Return an exact copy of template args T that can be modified
independently. */
-static tree
+tree
copy_template_args (tree t)
{
if (t == error_mark_node)
/* Our canonical type depends on the constraint. */
TYPE_CANONICAL (type) = canonical_type_parameter (type);
- /* Attach the constraint to the type declaration. */
- return TYPE_NAME (type);
+ return type;
}
/* Make a "constrained auto" type-specifier. */
/* Constraints will be checked after deduction. */;
else if (tree constr = NON_ERROR (PLACEHOLDER_TYPE_CONSTRAINTS (auto_node)))
{
+ if (context == adc_unify)
+ /* Simple constrained auto NTTPs should have gotten their constraint
+ moved to the template's associated constraints. */
+ gcc_checking_assert (type != auto_node);
+
if (processing_template_decl)
{
gcc_checking_assert (context == adc_variable_type
}
Set<bool> sb;
-Set<float> sf; // { dg-error "placeholder constraints not satisfied" }
+Set<float> sf; // { dg-error "constraint failure" }
A<false>::g(X<0>{}); // { dg-error "no match|constraints" }
bool v1 = A<true>::value<0>;
- bool v2 = A<false>::value<0>; // { dg-error "constraints" }
+ bool v2 = A<false>::value<0>; // { dg-error "invalid variable template" }
A<true>::D<0> d1;
- A<false>::D<0> d2; // { dg-error "constraints" }
+ A<false>::D<0> d2; // { dg-error "constraint failure" }
}
};
constexpr auto cc = pc {};
-constexpr auto mmcc = m <cc> {}; // { dg-error "not satisfied" }
+constexpr auto mmcc = m <cc> {}; // { dg-error "constraint failure" }
--- /dev/null
+// { dg-do compile { target c++20 } }
+// Verify partial ordering with respect to associated constraints
+// works in the presence of constrained NTTPs.
+
+template<class T> concept C = true;
+
+template<class T> concept D = C<T> && true;
+
+template<class T> concept E = true;
+
+template<C auto V> void f() = delete;
+template<D auto V> void f(); // more constrained
+
+template<C auto V> void g();
+template<C auto V> void g(); // redeclaration
+
+template<C auto V> void h();
+template<E auto V> void h(); // ambiguous
+
+template<C auto V> struct A;
+template<D auto V> struct A<V> { }; // more constrained
+
+template<D auto V> struct B;
+template<C auto V> struct B<V> { }; // { dg-error "not more constrained" }
+
+int main() {
+ f<0>();
+ g<0>();
+ h<0>(); // { dg-error "ambiguous" }
+ A<0> a;
+}
template<Int auto X = false> struct S2 { };
S1<> s1; // { dg-error "constraint failure" }
-S2<> s2; // { dg-error "placeholder constraints not satisfied" }
+S2<> s2; // { dg-error "constraint failure" }
S3<int, int, char> x0; // { dg-error "template constraint failure" }
template<Int auto... Xs> struct S4 { }; // requires (C<X> && ...) with each X deduced
-S4<0, 1, 2, 'a'> x1; // { dg-error "placeholder constraints not satisfied" }
+S4<0, 1, 2, 'a'> x1; // { dg-error "template constraint failure" }