return TREE_OPERAND (t, 0);
}
-/*---------------------------------------------------------------------------
- Resolution of qualified concept names
----------------------------------------------------------------------------*/
-
-/* This facility is used to resolve constraint checks from requirement
- expressions. A constraint check is a call to a function template declared
- with the keyword 'concept'.
-
- The result of resolution is a pair (a TREE_LIST) whose value is the
- matched declaration, and whose purpose contains the coerced template
- arguments that can be substituted into the call. */
-
-/* Returns a pair containing the checked concept and its associated
- prototype parameter. The result is a TREE_LIST whose TREE_VALUE
- is the concept (non-template) and whose TREE_PURPOSE contains
- the converted template arguments, including the deduced prototype
- parameter (in position 0). */
-
-tree
-resolve_concept_check (tree check)
-{
- gcc_assert (concept_check_p (check));
- tree tmpl = TREE_OPERAND (check, 0);
- tree args = TREE_OPERAND (check, 1);
- tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
- ++processing_template_decl;
- tree result = coerce_template_parms (parms, args, tmpl, tf_none);
- --processing_template_decl;
- if (result == error_mark_node)
- return error_mark_node;
- return build_tree_list (result, DECL_TEMPLATE_RESULT (tmpl));
-}
-
-/* Given a call expression or template-id expression to a concept EXPR
- possibly including a wildcard, deduce the concept being checked and
- the prototype parameter. Returns true if the constraint and prototype
- can be deduced and false otherwise. Note that the CHECK and PROTO
- arguments are set to NULL_TREE if this returns false. */
-
-bool
-deduce_constrained_parameter (tree expr, tree& check, tree& proto)
-{
- tree info = resolve_concept_check (expr);
- if (info && info != error_mark_node)
- {
- check = TREE_VALUE (info);
- tree arg = TREE_VEC_ELT (TREE_PURPOSE (info), 0);
- if (ARGUMENT_PACK_P (arg))
- arg = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg), 0);
- proto = TREE_TYPE (arg);
- return true;
- }
-
- check = proto = NULL_TREE;
- return false;
-}
-
-/* Build a constrained placeholder type where SPEC is a type-constraint.
- SPEC can be anything were concept_definition_p is true.
-
- Returns a pair whose FIRST is the concept being checked and whose
- SECOND is the prototype parameter. */
-
-tree_pair
-finish_type_constraints (tree spec, tree args, tsubst_flags_t complain)
-{
- gcc_assert (concept_definition_p (spec));
-
- /* Build an initial concept check. */
- tree check = build_type_constraint (spec, args, complain);
- if (check == error_mark_node)
- return std::make_pair (error_mark_node, NULL_TREE);
-
- /* Extract the concept and prototype parameter from the check. */
- tree con;
- tree proto;
- if (!deduce_constrained_parameter (check, con, proto))
- return std::make_pair (error_mark_node, NULL_TREE);
-
- return std::make_pair (con, proto);
-}
-
/*---------------------------------------------------------------------------
Expansion of concept definitions
---------------------------------------------------------------------------*/
/* Construct a sequence of template arguments by prepending
ARG to REST. Either ARG or REST may be null. */
+
static tree
build_concept_check_arguments (tree arg, tree rest)
{
- gcc_assert (rest ? TREE_CODE (rest) == TREE_VEC : true);
+ gcc_assert (!rest || TREE_CODE (rest) == TREE_VEC);
tree args;
if (arg)
{
SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, def + 1);
}
else
- {
- args = rest;
- }
+ args = rest;
return args;
}
-/* Builds an id-expression of the form `C<Args...>` where C is a standard
- concept. */
-
-static tree
-build_standard_check (tree tmpl, tree args, tsubst_flags_t complain)
-{
- gcc_assert (concept_definition_p (tmpl));
- gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
- if (TREE_DEPRECATED (DECL_TEMPLATE_RESULT (tmpl)))
- warn_deprecated_use (DECL_TEMPLATE_RESULT (tmpl), NULL_TREE);
- tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
- args = coerce_template_parms (parms, args, tmpl, complain);
- if (args == error_mark_node)
- return error_mark_node;
- return build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
-}
-
-/* Construct an expression that checks TARGET using ARGS. */
+/* Construct an expression that checks TMPL using ARGS. */
tree
-build_concept_check (tree target, tree args, tsubst_flags_t complain)
+build_concept_check (tree tmpl, tree args, tsubst_flags_t complain)
{
- return build_concept_check (target, NULL_TREE, args, complain);
+ return build_concept_check (tmpl, NULL_TREE, args, complain);
}
-/* Construct an expression that checks the concept given by DECL. If
- concept_definition_p (DECL) is false, this returns null. */
+/* Construct an expression that checks the concept given by TMPL. */
tree
-build_concept_check (tree decl, tree arg, tree rest, tsubst_flags_t complain)
+build_concept_check (tree tmpl, tree arg, tree rest, tsubst_flags_t complain)
{
- tree args = build_concept_check_arguments (arg, rest);
-
- if (concept_definition_p (decl))
- return build_standard_check (decl, args, complain);
+ if (TREE_DEPRECATED (DECL_TEMPLATE_RESULT (tmpl)))
+ warn_deprecated_use (DECL_TEMPLATE_RESULT (tmpl), NULL_TREE);
- return error_mark_node;
+ tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+ tree args = build_concept_check_arguments (arg, rest);
+ args = coerce_template_parms (parms, args, tmpl, complain);
+ if (args == error_mark_node)
+ return error_mark_node;
+ return build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
}
/* Build a template-id that can participate in a concept check. */
tree
build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
{
- tree wildcard = build_nt (WILDCARD_DECL);
+ tree proto = template_parm_to_arg (concept_prototype_parameter (decl));
++processing_template_decl;
- tree check = build_concept_check (decl, wildcard, args, complain);
+ tree check = build_concept_check (decl, proto, args, complain);
--processing_template_decl;
return check;
}
/* Build the concept constraint-expression. */
tree tmpl = DECL_TI_TEMPLATE (con);
- tree check = tmpl;
- if (TREE_CODE (con) == FUNCTION_DECL)
- check = ovl_make (tmpl);
- check = build_concept_check (check, arg, args, tf_warning_or_error);
+ tree 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
return result;
}
-/* Given the concept check 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 (concept_check_p (t))
- {
- tmpl = TREE_OPERAND (t, 0);
- args = TREE_OPERAND (t, 1);
- return;
- }
-
- if (TREE_CODE (t) == TYPE_DECL)
- {
- /* A constrained parameter. Build a constraint check
- based on the prototype parameter and then extract the
- arguments from that. */
- tree proto = CONSTRAINED_PARM_PROTOTYPE (t);
- tree check = finish_shorthand_constraint (proto, t);
- placeholder_extract_concept_and_args (check, tmpl, args);
- return;
- }
-}
-
/* Returns true iff the placeholders C1 and C2 are equivalent. C1
and C2 can be either TEMPLATE_TYPE_PARM or template-ids. */
placeholder constraints. */
return false;
- tree t1, t2, a1, a2;
- placeholder_extract_concept_and_args (c1, t1, a1);
- placeholder_extract_concept_and_args (c2, t2, a2);
+ gcc_assert (concept_check_p (c1) && concept_check_p (c2));
+ tree t1 = TREE_OPERAND (c1, 0);
+ tree a1 = TREE_OPERAND (c1, 1);
+ tree t2 = TREE_OPERAND (c2, 0);
+ tree a2 = TREE_OPERAND (c2, 1);
if (t1 != t2)
return false;
/* Skip the first argument so we don't infinitely recurse.
Also, they may differ in template parameter index. */
for (int i = 1; i < len1; ++i)
- {
- tree t1 = TREE_VEC_ELT (a1, i);
- tree t2 = TREE_VEC_ELT (a2, i);
- if (!template_args_equal (t1, t2))
+ if (!template_args_equal (TREE_VEC_ELT (a1, i),
+ TREE_VEC_ELT (a2, i)))
return false;
- }
return true;
}
hashval_t
iterative_hash_placeholder_constraint (tree c, hashval_t val)
{
- tree t, a;
- placeholder_extract_concept_and_args (c, t, a);
+ gcc_assert (concept_check_p (c));
+ tree t = TREE_OPERAND (c, 0);
+ tree a = TREE_OPERAND (c, 1);
/* Like hash_tmpl_and_args, but skip the first argument. */
val = iterative_hash_object (DECL_UID (t), val);
/* New decls. */
MARK_TS_DECL_COMMON (TEMPLATE_DECL);
- MARK_TS_DECL_COMMON (WILDCARD_DECL);
MARK_TS_DECL_NON_COMMON (USING_DECL);
/* Used to represent information associated with constrained declarations. */
DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
-/* A wildcard declaration is a placeholder for a template parameter
- used to resolve constrained-type-names in concepts. During
- resolution, the matching argument is saved as the TREE_TYPE
- of the wildcard. */
-DEFTREECODE (WILDCARD_DECL, "wildcard_decl", tcc_declaration, 0)
-
/* A requires-expr has three operands. The first operand is
its parameter list (possibly NULL). The second is a list of
requirements, which are denoted by the _REQ* tree codes
TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO)
SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
COMPOUND_REQ_NOEXCEPT_P (in COMPOUND_REQ)
- WILDCARD_PACK_P (in WILDCARD_DECL)
BLOCK_OUTER_CURLY_BRACE_P (in BLOCK)
FOLD_EXPR_MODIFY_P (*_FOLD_EXPR)
IF_STMT_CONSTEXPR_P (IF_STMT)
#define PACK_INDEX_PARENTHESIZED_P(NODE) \
TREE_LANG_FLAG_1 (TREE_CHECK (NODE, PACK_INDEX_EXPR))
-/* True iff the wildcard can match a template parameter pack. */
-#define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE)
-
/* Determine if this is an argument pack. */
#define ARGUMENT_PACK_P(NODE) \
(TREE_CODE (NODE) == TYPE_ARGUMENT_PACK \
int = LOOKUP_NORMAL,
tree = NULL_TREE);
extern tree type_uses_auto (tree);
-extern tree type_uses_auto_or_concept (tree);
-extern void append_type_to_template_for_access_check (tree, tree, tree,
- location_t);
extern tree convert_generic_types_to_packs (tree, int, int);
extern tree splice_late_return_type (tree, tree);
extern bool is_auto (const_tree);
extern tree build_concept_check (tree, tree, tsubst_flags_t);
extern tree build_concept_check (tree, tree, tree, tsubst_flags_t);
-extern tree_pair finish_type_constraints (tree, tree, tsubst_flags_t);
extern tree build_constrained_parameter (tree, tree, tree = NULL_TREE);
-extern void placeholder_extract_concept_and_args (tree, tree&, tree&);
extern bool equivalent_placeholder_constraints (tree, tree);
extern hashval_t iterative_hash_placeholder_constraint (tree, hashval_t);
-extern bool deduce_constrained_parameter (tree, tree&, tree&);
-extern tree resolve_constraint_check (tree);
-extern bool valid_requirements_p (tree);
-extern tree finish_concept_name (tree);
extern tree finish_shorthand_constraint (tree, tree);
extern tree finish_requires_expr (location_t, tree, tree);
extern tree finish_simple_requirement (location_t, tree);
/* True iff T is a concept. */
-inline bool
-concept_definition_p (tree t)
-{
- return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
-}
-
-/* Same as above, but for const trees. */
-
inline bool
concept_definition_p (const_tree t)
{
- return concept_definition_p (const_cast<tree> (t));
+ return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
}
/* True if t is an expression that checks a concept. */
return false;
}
+/* Return the prototype parameter of the concept T,
+ i.e. its first declared template parameter. */
+
+inline tree
+concept_prototype_parameter (const_tree t)
+{
+ gcc_checking_assert (concept_definition_p (t));
+ if (TREE_CODE (t) == CONCEPT_DECL)
+ t = DECL_TI_TEMPLATE (t);
+ tree parms = DECL_INNERMOST_TEMPLATE_PARMS (t);
+ return TREE_VALUE (TREE_VEC_ELT (parms, 0));
+}
+
/* Helpers for IMPLICIT_RVALUE_P to look through automatic dereference. */
inline bool
pp_cxx_ws_string(pp, "<unsatisfied-type-constraint>");
return;
}
- tree t, a;
- placeholder_extract_concept_and_args (c, t, a);
+ tree t = TREE_OPERAND (c, 0);
+ tree a = TREE_OPERAND (c, 1);
pp->id_expression (t);
pp_cxx_begin_template_argument_list (pp);
pp_cxx_ws_string (pp, "<placeholder>");
dump_simple_decl (pp, t, TREE_TYPE (t), flags);
break;
- case WILDCARD_DECL:
- pp_string (pp, "<wildcard>");
- break;
-
case TEMPLATE_ID_EXPR:
{
tree name = TREE_OPERAND (t, 0);
case TEMPLATE_DECL:
case NAMESPACE_DECL:
case LABEL_DECL:
- case WILDCARD_DECL:
case OVERLOAD:
case TYPE_DECL:
case USING_DECL:
return NULL_TREE;
}
-/* Returns true if TYPE would declare a constrained constrained-parameter. */
-
-static inline bool
-is_constrained_parameter (tree type)
-{
- return (type
- && TREE_CODE (type) == TYPE_DECL
- && CONSTRAINED_PARM_CONCEPT (type)
- && DECL_P (CONSTRAINED_PARM_CONCEPT (type)));
-}
-
-/* Returns true if PARM declares a constrained-parameter. */
-
-static inline bool
-is_constrained_parameter (cp_parameter_declarator *parm)
-{
- return is_constrained_parameter (parm->decl_specifiers.type);
-}
-
/* Check that the type parameter is only a declarator-id, and that its
type is not cv-qualified. */
-bool
+static bool
cp_parser_check_constrained_type_parm (cp_parser *parser,
cp_parameter_declarator *parm)
{
return error_mark_node;
}
-static tree
-finish_constrained_template_template_parm (tree proto, tree id)
-{
- /* FIXME: This should probably be copied, and we may need to adjust
- the template parameter depths. */
- tree saved_parms = current_template_parms;
- begin_template_parm_list ();
- current_template_parms = DECL_TEMPLATE_PARMS (proto);
- end_template_parm_list ();
-
- tree parm = finish_template_template_parm (class_type_node, id);
- current_template_parms = saved_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. */
tree parm;
if (TREE_CODE (proto) == TYPE_DECL)
parm = cp_parser_constrained_type_template_parm (parser, id, parmdecl);
- else if (TREE_CODE (proto) == TEMPLATE_DECL)
- parm = cp_parser_constrained_template_template_parm (parser, proto, id,
- parmdecl);
else
parm = cp_parser_constrained_non_type_template_parm (is_non_type, parmdecl);
if (parm == error_mark_node)
return parm;
}
-/* Returns true if the parsed type actually represents the declaration
- of a type template-parameter. */
+/* Returns true if the TYPE would declare a constrained type
+ template-parameter. */
static bool
declares_constrained_type_template_parameter (tree type)
{
- return (is_constrained_parameter (type)
+ return (type
+ && TREE_CODE (type) == TYPE_DECL
+ && CONSTRAINED_PARM_CONCEPT (type)
+ && DECL_P (CONSTRAINED_PARM_CONCEPT (type))
&& TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TYPE_PARM);
}
-/* Returns true if the parsed type actually represents the declaration of
- a template template-parameter. */
+/* Returns true if PARM declares a constrained type template-parameter. */
static bool
-declares_constrained_template_template_parameter (tree type)
+declares_constrained_type_template_parameter (cp_parameter_declarator *parm)
{
- return (is_constrained_parameter (type)
- && TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TEMPLATE_PARM);
+ tree type = parm->decl_specifiers.type;
+ return declares_constrained_type_template_parameter (type);
}
/* Parse a default argument for a type template-parameter.
}
/* The parameter may have been constrained type parameter. */
- if (is_constrained_parameter (parameter_declarator))
+ if (declares_constrained_type_template_parameter (parameter_declarator))
return finish_constrained_parameter (parser,
parameter_declarator,
is_non_type);
/* A concept-name with no arguments can't be an expression. */
tentative = false;
+ tree con = DECL_TEMPLATE_RESULT (tmpl);
+ tree proto = concept_prototype_parameter (con);
tsubst_flags_t complain = tentative ? tf_none : tf_warning_or_error;
+ /* A type constraint constrains a contextually determined type or type
+ parameter pack. */
+ if (TREE_CODE (proto) != TYPE_DECL)
+ {
+ if (!tentative)
+ {
+ auto_diagnostic_group d;
+ error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
+ inform (DECL_SOURCE_LOCATION (con), "concept defined here");
+ }
+ return error_mark_node;
+ }
+
/* Get the concept and prototype parameter for the constraint. */
- tree_pair info = finish_type_constraints (tmpl, args, complain);
- tree con = info.first;
- tree proto = info.second;
- if (con == error_mark_node)
+ tree check = build_type_constraint (tmpl, args, complain);
+ if (check == error_mark_node)
return error_mark_node;
/* As per the standard, require auto or decltype(auto). */
close_paren = parens.require_close (parser);
}
- /* A type constraint constrains a contextually determined type or type
- parameter pack. */
- if (TREE_CODE (proto) != TYPE_DECL)
- {
- if (!tentative)
- {
- auto_diagnostic_group d;
- error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
- inform (DECL_SOURCE_LOCATION (con), "concept defined here");
- }
- return error_mark_node;
- }
-
/* In a template parameter list, a type-parameter can be introduced
by type-constraints alone. */
if (processing_template_parmlist && !placeholder)
default_argument
= cp_parser_default_type_template_argument (parser);
- /* A constrained-type-specifier may declare a
- template-template-parameter. */
- else if (declares_constrained_template_template_parameter (type))
- default_argument
- = cp_parser_default_template_template_argument (parser);
-
/* Outside of a class definition, we can just parse the
assignment-expression. */
else
return ttp_subsumes (parm_cons, arg);
}
-// Convert a placeholder argument into a binding to the original
-// parameter. The original parameter is saved as the TREE_TYPE of
-// ARG.
-static inline tree
-convert_wildcard_argument (tree parm, tree arg)
-{
- TREE_TYPE (arg) = parm;
- return arg;
-}
-
/* We can't fully resolve ARG given as a non-type template argument to TYPE,
because one of them is dependent. But we need to represent the
conversion for the benefit of cp_tree_equal. */
if (parm == error_mark_node || error_operand_p (arg))
return error_mark_node;
- /* Trivially convert placeholders. */
- if (TREE_CODE (arg) == WILDCARD_DECL)
- return convert_wildcard_argument (parm, arg);
-
if (arg == any_targ_node)
return arg;
packed_args = make_tree_vec (TREE_VEC_LENGTH (packed_parms));
}
- /* Check if we have a placeholder pack, which indicates we're
- in the context of a introduction list. In that case we want
- to match this pack to the single placeholder. */
- else if (arg_idx < nargs
- && TREE_CODE (TREE_VEC_ELT (inner_args, arg_idx)) == WILDCARD_DECL
- && WILDCARD_PACK_P (TREE_VEC_ELT (inner_args, arg_idx)))
- {
- nargs = arg_idx + 1;
- packed_args = make_tree_vec (1);
- }
else
packed_args = make_tree_vec (nargs - arg_idx);
{
int quals;
- /* When building concept checks for the purpose of
- deducing placeholders, we can end up with wildcards
- where types are expected. Adjust this to the deduced
- value. */
- if (TREE_CODE (arg) == WILDCARD_DECL)
- arg = TREE_TYPE (TREE_TYPE (arg));
-
gcc_assert (TYPE_P (arg));
quals = cp_type_quals (arg) | cp_type_quals (t);
/* An unresolved name is always dependent. */
if (identifier_p (expression)
- || TREE_CODE (expression) == USING_DECL
- || TREE_CODE (expression) == WILDCARD_DECL)
+ || TREE_CODE (expression) == USING_DECL)
return true;
/* A lambda-expression in template context is dependent. dependent_type_p is
{
/* Build the constraint. */
tree tmpl = DECL_TI_TEMPLATE (con);
- tree expr = tmpl;
- if (TREE_CODE (con) == FUNCTION_DECL)
- expr = ovl_make (tmpl);
++processing_template_decl;
- expr = build_concept_check (expr, type, args, tf_warning_or_error);
+ tree expr = build_concept_check (tmpl, type, args, tf_warning_or_error);
--processing_template_decl;
PLACEHOLDER_TYPE_CONSTRAINTS_INFO (type)
args = expand_template_argument_pack (args);
first = TREE_VEC_ELT (args, 0);
}
- gcc_checking_assert (TREE_CODE (first) == WILDCARD_DECL
- || is_auto (first));
+ gcc_checking_assert (is_auto (first));
for (int i = 1; i < TREE_VEC_LENGTH (args); ++i)
if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
return true;