aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c1240
1 files changed, 1141 insertions, 99 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bfad608..a0b249b 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1343,7 +1343,7 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
static cp_declarator *make_call_declarator
- (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier, tree, tree);
+ (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier, tree, tree, tree);
static cp_declarator *make_array_declarator
(cp_declarator *, tree);
static cp_declarator *make_pointer_declarator
@@ -1522,7 +1522,8 @@ make_call_declarator (cp_declarator *target,
cp_virt_specifiers virt_specifiers,
cp_ref_qualifier ref_qualifier,
tree exception_specification,
- tree late_return_type)
+ tree late_return_type,
+ tree requires_clause)
{
cp_declarator *declarator;
@@ -1534,6 +1535,7 @@ make_call_declarator (cp_declarator *target,
declarator->u.function.ref_qualifier = ref_qualifier;
declarator->u.function.exception_specification = exception_specification;
declarator->u.function.late_return_type = late_return_type;
+ declarator->u.function.requires_clause = requires_clause;
if (target)
{
declarator->id_loc = target->id_loc;
@@ -2082,6 +2084,8 @@ static tree cp_parser_type_specifier
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
static tree cp_parser_type_name
+ (cp_parser *, bool);
+static tree cp_parser_type_name
(cp_parser *);
static tree cp_parser_nonclass_name
(cp_parser* parser);
@@ -2136,7 +2140,7 @@ static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
static cp_ref_qualifier cp_parser_ref_qualifier_opt
(cp_parser *);
static tree cp_parser_late_return_type_opt
- (cp_parser *, cp_declarator *, cp_cv_quals);
+ (cp_parser *, cp_declarator *, tree &, cp_cv_quals);
static tree cp_parser_declarator_id
(cp_parser *, bool);
static tree cp_parser_type_id
@@ -2177,7 +2181,7 @@ static tree cp_parser_late_parsing_cilk_simd_fn_info
(cp_parser *, tree);
static tree synthesize_implicit_template_parm
- (cp_parser *);
+ (cp_parser *, tree);
static tree finish_fully_implicit_template
(cp_parser *, tree);
@@ -2314,6 +2318,31 @@ static bool cp_parser_extension_opt
static void cp_parser_label_declaration
(cp_parser *);
+/* Concept Extensions */
+
+static tree cp_parser_requires_clause
+ (cp_parser *);
+static tree cp_parser_requires_clause_opt
+ (cp_parser *);
+static tree cp_parser_requires_expression
+ (cp_parser *);
+static tree cp_parser_requirement_parameter_list
+ (cp_parser *);
+static tree cp_parser_requirement_body
+ (cp_parser *);
+static tree cp_parser_requirement_list
+ (cp_parser *);
+static tree cp_parser_requirement
+ (cp_parser *);
+static tree cp_parser_simple_requirement
+ (cp_parser *);
+static tree cp_parser_compound_requirement
+ (cp_parser *);
+static tree cp_parser_type_requirement
+ (cp_parser *);
+static tree cp_parser_nested_requirement
+ (cp_parser *);
+
/* Transactional Memory Extensions */
static tree cp_parser_transaction
@@ -2396,7 +2425,7 @@ static tree cp_parser_function_definition_from_specifiers_and_declarator
(cp_parser *, cp_decl_specifier_seq *, tree, const cp_declarator *);
static tree cp_parser_function_definition_after_declarator
(cp_parser *, bool);
-static void cp_parser_template_declaration_after_export
+static bool cp_parser_template_declaration_after_export
(cp_parser *, bool);
static void cp_parser_perform_template_parameter_access_checks
(vec<deferred_access_check, va_gc> *);
@@ -2532,6 +2561,30 @@ static bool cp_parser_array_designator_p
static bool cp_parser_skip_to_closing_square_bracket
(cp_parser *);
+/* Concept-related syntactic transformations */
+
+static tree cp_parser_maybe_concept_name (cp_parser *, tree);
+static tree cp_parser_maybe_partial_concept_id (cp_parser *, tree, tree);
+
+// -------------------------------------------------------------------------- //
+// Unevaluated Operand Guard
+//
+// Implementation of an RAII helper for unevaluated operand parsing.
+cp_unevaluated::cp_unevaluated ()
+{
+ ++cp_unevaluated_operand;
+ ++c_inhibit_evaluation_warnings;
+}
+
+cp_unevaluated::~cp_unevaluated ()
+{
+ --c_inhibit_evaluation_warnings;
+ --cp_unevaluated_operand;
+}
+
+// -------------------------------------------------------------------------- //
+// Tentative Parsing
+
/* Returns nonzero if we are parsing tentatively. */
static inline bool
@@ -3552,6 +3605,9 @@ cp_parser_new (void)
parser->implicit_template_parms = 0;
parser->implicit_template_scope = 0;
+ /* Allow constrained-type-specifiers. */
+ parser->prevent_constrained_type_specifiers = 0;
+
return parser;
}
@@ -4591,6 +4647,7 @@ cp_parser_primary_expression (cp_parser *parser,
case RID_IS_LITERAL_TYPE:
case RID_IS_POD:
case RID_IS_POLYMORPHIC:
+ case RID_IS_SAME_AS:
case RID_IS_STD_LAYOUT:
case RID_IS_TRIVIAL:
case RID_IS_TRIVIALLY_ASSIGNABLE:
@@ -4599,6 +4656,10 @@ cp_parser_primary_expression (cp_parser *parser,
case RID_IS_UNION:
return cp_parser_trait_expr (parser, token->keyword);
+ // C++ concepts
+ case RID_REQUIRES:
+ return cp_parser_requires_expression (parser);
+
/* Objective-C++ expressions. */
case RID_AT_ENCODE:
case RID_AT_PROTOCOL:
@@ -5956,9 +6017,11 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
tree type;
/* The syntax permitted here is the same permitted for an
elaborated-type-specifier. */
+ ++parser->prevent_constrained_type_specifiers;
type = cp_parser_elaborated_type_specifier (parser,
/*is_friend=*/false,
/*is_declaration=*/false);
+ --parser->prevent_constrained_type_specifiers;
postfix_expression = cp_parser_functional_cast (parser, type);
}
break;
@@ -6056,9 +6119,11 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
that doesn't work we fall back to the primary-expression. */
cp_parser_parse_tentatively (parser);
/* Look for the simple-type-specifier. */
+ ++parser->prevent_constrained_type_specifiers;
type = cp_parser_simple_type_specifier (parser,
/*decl_specs=*/NULL,
CP_PARSER_FLAGS_NONE);
+ --parser->prevent_constrained_type_specifiers;
/* Parse the cast itself. */
if (!cp_parser_error_occurred (parser))
postfix_expression
@@ -8843,6 +8908,10 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
case RID_IS_POLYMORPHIC:
kind = CPTK_IS_POLYMORPHIC;
break;
+ case RID_IS_SAME_AS:
+ kind = CPTK_IS_SAME_AS;
+ binary = true;
+ break;
case RID_IS_STD_LAYOUT:
kind = CPTK_IS_STD_LAYOUT;
break;
@@ -9440,7 +9509,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
VIRT_SPEC_UNSPECIFIED,
REF_QUAL_NONE,
exception_spec,
- /*late_return_type=*/NULL_TREE);
+ /*late_return_type=*/NULL_TREE,
+ /*requires_clause*/NULL_TREE);
declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr);
fco = grokmethod (&return_type_specs,
@@ -11371,8 +11441,12 @@ cp_parser_declaration (cp_parser* parser)
&& token1.keyword == RID_ATTRIBUTE
&& cp_parser_objc_valid_prefix_attributes (parser, &attributes))
cp_parser_objc_declaration (parser, attributes);
- /* We must have either a block declaration or a function
- definition. */
+ /* At this point we may have a template declared by a concept
+ introduction. */
+ else if (flag_concepts
+ && cp_parser_template_declaration_after_export (parser,
+ /*member_p=*/false))
+ /* We did. */;
else
/* Try to parse a block-declaration, or a function-definition. */
cp_parser_block_declaration (parser, /*statement_p=*/false);
@@ -11723,6 +11797,11 @@ cp_parser_simple_declaration (cp_parser* parser,
decl-specifier:
attributes
+ Concepts Extension:
+
+ decl-specifier:
+ concept
+
Set *DECL_SPECS to a representation of the decl-specifier-seq.
The parser flags FLAGS is used to control type-specifier parsing.
@@ -11850,6 +11929,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
cp_lexer_consume_token (parser->lexer);
break;
+ case RID_CONCEPT:
+ ds = ds_concept;
+ cp_lexer_consume_token (parser->lexer);
+ break;
+
/* function-specifier:
inline
virtual
@@ -13256,7 +13340,15 @@ cp_parser_operator (cp_parser* parser)
template-parameter-list-seq:
template-parameter-list-seq [opt]
- template < template-parameter-list > */
+ template < template-parameter-list >
+
+ Concept Extensions:
+
+ template-parameter-list-seq:
+ template < template-parameter-list > requires-clause [opt]
+
+ requires-clause:
+ requires logical-or-expression */
static void
cp_parser_template_declaration (cp_parser* parser, bool member_p)
@@ -13330,6 +13422,244 @@ cp_parser_template_parameter_list (cp_parser* parser)
return end_template_parm_list (parameter_list);
}
+/* Parse a introduction-list.
+
+ introduction-list:
+ introduced-parameter
+ introduction-list , introduced-parameter
+
+ introduced-parameter:
+ ...[opt] identifier
+
+ Returns a TREE_VEC of WILDCARD_DECLs. If the parameter is a pack
+ then the introduced parm will have WILDCARD_PACK_P set. In addition, the
+ WILDCARD_DECL will also have DECL_NAME set and token location in
+ DECL_SOURCE_LOCATION. */
+
+static tree
+cp_parser_introduction_list (cp_parser *parser)
+{
+ vec<tree, va_gc> *introduction_vec = make_tree_vector ();
+
+ while (true)
+ {
+ bool is_pack = cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS);
+ if (is_pack)
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Build placeholder. */
+ tree parm = build_nt (WILDCARD_DECL);
+ DECL_SOURCE_LOCATION (parm)
+ = cp_lexer_peek_token (parser->lexer)->location;
+ DECL_NAME (parm) = cp_parser_identifier (parser);
+ WILDCARD_PACK_P (parm) = is_pack;
+ vec_safe_push (introduction_vec, parm);
+
+ /* If the next token is not a `,', we're done. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+ break;
+ /* Otherwise, consume the `,' token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
+
+ /* Convert the vec into a TREE_VEC. */
+ tree introduction_list = make_tree_vec (introduction_vec->length ());
+ unsigned int n;
+ tree parm;
+ FOR_EACH_VEC_ELT (*introduction_vec, n, parm)
+ TREE_VEC_ELT (introduction_list, n) = parm;
+
+ release_tree_vector (introduction_vec);
+ return introduction_list;
+}
+
+/* Given a declarator, get the declarator-id part, or NULL_TREE if this
+ is an abstract declarator. */
+
+static inline cp_declarator*
+get_id_declarator (cp_declarator *declarator)
+{
+ cp_declarator *d = declarator;
+ while (d && d->kind != cdk_id)
+ d = d->declarator;
+ return d;
+}
+
+/* Get the unqualified-id from the DECLARATOR or NULL_TREE if this
+ is an abstract declarator. */
+
+static inline tree
+get_unqualified_id (cp_declarator *declarator)
+{
+ declarator = get_id_declarator (declarator);
+ if (declarator)
+ return declarator->u.id.unqualified_name;
+ else
+ return NULL_TREE;
+}
+
+/* Returns true if DECL represents a constrained-parameter. */
+
+static inline bool
+is_constrained_parameter (tree decl)
+{
+ return (decl
+ && TREE_CODE (decl) == TYPE_DECL
+ && CONSTRAINED_PARM_CONCEPT (decl)
+ && DECL_P (CONSTRAINED_PARM_CONCEPT (decl)));
+}
+
+/* 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
+cp_parser_check_constrained_type_parm (cp_parser *parser,
+ cp_parameter_declarator *parm)
+{
+ if (!parm->declarator)
+ return true;
+
+ if (parm->declarator->kind != cdk_id)
+ {
+ cp_parser_error (parser, "invalid constrained type parameter");
+ return false;
+ }
+
+ /* Don't allow cv-qualified type parameters. */
+ if (decl_spec_seq_has_spec_p (&parm->decl_specifiers, ds_const)
+ || decl_spec_seq_has_spec_p (&parm->decl_specifiers, ds_volatile))
+ {
+ cp_parser_error (parser, "cv-qualified type parameter");
+ return false;
+ }
+
+ 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;
+}
+
+/* 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;
+
+ /* 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;
+}
+
+/* Create a new non-type template parameter from the given PARM
+ declarator. */
+
+static tree
+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
+ specifies the type of the declared parameter. */
+
+static tree
+finish_constrained_parameter (cp_parser *parser,
+ cp_parameter_declarator *parmdecl,
+ bool *is_non_type,
+ bool *is_parameter_pack)
+{
+ tree decl = parmdecl->decl_specifiers.type;
+ tree id = get_unqualified_id (parmdecl->declarator);
+ tree def = parmdecl->default_argument;
+ tree proto = DECL_INITIAL (decl);
+
+ /* A template parameter constrained by a variadic concept shall also
+ be declared as a template parameter pack. */
+ bool is_variadic = template_parameter_pack_p (proto);
+ if (is_variadic && !*is_parameter_pack)
+ cp_parser_error (parser, "variadic constraint introduced without %<...%>");
+
+ /* Build the parameter. Return an error if the declarator was invalid. */
+ 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 = constrained_non_type_template_parm (is_non_type, parmdecl);
+ 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;
+
+ return parm;
+}
+
+/* Returns true if the parsed type actually represents the declaration
+ of a type template-parameter. */
+
+static inline bool
+declares_constrained_type_template_parameter (tree type)
+{
+ return (is_constrained_parameter (type)
+ && TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TYPE_PARM);
+}
+
+
+/* Returns true if the parsed type actually represents the declaration of
+ a template template-parameter. */
+
+static bool
+declares_constrained_template_template_parameter (tree type)
+{
+ return (is_constrained_parameter (type)
+ && TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TEMPLATE_PARM);
+}
+
/* Parse a default argument for a type template-parameter.
Note that diagnostics are handled in cp_parser_template_parameter. */
@@ -13454,7 +13784,7 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
return cp_parser_type_parameter (parser, is_parameter_pack);
}
- /* Otherwise, it is a non-type parameter.
+ /* Otherwise, it is a non-type parameter or a constrained parameter.
[temp.param]
@@ -13462,7 +13792,6 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
template-parameter, the first non-nested `>' is taken as the end
of the template parameter-list rather than a greater-than
operator. */
- *is_non_type = true;
parameter_declarator
= cp_parser_parameter_declaration (parser, /*template_parm_p=*/true,
/*parenthesized_p=*/NULL);
@@ -13483,6 +13812,16 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
cp_lexer_consume_token (parser->lexer);
}
+ // The parameter may have been constrained.
+ if (is_constrained_parameter (parameter_declarator))
+ return finish_constrained_parameter (parser,
+ parameter_declarator,
+ is_non_type,
+ is_parameter_pack);
+
+ // Now we're sure that the parameter is a non-type parameter.
+ *is_non_type = true;
+
parm = grokdeclarator (parameter_declarator->declarator,
&parameter_declarator->decl_specifiers,
TPARM, /*initialized=*/0,
@@ -13599,6 +13938,16 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
cp_parser_template_parameter_list (parser);
/* Look for the `>'. */
cp_parser_require (parser, CPP_GREATER, RT_GREATER);
+
+ // If template requirements are present, parse them.
+ if (flag_concepts)
+ {
+ tree reqs = get_shorthand_constraints (current_template_parms);
+ if (tree r = cp_parser_requires_clause_opt (parser))
+ reqs = conjoin_constraints (reqs, make_predicate_constraint (r));
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
+ }
+
/* Look for the `class' or 'typename' keywords. */
cp_parser_type_parameter_key (parser);
/* If the next token is an ellipsis, we have a template
@@ -13833,6 +14182,11 @@ cp_parser_template_id (cp_parser *parser,
template_id
= finish_template_type (templ, arguments, entering_scope);
}
+ /* A template-like identifier may be a partial concept id. */
+ else if (flag_concepts
+ && (template_id = (cp_parser_maybe_partial_concept_id
+ (parser, templ, arguments))))
+ return template_id;
else if (variable_template_p (templ))
{
template_id = lookup_template_variable (templ, arguments);
@@ -14844,6 +15198,11 @@ cp_parser_type_specifier (cp_parser* parser,
__typeof__ ( type-id )
__typeof__ ( type-id ) { initializer-list , [opt] }
+ Concepts Extension:
+
+ simple-type-specifier:
+ constrained-type-specifier
+
Returns the indicated TYPE_DECL. If DECL_SPECS is not NULL, it is
appropriately updated. */
@@ -14954,7 +15313,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
}
if (cxx_dialect >= cxx14)
- type = synthesize_implicit_template_parm (parser);
+ type = synthesize_implicit_template_parm (parser, NULL_TREE);
else
type = error_mark_node;
@@ -15195,18 +15554,34 @@ cp_parser_simple_type_specifier (cp_parser* parser,
typedef-name:
identifier
+ Concepts:
+
+ type-name:
+ concept-name
+ partial-concept-id
+
+ concept-name:
+ identifier
+
Returns a TYPE_DECL for the type. */
static tree
cp_parser_type_name (cp_parser* parser)
{
+ return cp_parser_type_name (parser, /*typename_keyword_p=*/false);
+}
+
+/* See above. */
+static tree
+cp_parser_type_name (cp_parser* parser, bool typename_keyword_p)
+{
tree type_decl;
/* We can't know yet whether it is a class-name or not. */
cp_parser_parse_tentatively (parser);
/* Try a class-name. */
type_decl = cp_parser_class_name (parser,
- /*typename_keyword_p=*/false,
+ typename_keyword_p,
/*template_keyword_p=*/false,
none_type,
/*check_dependency_p=*/true,
@@ -15236,11 +15611,16 @@ cp_parser_type_name (cp_parser* parser)
Whereas [temp.names]/7 says:
A simple-template-id that names a class template
- specialization is a class-name. */
+ specialization is a class-name.
+
+ With concepts, this could also be a partial-concept-id that
+ declares a non-type template parameter. */
if (type_decl != NULL_TREE
&& TREE_CODE (type_decl) == TYPE_DECL
&& TYPE_DECL_ALIAS_P (type_decl))
gcc_assert (DECL_TEMPLATE_INSTANTIATION (type_decl));
+ else if (is_constrained_parameter (type_decl))
+ /* Don't do anything. */ ;
else
cp_parser_simulate_error (parser);
@@ -15252,7 +15632,121 @@ cp_parser_type_name (cp_parser* parser)
return type_decl;
}
-/* Parse a non-class type-name, that is, either an enum-name or a typedef-name.
+/* 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
+ kind of template argument. If ARGS is NULL, then we try to
+ form a concept check of the form DECL<?>. */
+
+static tree
+cp_parser_maybe_constrained_type_specifier (cp_parser *parser,
+ tree decl, tree args)
+{
+ gcc_assert (args ? TREE_CODE (args) == TREE_VEC : true);
+
+ /* If we a constrained-type-specifier cannot be deduced. */
+ if (parser->prevent_constrained_type_specifiers)
+ return NULL_TREE;
+
+ /* A constrained type specifier can only be found in an
+ overload set or as a reference to a template declaration.
+
+ FIXME: This might be masking a bug. It's possible that
+ that the deduction below is causing template specializations
+ to be formed with the wildcard as an argument. */
+ if (TREE_CODE (decl) != OVERLOAD && TREE_CODE (decl) != TEMPLATE_DECL)
+ return NULL_TREE;
+
+ /* Try to build a call expression that evaluates the
+ concept. This can fail if the overload set refers
+ only to non-templates. */
+ tree placeholder = build_nt (WILDCARD_DECL);
+ tree check = build_concept_check (decl, placeholder, args);
+ if (check == error_mark_node)
+ return NULL_TREE;
+
+ /* Deduce the checked constraint and the prototype parameter.
+
+ FIXME: In certain cases, failure to deduce should be a
+ diagnosable error. */
+ tree conc;
+ tree proto;
+ if (!deduce_constrained_parameter (check, conc, proto))
+ return NULL_TREE;
+
+ /* In template parameter scope, this results in a constrained
+ parameter. Return a descriptor of that parm. */
+ 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)
+ {
+ tree x = build_constrained_parameter (conc, proto, args);
+ return synthesize_implicit_template_parm (parser, x);
+ }
+ else
+ {
+ /* Otherwise, we're in a context where the constrained
+ type name is deduced and the constraint applies
+ after deduction. */
+ return make_constrained_auto (conc, args);
+ }
+
+ return NULL_TREE;
+}
+
+/* If DECL refers to a concept, return a TYPE_DECL representing
+ the result of using the constrained type specifier in the
+ current context. DECL refers to a concept if
+
+ - it is an overload set containing a function concept taking a single
+ type argument, or
+
+ - it is a variable concept taking a single type argument. */
+
+static tree
+cp_parser_maybe_concept_name (cp_parser* parser, tree decl)
+{
+ return cp_parser_maybe_constrained_type_specifier (parser, decl, NULL_TREE);
+}
+
+/* Check if DECL and ARGS form a partial-concept-id. If so,
+ assign ID to the resulting constrained placeholder.
+
+ Returns true if the partial-concept-id designates a placeholder
+ and false otherwise. Note that *id is set to NULL_TREE in
+ this case. */
+
+static tree
+cp_parser_maybe_partial_concept_id (cp_parser *parser, tree decl, tree args)
+{
+ return cp_parser_maybe_constrained_type_specifier (parser, decl, args);
+}
+
+/* Parse a non-class type-name, that is, either an enum-name, a typedef-name,
+ or a concept-name.
enum-name:
identifier
@@ -15260,6 +15754,9 @@ cp_parser_type_name (cp_parser* parser)
typedef-name:
identifier
+ concept-name:
+ identifier
+
Returns a TYPE_DECL for the type. */
static tree
@@ -15278,6 +15775,17 @@ cp_parser_nonclass_name (cp_parser* parser)
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_CODE (type_decl) != TYPE_DECL
&& (objc_is_id (identifier) || objc_is_class_name (identifier)))
{
@@ -16637,6 +17145,14 @@ cp_parser_alias_declaration (cp_parser* parser)
if (decl == error_mark_node)
return decl;
+ // Attach constraints to the alias declaration.
+ if (flag_concepts && current_template_parms)
+ {
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ tree constr = build_constraints (reqs, NULL_TREE);
+ set_constraints (decl, constr);
+ }
+
cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0);
if (pushed_scope)
@@ -17632,11 +18148,11 @@ cp_parser_direct_declarator (cp_parser* parser,
else
attrs = chainon (attr, attrs);
}
+ tree requires_clause = NULL_TREE;
late_return = (cp_parser_late_return_type_opt
- (parser, declarator,
+ (parser, declarator, requires_clause,
memfn ? cv_quals : -1));
-
/* Parse the virt-specifier-seq. */
virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
@@ -17647,7 +18163,8 @@ cp_parser_direct_declarator (cp_parser* parser,
virt_specifiers,
ref_qual,
exception_specification,
- late_return);
+ late_return,
+ requires_clause);
declarator->std_attributes = attrs;
/* Any subsequent parameter lists are to do with
return type, so are not those of the declared
@@ -18369,7 +18886,7 @@ parsing_nsdmi (void)
static tree
cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator,
- cp_cv_quals quals)
+ tree& requires_clause, cp_cv_quals quals)
{
cp_token *token;
tree type = NULL_TREE;
@@ -18383,7 +18900,9 @@ cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator,
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* A late-specified return type is indicated by an initial '->'. */
- if (token->type != CPP_DEREF && !(declare_simd_p || cilk_simd_fn_vector_p))
+ if (token->type != CPP_DEREF
+ && token->keyword != RID_REQUIRES
+ && !(declare_simd_p || cilk_simd_fn_vector_p))
return NULL_TREE;
tree save_ccp = current_class_ptr;
@@ -18402,6 +18921,10 @@ cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator,
type = cp_parser_trailing_type_id (parser);
}
+ /* Function declarations may be followed by a trailing
+ requires-clause. */
+ requires_clause = cp_parser_requires_clause_opt (parser);
+
if (cilk_simd_fn_vector_p)
declarator->std_attributes
= cp_parser_late_parsing_cilk_simd_fn_info (parser,
@@ -18502,11 +19025,16 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg,
&& type_uses_auto (type_specifier_seq.type))
{
/* A type-id with type 'auto' is only ok if the abstract declarator
- is a function declarator with a late-specified return type. */
+ is a function declarator with a late-specified return type.
+
+ A type-id with 'auto' is also valid in a trailing-return-type
+ in a compound-requirement. */
if (abstract_declarator
&& abstract_declarator->kind == cdk_function
&& abstract_declarator->u.function.late_return_type)
/* OK */;
+ else if (parser->in_result_type_constraint_p)
+ /* OK */;
else
{
error ("invalid use of %<auto%>");
@@ -18539,7 +19067,8 @@ static tree cp_parser_template_type_arg (cp_parser *parser)
return r;
}
-static tree cp_parser_trailing_type_id (cp_parser *parser)
+static tree
+cp_parser_trailing_type_id (cp_parser *parser)
{
return cp_parser_type_id_1 (parser, false, true);
}
@@ -19123,6 +19652,7 @@ cp_parser_parameter_declaration (cp_parser *parser,
/* If the next token is `=', then process a default argument. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
+ tree type = decl_specifiers.type;
token = cp_lexer_peek_token (parser->lexer);
/* If we are defining a class, then the tokens that make up the
default argument must be saved and processed later. */
@@ -19130,6 +19660,17 @@ cp_parser_parameter_declaration (cp_parser *parser,
&& TYPE_BEING_DEFINED (current_class_type)
&& !LAMBDA_TYPE_P (current_class_type))
default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
+
+ // A constrained-type-specifier may declare a type template-parameter.
+ else if (declares_constrained_type_template_parameter (type))
+ 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
@@ -19872,6 +20413,10 @@ cp_parser_class_specifier_1 (cp_parser* parser)
= parser->in_unbraced_linkage_specification_p;
parser->in_unbraced_linkage_specification_p = false;
+ // Associate constraints with the type.
+ if (flag_concepts)
+ type = associate_classtype_constraints (type);
+
/* Start the class. */
if (nested_name_specifier_p)
{
@@ -20770,6 +21315,9 @@ cp_parser_member_declaration (cp_parser* parser)
return;
}
+ /* Check for a template introduction. */
+ else if (cp_parser_template_declaration_after_export (parser, true))
+ return;
/* Check for a using-declaration. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
@@ -22764,6 +23312,324 @@ cp_parser_label_declaration (cp_parser* parser)
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
}
+// -------------------------------------------------------------------------- //
+// Requires Clause
+
+// Parse a requires clause.
+//
+// requires-clause:
+// 'requires' logical-or-expression
+//
+// The required logical-or-expression must be a constant expression. Note
+// that we don't check that the expression is constepxr here. We defer until
+// we analyze constraints and then, we only check atomic constraints.
+static tree
+cp_parser_requires_clause (cp_parser *parser)
+{
+ // Parse the requires clause so that it is not automatically folded.
+ ++processing_template_decl;
+ tree expr = cp_parser_binary_expression (parser, false, false,
+ PREC_NOT_OPERATOR, NULL);
+ --processing_template_decl;
+ return expr;
+}
+
+// Optionally parse a requires clause:
+static tree
+cp_parser_requires_clause_opt (cp_parser *parser)
+{
+ if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+ return NULL_TREE;
+ cp_lexer_consume_token (parser->lexer);
+ return cp_parser_requires_clause (parser);
+}
+
+
+/*---------------------------------------------------------------------------
+ Requires expressions
+---------------------------------------------------------------------------*/
+
+/* Parse a requires expression
+
+ requirement-expression:
+ 'requires' requirement-parameter-list [opt] requirement-body */
+static tree
+cp_parser_requires_expression (cp_parser *parser)
+{
+ gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES));
+ location_t loc = cp_lexer_consume_token (parser->lexer)->location;
+
+ /* A requires-expression shall appear only within a concept
+ definition or a requires-clause.
+
+ TODO: Implement this diagnostic correctly. */
+ if (!processing_template_decl)
+ {
+ error_at (loc, "a requires expression cannot appear outside a template");
+ cp_parser_skip_to_end_of_statement (parser);
+ return error_mark_node;
+ }
+
+ tree parms, reqs;
+ {
+ /* Local parameters are delared as variables within the scope
+ of the expression. They are not visible past the end of
+ the expression. Expressions within the requires-expression
+ are unevaluated. */
+ struct scope_sentinel
+ {
+ scope_sentinel ()
+ {
+ ++cp_unevaluated_operand;
+ begin_scope (sk_block, NULL_TREE);
+ }
+
+ ~scope_sentinel ()
+ {
+ pop_bindings_and_leave_scope ();
+ --cp_unevaluated_operand;
+ }
+ } s;
+
+ /* Parse the optional parameter list. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ parms = cp_parser_requirement_parameter_list (parser);
+ if (parms == error_mark_node)
+ return error_mark_node;
+ }
+ else
+ parms = NULL_TREE;
+
+ /* Parse the requirement body. */
+ reqs = cp_parser_requirement_body (parser);
+ if (reqs == error_mark_node)
+ return error_mark_node;
+ }
+
+ /* This needs to happen after pop_bindings_and_leave_scope, as it reverses
+ the parm chain. */
+ grokparms (parms, &parms);
+ return finish_requires_expr (parms, reqs);
+}
+
+/* Parse a parameterized requirement.
+
+ requirement-parameter-list:
+ '(' parameter-declaration-clause ')' */
+static tree
+cp_parser_requirement_parameter_list (cp_parser *parser)
+{
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return error_mark_node;
+
+ tree parms = cp_parser_parameter_declaration_clause (parser);
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ return error_mark_node;
+
+ return parms;
+}
+
+/* Parse the body of a requirement.
+
+ requirement-body:
+ '{' requirement-list '}' */
+static tree
+cp_parser_requirement_body (cp_parser *parser)
+{
+ if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
+ return error_mark_node;
+
+ tree reqs = cp_parser_requirement_list (parser);
+
+ if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE))
+ return error_mark_node;
+
+ return reqs;
+}
+
+/* Parse a list of requirements.
+
+ requirement-list:
+ requirement
+ requirement-list ';' requirement[opt] */
+static tree
+cp_parser_requirement_list (cp_parser *parser)
+{
+ tree result = NULL_TREE;
+ while (true)
+ {
+ tree req = cp_parser_requirement (parser);
+ if (req == error_mark_node)
+ return error_mark_node;
+
+ result = tree_cons (NULL_TREE, req, result);
+
+ /* If we see a semi-colon, consume it. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Stop processing at the end of the list. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ break;
+ }
+
+ /* Reverse the order of requirements so they are analyzed in
+ declaration order. */
+ return nreverse (result);
+}
+
+/* Parse a syntactic requirement or type requirement.
+
+ requirement:
+ simple-requirement
+ compound-requirement
+ type-requirement
+ nested-requirement */
+static tree
+cp_parser_requirement (cp_parser *parser)
+{
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ return cp_parser_compound_requirement (parser);
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
+ return cp_parser_type_requirement (parser);
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+ return cp_parser_nested_requirement (parser);
+ else
+ return cp_parser_simple_requirement (parser);
+}
+
+/* Parse a simple requirement.
+
+ simple-requirement:
+ expression ';' */
+static tree
+cp_parser_simple_requirement (cp_parser *parser)
+{
+ tree expr = cp_parser_expression (parser, NULL, false, false);
+ if (!expr || expr == error_mark_node)
+ return error_mark_node;
+
+ if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+ return error_mark_node;
+
+ return finish_simple_requirement (expr);
+}
+
+/* Parse a type requirement
+
+ type-requirement
+ nested-name-specifier [opt] required-type-name ';'
+
+ required-type-name:
+ type-name
+ 'template' [opt] simple-template-id */
+static tree
+cp_parser_type_requirement (cp_parser *parser)
+{
+ cp_lexer_consume_token (parser->lexer);
+
+ // Save the scope before parsing name specifiers.
+ tree saved_scope = parser->scope;
+ tree saved_object_scope = parser->object_scope;
+ tree saved_qualifying_scope = parser->qualifying_scope;
+ cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/true);
+ cp_parser_nested_name_specifier_opt (parser,
+ /*typename_keyword_p=*/true,
+ /*check_dependency_p=*/false,
+ /*type_p=*/true,
+ /*is_declaration=*/false);
+
+ tree type;
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ type = cp_parser_template_id (parser,
+ /*template_keyword_p=*/true,
+ /*check_dependency=*/false,
+ /*tag_type=*/none_type,
+ /*is_declaration=*/false);
+ type = make_typename_type (parser->scope, type, typename_type,
+ /*complain=*/tf_error);
+ }
+ else
+ type = cp_parser_type_name (parser, /*typename_keyword_p=*/true);
+
+ if (TREE_CODE (type) == TYPE_DECL)
+ type = TREE_TYPE (type);
+
+ parser->scope = saved_scope;
+ parser->object_scope = saved_object_scope;
+ parser->qualifying_scope = saved_qualifying_scope;
+
+ if (type == error_mark_node)
+ cp_parser_skip_to_end_of_statement (parser);
+
+ if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+ return error_mark_node;
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ return finish_type_requirement (type);
+}
+
+/* Parse a compound requirement
+
+ compound-requirement:
+ '{' expression '}' 'noexcept' [opt] trailing-return-type [opt] ';' */
+static tree
+cp_parser_compound_requirement (cp_parser *parser)
+{
+ /* Parse an expression enclosed in '{ }'s. */
+ if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
+ return error_mark_node;
+
+ tree expr = cp_parser_expression (parser, NULL, false, false);
+ if (!expr || expr == error_mark_node)
+ return error_mark_node;
+
+ if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE))
+ return error_mark_node;
+
+ /* Parse the optional noexcept. */
+ bool noexcept_p = false;
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_NOEXCEPT))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ noexcept_p = true;
+ }
+
+ /* Parse the optional trailing return type. */
+ tree type = NULL_TREE;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ bool saved_result_type_constraint_p = parser->in_result_type_constraint_p;
+ parser->in_result_type_constraint_p = true;
+ type = cp_parser_trailing_type_id (parser);
+ parser->in_result_type_constraint_p = saved_result_type_constraint_p;
+ if (type == error_mark_node)
+ return error_mark_node;
+ }
+
+ return finish_compound_requirement (expr, type, noexcept_p);
+}
+
+/* Parse a nested requirement. This is the same as a requires clause.
+
+ nested-requirement:
+ requires-clause */
+static tree
+cp_parser_nested_requirement (cp_parser *parser)
+{
+ cp_lexer_consume_token (parser->lexer);
+ tree req = cp_parser_requires_clause (parser);
+ if (req == error_mark_node)
+ return error_mark_node;
+ return finish_nested_requirement (req);
+}
+
/* Support Functions */
/* Looks up NAME in the current scope, as given by PARSER->SCOPE.
@@ -23586,87 +24452,29 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
return fn;
}
-/* Parse a template-declaration, assuming that the `export' (and
- `extern') keywords, if present, has already been scanned. MEMBER_P
- is as for cp_parser_template_declaration. */
+/* Parse a template-declaration body (following argument list). */
static void
-cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
+cp_parser_template_declaration_after_parameters (cp_parser* parser,
+ tree parameter_list,
+ bool member_p)
{
tree decl = NULL_TREE;
- vec<deferred_access_check, va_gc> *checks;
- tree parameter_list;
bool friend_p = false;
- bool need_lang_pop;
- cp_token *token;
-
- /* Look for the `template' keyword. */
- token = cp_lexer_peek_token (parser->lexer);
- if (!cp_parser_require_keyword (parser, RID_TEMPLATE, RT_TEMPLATE))
- return;
- /* And the `<'. */
- if (!cp_parser_require (parser, CPP_LESS, RT_LESS))
- return;
- if (at_class_scope_p () && current_function_decl)
- {
- /* 14.5.2.2 [temp.mem]
-
- A local class shall not have member templates. */
- error_at (token->location,
- "invalid declaration of member template in local class");
- cp_parser_skip_to_end_of_block_or_statement (parser);
- return;
- }
- /* [temp]
-
- A template ... shall not have C linkage. */
- if (current_lang_name == lang_name_c)
- {
- error_at (token->location, "template with C linkage");
- /* Give it C++ linkage to avoid confusing other parts of the
- front end. */
- push_lang_context (lang_name_cplusplus);
- need_lang_pop = true;
- }
- else
- need_lang_pop = false;
-
- /* We cannot perform access checks on the template parameter
- declarations until we know what is being declared, just as we
- cannot check the decl-specifier list. */
- push_deferring_access_checks (dk_deferred);
-
- /* If the next token is `>', then we have an invalid
- specialization. Rather than complain about an invalid template
- parameter, issue an error message here. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
- {
- cp_parser_error (parser, "invalid explicit specialization");
- begin_specialization ();
- parameter_list = NULL_TREE;
- }
- else
- {
- /* Parse the template parameters. */
- parameter_list = cp_parser_template_parameter_list (parser);
- }
+ /* We just processed one more parameter list. */
+ ++parser->num_template_parameter_lists;
/* Get the deferred access checks from the parameter list. These
will be checked once we know what is being declared, as for a
member template the checks must be performed in the scope of the
class containing the member. */
- checks = get_deferred_access_checks ();
+ vec<deferred_access_check, va_gc> *checks = get_deferred_access_checks ();
- /* Look for the `>'. */
- cp_parser_skip_to_end_of_template_parameter_list (parser);
- /* We just processed one more parameter list. */
- ++parser->num_template_parameter_lists;
- /* If the next token is `template', there are more template
- parameters. */
- if (cp_lexer_next_token_is_keyword (parser->lexer,
- RID_TEMPLATE))
- cp_parser_template_declaration_after_export (parser, member_p);
+ /* Tentatively parse for a new template parameter list, which can either be
+ the template keyword or a template introduction. */
+ if (cp_parser_template_declaration_after_export (parser, member_p))
+ /* OK */;
else if (cxx_dialect >= cxx11
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
decl = cp_parser_alias_declaration (parser);
@@ -23675,7 +24483,7 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
/* There are no access checks when parsing a template, as we do not
know if a specialization will be a friend. */
push_deferring_access_checks (dk_no_check);
- token = cp_lexer_peek_token (parser->lexer);
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
decl = cp_parser_single_declaration (parser,
checks,
member_p,
@@ -23750,13 +24558,10 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
decl);
}
}
+
/* Register member declarations. */
if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
finish_member_declaration (decl);
- /* For the erroneous case of a template with C linkage, we pushed an
- implicit C++ linkage scope; exit that scope now. */
- if (need_lang_pop)
- pop_lang_context ();
/* If DECL is a function template, we must return to parse it later.
(Even though there is no definition, there might be default
arguments that need handling.) */
@@ -23765,6 +24570,182 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
vec_safe_push (unparsed_funs_with_definitions, decl);
}
+/* Parse a template introduction header for a template-declaration. Returns
+ false if tentative parse fails. */
+
+static bool
+cp_parser_template_introduction (cp_parser* parser, bool member_p)
+{
+ cp_parser_parse_tentatively (parser);
+
+ tree saved_scope = parser->scope;
+ tree saved_object_scope = parser->object_scope;
+ tree saved_qualifying_scope = parser->qualifying_scope;
+
+ /* Look for the optional `::' operator. */
+ cp_parser_global_scope_opt (parser,
+ /*current_scope_valid_p=*/false);
+ /* Look for the nested-name-specifier. */
+ cp_parser_nested_name_specifier_opt (parser,
+ /*typename_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ /*type_p=*/false,
+ /*is_declaration=*/false);
+
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ tree concept_name = cp_parser_identifier (parser);
+
+ /* Look up the concept for which we will be matching
+ template parameters. */
+ tree tmpl_decl = cp_parser_lookup_name_simple (parser, concept_name,
+ token->location);
+ parser->scope = saved_scope;
+ parser->object_scope = saved_object_scope;
+ parser->qualifying_scope = saved_qualifying_scope;
+
+ if (concept_name == error_mark_node)
+ cp_parser_simulate_error (parser);
+
+ /* Look for opening brace for introduction. */
+ cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
+
+ if (!cp_parser_parse_definitely (parser))
+ return false;
+
+ push_deferring_access_checks (dk_deferred);
+
+ /* Build vector of placeholder parameters and grab
+ matching identifiers. */
+ tree introduction_list = cp_parser_introduction_list (parser);
+
+ /* The introduction-list shall not be empty. */
+ int nargs = TREE_VEC_LENGTH (introduction_list);
+ if (nargs == 0)
+ {
+ error ("empty introduction-list");
+ return true;
+ }
+
+ /* Look for closing brace for introduction. */
+ if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE))
+ return true;
+
+ if (tmpl_decl == error_mark_node)
+ {
+ cp_parser_name_lookup_error (parser, concept_name, tmpl_decl, NLE_NULL,
+ token->location);
+ return true;
+ }
+
+ /* Build and associate the constraint. */
+ tree parms = finish_template_introduction (tmpl_decl, introduction_list);
+ if (parms && parms != error_mark_node)
+ {
+ cp_parser_template_declaration_after_parameters (parser, parms,
+ member_p);
+ return true;
+ }
+
+ error_at (token->location, "no matching concept for template-introduction");
+ return true;
+}
+
+/* Parse a normal template-declaration following the template keyword. */
+
+static void
+cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p)
+{
+ tree parameter_list;
+ bool need_lang_pop;
+ location_t location = input_location;
+
+ /* Look for the `<' token. */
+ if (!cp_parser_require (parser, CPP_LESS, RT_LESS))
+ return;
+ if (at_class_scope_p () && current_function_decl)
+ {
+ /* 14.5.2.2 [temp.mem]
+
+ A local class shall not have member templates. */
+ error_at (location,
+ "invalid declaration of member template in local class");
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ /* [temp]
+
+ A template ... shall not have C linkage. */
+ if (current_lang_name == lang_name_c)
+ {
+ error_at (location, "template with C linkage");
+ /* Give it C++ linkage to avoid confusing other parts of the
+ front end. */
+ push_lang_context (lang_name_cplusplus);
+ need_lang_pop = true;
+ }
+ else
+ need_lang_pop = false;
+
+ /* We cannot perform access checks on the template parameter
+ declarations until we know what is being declared, just as we
+ cannot check the decl-specifier list. */
+ push_deferring_access_checks (dk_deferred);
+
+ /* If the next token is `>', then we have an invalid
+ specialization. Rather than complain about an invalid template
+ parameter, issue an error message here. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
+ {
+ cp_parser_error (parser, "invalid explicit specialization");
+ begin_specialization ();
+ parameter_list = NULL_TREE;
+ }
+ else
+ {
+ /* Parse the template parameters. */
+ parameter_list = cp_parser_template_parameter_list (parser);
+ }
+
+ /* Look for the `>'. */
+ cp_parser_skip_to_end_of_template_parameter_list (parser);
+
+ /* Manage template requirements */
+ if (flag_concepts)
+ {
+ tree reqs = get_shorthand_constraints (current_template_parms);
+ if (tree r = cp_parser_requires_clause_opt (parser))
+ reqs = conjoin_constraints (reqs, make_predicate_constraint (r));
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
+ }
+
+ cp_parser_template_declaration_after_parameters (parser, parameter_list,
+ member_p);
+
+ /* For the erroneous case of a template with C linkage, we pushed an
+ implicit C++ linkage scope; exit that scope now. */
+ if (need_lang_pop)
+ pop_lang_context ();
+}
+
+/* Parse a template-declaration, assuming that the `export' (and
+ `extern') keywords, if present, has already been scanned. MEMBER_P
+ is as for cp_parser_template_declaration. */
+
+static bool
+cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
+{
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_explicit_template_declaration (parser, member_p);
+ return true;
+ }
+ else if (flag_concepts)
+ return cp_parser_template_introduction (parser, member_p);
+
+ return false;
+}
+
/* Perform the deferred access checks from a template-parameter-list.
CHECKS is a TREE_LIST of access checks, as returned by
get_deferred_access_checks. */
@@ -23832,6 +24813,12 @@ cp_parser_single_declaration (cp_parser* parser,
{
if (cp_parser_declares_only_class_p (parser))
{
+ // If this is a declaration, but not a definition, associate
+ // any constraints with the type declaration. Constraints
+ // are associated with definitions in cp_parser_class_specifier.
+ if (declares_class_or_enum == 1)
+ associate_classtype_constraints (decl_specifiers.type);
+
decl = shadow_tag (&decl_specifiers);
/* In this case:
@@ -33614,15 +34601,57 @@ tree_type_is_auto_or_concept (const_tree t)
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)
+{
+ gcc_assert (TREE_CODE (t) == PRED_CONSTR);
+ t = PRED_CONSTR_EXPR (t);
+ gcc_assert (TREE_CODE (t) == CALL_EXPR
+ || TREE_CODE (t) == TEMPLATE_ID_EXPR
+ || VAR_P (t));
+
+ if (TREE_CODE (t) == TEMPLATE_ID_EXPR)
+ return DECL_TEMPLATE_RESULT (TREE_OPERAND (t, 0));
+ if (VAR_P (t))
+ return DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (t));
+ else
+ {
+ tree fn = CALL_EXPR_FN (t);
+ tree ovl = TREE_OPERAND (fn, 0);
+ tree tmpl = OVL_FUNCTION (ovl);
+ 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
-synthesize_implicit_template_parm (cp_parser *parser)
+synthesize_implicit_template_parm (cp_parser *parser, tree constr)
{
gcc_assert (current_binding_level->kind == sk_function_parms);
+ /* Before committing to modifying any scope, if we're in an
+ implicit template scope, and we're trying to synthesize a
+ constrained parameter, try to find a previous parameter with
+ the same name. This is the same-type rule for abbreviated
+ function templates. */
+ if (parser->implicit_template_scope && constr)
+ {
+ 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);
+ t = TREE_CHAIN (t);
+ }
+ }
+
/* We are either continuing a function template that already contains implicit
template parameters, creating a new fully-implicit function template, or
extending an existing explicit function template with implicit template
@@ -33731,14 +34760,18 @@ synthesize_implicit_template_parm (cp_parser *parser)
tree synth_id = make_generic_type_name ();
tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
synth_id);
+
+ // Attach the constraint to the parm before processing.
+ tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
+ TREE_TYPE (node) = constr;
tree new_parm
= process_template_parm (parser->implicit_template_parms,
input_location,
- build_tree_list (NULL_TREE, synth_tmpl_parm),
+ node,
/*non_type=*/false,
/*param_pack=*/false);
-
+ // Chain the new parameter to the list of implicit parameters.
if (parser->implicit_template_parms)
parser->implicit_template_parms
= TREE_CHAIN (parser->implicit_template_parms);
@@ -33768,6 +34801,15 @@ synthesize_implicit_template_parm (cp_parser *parser)
TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
}
+ // If the new parameter was constrained, we need to add that to the
+ // constraints in the template parameter list.
+ if (tree req = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
+ {
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ reqs = conjoin_constraints (reqs, req);
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
+ }
+
current_binding_level = entry_scope;
return new_type;