return decl;
}
-/* Given the predicate constraint T from a placeholder type, extract its
- TMPL and ARGS. */
+/* Given the predicate constraint T from a constrained-type-specifier, extract
+ its TMPL and ARGS. FIXME why do we need two different forms of
+ constrained-type-specifier? */
void
placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
{
+ if (TREE_CODE (t) == TYPE_DECL)
+ {
+ /* A constrained parameter. */
+ tmpl = DECL_TI_TEMPLATE (CONSTRAINED_PARM_CONCEPT (t));
+ args = CONSTRAINED_PARM_EXTRA_ARGS (t);
+ return;
+ }
+
gcc_assert (TREE_CODE (t) == PRED_CONSTR);
t = PRED_CONSTR_EXPR (t);
gcc_assert (TREE_CODE (t) == CALL_EXPR
bool
equivalent_placeholder_constraints (tree c1, tree c2)
{
- if (TREE_CODE (c1) == TEMPLATE_TYPE_PARM)
+ if (c1 && TREE_CODE (c1) == TEMPLATE_TYPE_PARM)
+ /* A constrained auto. */
c1 = PLACEHOLDER_TYPE_CONSTRAINTS (c1);
- if (TREE_CODE (c2) == TEMPLATE_TYPE_PARM)
+ if (c2 && TREE_CODE (c2) == TEMPLATE_TYPE_PARM)
c2 = PLACEHOLDER_TYPE_CONSTRAINTS (c2);
if (c1 == c2)
if (t1 != t2)
return false;
- int len = TREE_VEC_LENGTH (a1);
- if (len != TREE_VEC_LENGTH (a2))
- return false;
+
/* Skip the first argument to avoid infinite recursion on the
placeholder auto itself. */
- for (int i = len-1; i > 0; --i)
- if (!cp_tree_equal (TREE_VEC_ELT (a1, i),
- TREE_VEC_ELT (a2, i)))
+ bool skip1 = (TREE_CODE (c1) == PRED_CONSTR);
+ bool skip2 = (TREE_CODE (c2) == PRED_CONSTR);
+
+ int len1 = (a1 ? TREE_VEC_LENGTH (a1) : 0) - skip1;
+ int len2 = (a2 ? TREE_VEC_LENGTH (a2) : 0) - skip2;
+
+ if (len1 != len2)
+ return false;
+
+ for (int i = 0; i < len1; ++i)
+ if (!cp_tree_equal (TREE_VEC_ELT (a1, i + skip1),
+ TREE_VEC_ELT (a2, i + skip2)))
return false;
return true;
}
return error_mark_node;
}
-/* Finish parsing/processing a template template parameter by borrowing
- the template parameter list from the prototype parameter. */
-
static tree
-cp_parser_constrained_template_template_parm (cp_parser *parser,
- tree proto,
- tree id,
- cp_parameter_declarator *parmdecl)
+finish_constrained_template_template_parm (tree proto, tree id)
{
- if (!cp_parser_check_constrained_type_parm (parser, parmdecl))
- return error_mark_node;
-
/* FIXME: This should probably be copied, and we may need to adjust
the template parameter depths. */
tree saved_parms = current_template_parms;
return parm;
}
+/* Finish parsing/processing a template template parameter by borrowing
+ the template parameter list from the prototype parameter. */
+
+static tree
+cp_parser_constrained_template_template_parm (cp_parser *parser,
+ tree proto,
+ tree id,
+ cp_parameter_declarator *parmdecl)
+{
+ if (!cp_parser_check_constrained_type_parm (parser, parmdecl))
+ return error_mark_node;
+ return finish_constrained_template_template_parm (proto, id);
+}
+
/* Create a new non-type template parameter from the given PARM
declarator. */
/*check_dependency=*/true,
/*ambiguous_decls=*/NULL,
argument_start_token->location);
- if (TREE_CODE (argument) != TEMPLATE_DECL
- && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
+ /* Handle a constrained-type-specifier for a non-type template
+ parameter. */
+ if (tree decl = cp_parser_maybe_concept_name (parser, argument))
+ argument = decl;
+ else if (TREE_CODE (argument) != TEMPLATE_DECL
+ && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
cp_parser_error (parser, "expected template-name");
}
if (cp_parser_parse_definitely (parser))
}
if (cxx_dialect >= cxx14)
- type = synthesize_implicit_template_parm (parser, NULL_TREE);
+ {
+ type = synthesize_implicit_template_parm (parser, NULL_TREE);
+ type = TREE_TYPE (type);
+ }
else
type = error_mark_node;
return type_decl;
}
-/* Returns true if proto is a type parameter, but not a template
- template parameter. */
-static bool
-check_type_concept (tree fn, tree proto)
-{
- if (TREE_CODE (proto) != TYPE_DECL)
- {
- error ("invalid use of non-type concept %qD", fn);
- return false;
- }
- return true;
-}
-
/* Check if DECL and ARGS can form a constrained-type-specifier.
If ARGS is non-null, we try to form a concept check of the
form DECL<?, ARGS> where ? is a wildcard that matches any
if (processing_template_parmlist)
return build_constrained_parameter (conc, proto, args);
- /* In any other context, a concept must be a type concept.
-
- FIXME: A constrained-type-specifier can be a placeholder
- of any kind. */
- if (!check_type_concept (conc, proto))
- return error_mark_node;
-
/* In a parameter-declaration-clause, constrained-type
specifiers result in invented template parameters. */
if (parser->auto_is_implicit_function_template_parm_p)
static tree
cp_parser_maybe_concept_name (cp_parser* parser, tree decl)
{
- return cp_parser_maybe_constrained_type_specifier (parser, decl, NULL_TREE);
+ if (flag_concepts
+ && (TREE_CODE (decl) == OVERLOAD
+ || BASELINK_P (decl)
+ || variable_concept_p (decl)))
+ return cp_parser_maybe_constrained_type_specifier (parser, decl, NULL_TREE);
+ else
+ return NULL_TREE;
}
/* Check if DECL and ARGS form a partial-concept-id. If so,
type_decl = strip_using_decl (type_decl);
/* If we found an overload set, then it may refer to a concept-name. */
- if (flag_concepts
- && (TREE_CODE (type_decl) == OVERLOAD
- || BASELINK_P (type_decl)
- || variable_concept_p (type_decl)))
- {
- /* Determine whether the overload refers to a concept. */
- if (tree decl = cp_parser_maybe_concept_name (parser, type_decl))
- return decl;
- }
+ if (tree decl = cp_parser_maybe_concept_name (parser, type_decl))
+ type_decl = decl;
if (TREE_CODE (type_decl) != TYPE_DECL
&& (objc_is_id (identifier) || objc_is_class_name (identifier)))
"attributes after parenthesized initializer ignored");
/* And now complain about a non-function implicit template. */
- if (bogus_implicit_tmpl)
+ if (bogus_implicit_tmpl && decl != error_mark_node)
error_at (DECL_SOURCE_LOCATION (decl),
"non-function %qD declared as implicit template", decl);
return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t));
}
-/* Returns the template declaration being called or evaluated as
- part of the constraint check. Note that T must be a predicate
- constraint (it can't be any other kind of constraint). */
-static tree
-get_concept_from_constraint (tree t)
-{
- tree tmpl, args;
- placeholder_extract_concept_and_args (t, tmpl, args);
- return DECL_TEMPLATE_RESULT (tmpl);
-}
-
/* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS
(creating a new template parameter list if necessary). Returns the newly
created template type parm. */
tree t = parser->implicit_template_parms;
while (t)
{
- tree c = get_concept_from_constraint (TREE_TYPE (t));
- if (c == CONSTRAINED_PARM_CONCEPT (constr))
- return TREE_VALUE (t);
+ if (equivalent_placeholder_constraints (TREE_TYPE (t), constr))
+ {
+ tree d = TREE_VALUE (t);
+ if (TREE_CODE (d) == PARM_DECL)
+ /* Return the TEMPLATE_PARM_INDEX. */
+ d = DECL_INITIAL (d);
+ return d;
+ }
t = TREE_CHAIN (t);
}
}
/* Synthesize a new template parameter and track the current template
parameter chain with implicit_template_parms. */
+ tree proto = constr ? DECL_INITIAL (constr) : NULL_TREE;
tree synth_id = make_generic_type_name ();
- tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
- synth_id);
+ tree synth_tmpl_parm;
+ bool non_type = false;
+
+ if (proto == NULL_TREE || TREE_CODE (proto) == TYPE_DECL)
+ synth_tmpl_parm
+ = finish_template_type_parm (class_type_node, synth_id);
+ else if (TREE_CODE (proto) == TEMPLATE_DECL)
+ synth_tmpl_parm
+ = finish_constrained_template_template_parm (proto, synth_id);
+ else
+ {
+ synth_tmpl_parm = copy_decl (proto);
+ DECL_NAME (synth_tmpl_parm) = synth_id;
+ non_type = true;
+ }
// Attach the constraint to the parm before processing.
tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
= process_template_parm (parser->implicit_template_parms,
input_location,
node,
- /*non_type=*/false,
+ /*non_type=*/non_type,
/*param_pack=*/false);
// Chain the new parameter to the list of implicit parameters.
else
parser->implicit_template_parms = new_parm;
- tree new_type = TREE_TYPE (getdecls ());
+ tree new_decl = getdecls ();
+ if (non_type)
+ /* Return the TEMPLATE_PARM_INDEX, not the PARM_DECL. */
+ new_decl = DECL_INITIAL (new_decl);
/* If creating a fully implicit function template, start the new implicit
template parameter list with this synthesized type, otherwise grow the
current_binding_level = entry_scope;
- return new_type;
+ return new_decl;
}
/* Finish the declaration of a fully implicit function template. Such a