aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
authorJason Merrill <jason@gcc.gnu.org>2019-10-09 13:20:32 -0400
committerJason Merrill <jason@gcc.gnu.org>2019-10-09 13:20:32 -0400
commitcb57504a550158913258e5be8ddb991376475efb (patch)
treed1f7676666e845ba7e77b45fcc3d6e5e0a2acb82 /gcc/cp/parser.c
parent8cb6a77590957942e124b34e0bb0827d1404f341 (diff)
downloadgcc-cb57504a550158913258e5be8ddb991376475efb.zip
gcc-cb57504a550158913258e5be8ddb991376475efb.tar.gz
gcc-cb57504a550158913258e5be8ddb991376475efb.tar.bz2
Update the concepts implementation to conform to C++20.
gcc/c-family/ * c-cppbuiltin.c (c_cpp_builtins): Use new feature test values for concepts when -std=c++2a. Bump __cpp_concepts to 201907. * c.opt: Add -Wconcepts-ts. * c-opts.c (c_common_post_options): Warn when -fconcepts is used with -std=c++2a. Disable warning for -fconcepts in C++20 mode. (set_std_cxx2a): Enable concepts by default. gcc/cp/ * call.c (build_new_function_call): Don't evaluate concepts here. (constraint_failure): Don't record the template. (print_z_candidate): Don't extract the template. * class.c (add_method): When overloading, hide ineligible special member fns. (check_methods): Set TYPE_HAS_COMPLEX_* here. * constexpr.c (cxx_eval_constant_expression): Evaluate concepts. (maybe_initialize_fundef_copies_table): Remove. (get_fundef_copy): Use hash_map_safe_get_or_insert. (clear_cv_and_fold_caches): Clear the satisfaction cache. * constraint.cc (known_non_bool_p): New. (parsing_constraint_expression_sentinel): Renamed from expanding_constraint_sentinel. (check_constraint_operands): New. (check_constraint_atom): New. (finish_constraint_binary_op): New. (finish_constraint_or_expr): Likewise. (finish_constraint_and_expr): Likewise. (finish_constraint_primary_expr): Likewise. (combine_constraint_expressions): New. (finish_requires_expr): Add location parm. (get_concept_definition): Return the initializer of concept definitions. (get_template_head_requirements): New. (get_trailing_function_requirements): New. (deduce_constrained_parameter): Check if the identifier or template-id is a concept definition. (resolve_concept_definition_check): Removed. (resolve_variable_concept_check): Removed. (resolve_concept_check): New. (resolve_constraint_check): Handle concept definitions. converting arguments. (function_concept_check_p): Removed. (variable_concept_check_p): Removed. (unpack_concept_check): New. (get_concept_check_template): New. (build_call_check): Moved and renamed to build_function_check. (build_concept_check_arguments): make static. (build_function_check): Always do overload resolution in order to force conversion of template arguments (i.e., actually check that the use of a concept is valid). (build_standard_check): Renamed from build_real_concept_check. (build_real_concept_check): Build checks for C++2a concepts by (build_wildcard_concept_check): New. (build_concept_check): Use build_real_concept_check. New overload. (build_constraints): Save expressions, not normalized constraints. (build_concept_id): New. Pass tf_warning_or_error. (build_type_constraint): New. (finish_type_constraints): New. (associate_classtype_constraints): Also add constraints to union types. Note the original declaration in errors. Don't return error_mark_node in order to avoid an assertion later. (push_down_pack_expansion): Remove. (finish_shorthand_constraint): Make fold expressions, not naked parameter packs. Always apply the constraint to each template argument. (check_introduction_list): New. Fail if not enough names are introduced. (finish_template_introduction): Don't normalize constraints. Pass tsubst flags. Check for insufficient introductions. (placeholder_extract_concept_and_args): Handle the template-id case. Unpack function concept checks correctly. (tsubst_simple_requirement): Return errors if they occur. Don't process as a template. (tsubst_type_requirement): Likewise. (type_deducible_p): New. Wrap the input expression in parens for the purpose of deduction. (expression_convertible_t): New. (tsubst_compound_requirement): Use new deduction, conversion predicates. (tsubst_nested_requirement): Return errors if they occur. Don't process as a template. Instantiate and evaluate the nested requirement. (tsubst_valid_expression_requirement): New. (tsubst_simple_requirement): Use tsubst_valid_expression_requirement. (tsubst_compound_requirement): Use tsubst_valid_expression_requirement. (check_constaint_variables): New. (tsubst_constraint_variables): Check that type substitutions are valid. (tsubst_requires_expr): Likewise. Produce new requires-exprs during template substitution. Copy the previous local specialization stack, so references to non-local parameters can be found. Use cp_unevaluated. (tsubst_constraint): New. Don't evaluate concept checks. (subst_info): New. (norm_info): New. Used to build a normalization tree for concept check diagnostics. (debug_parameter_mapping): New. (debug_argument_list): New. (expand_concept): Removed. (normalize_logical_operation): Pass subst_info through call. (normalize_pack_expansion): Remove. (normalize_simple_requirement): Removed (normalize_type_requirement): Removed (normalize_compound_requirement): Removed (normalize_nested_requirement): Removed (normalize_requirement): Removed (normalize_requirements): Removed (normalize_requires_expression): Removed (normalize_variable_concept_check): Removed. (normalize_function_concept_check): Removed. (normalize_concept_check): Merged all normalize_*_check here. Substitute through written template arguments before normalizing the definition. Only substitute the innermost template arguments. (check_for_logical_overloads): Delete. (map_arguments): New. Associate template parameters with arguments. (build_parameter_mapping): New. Extract used parameters. (normalize_expression): Rewrite. (normalize_conjunction): Removed (normalize_disjunction): Removed (normalize_predicate_constraint): Removed (normalize_parameterized_constraint): Removed (normalized_map): New variable. (get_normalized_constraints): New entry point for normalization. Establishes a timer. (get_normalized_constraints_from_info): New. (get_normalized_constraints_from_decl): New. Turn on template processing prior to normalization. Handle inheriting ctors. Build the normalization arguments from the full set of template parameters of the most general template. This guarantees that we have no concrete arguments in the parameter mapping (e.g., from template members of class templates). Cache normalizations. (normalize_concept_definition): New. Cache normalizations. (normalize_template_requirements): New. (normalize_nontemplate_requirements): New. (normalize_constraint_expression): New. (tsubst_parameter_mapping): New. (get_mapped_args): New. (parameter_mapping_equivalent_p): New. Use template_args_equal. (atomic_constraints_identical_p): New. (hash_atomic_constraint): New. (satisfying_constraint_p): New. Guard against recursive evaluation of constraints during satisfaction. (satisfy_conjunction): New. (satisfy_disjunction): New. (sat_entry): New class for hashing satisfaction results. (sat_hasher): New hash traits. (sat_cache): New. (get_satisfaction): New. Returns cached satisfaction result. (save_satisfaction): New. Caches a satisfaction result. (clear_satisfaction_cache): New. (satisfaction_cache): New. Helps manage satisfaction cache requests. (decl_satisfied_cache): New. (satisfy_atom): New. (satisfy_constraint_r): New. (satisfy_constraint): Use new satisfaction algorithm. (evaluate_concept_check): New. (evaluate_concept): Removed. (evaluate_function_concept): Removed. (evaluate_variable_concept): Removed. (satisfy_constraint_expression): New. (constraint_expression_satisfied_p): New. (constraints_satisfied_p): Use strip_inheriting_ctors. Use push_/pop_access_scope. (more_constrained): Normalize before calling out to subsumption. Allow classes as arguments. (strictly_subsumes): Allow non-templates as arguments. Accept a new template argument. (weakly_subsumes): New. (at_least_as_constrained): Removed. (diagnose_other_expression): Removed. (diagnose_predicate_constraint): Removed. (diagnose_pack_expansion): Removed. (diagnose_check_constraint): Removed. (diagnose_logical_constraint): Removed. (diagnose_expression_constraint): Removed. (diagnose_type_constraint): Removed. (diagnose_implicit_conversion_constraint): Removed. (diagnose_argument_deduction_constraint): Removed. (diagnose_exception_constraint): Removed. (diagnose_parameterized_constraint): Removed. (diagnose_argument_deduction_constraint): Removed. (diagnose_argument_deduction_constraint): Removed. (diagnose_argument_deduction_constraint): Removed. (diagnose_trait_expr): New. (diagnose_requires_expr): New. (diagnose_atomic_constraint): New. (diagnose_valid_expression) Stop wrongly diagnosing valid expressions. Don't substitute as if in template decls. This causes substitution to generate expressions that aren't suitable for use with the noexcept routines. (diagnose_valid_type) Likewise. (diagnose_compound_requirement) Actually emit diagnostics for the causes of errors.Call force_paren_expr_uneval. (diagnose_declaration_constraints): Turn on template processing to suppress certain analyses. * cp-objcp-common.c (cp_common_init_ts): Make concepts typed. (cp_get_debug_type): Use hash_map_safe_*. * cp-tree.h: New function declarations for semantic actions, other facilities. Remove declaration no longer used or needed. Remove unused _CONSTR macros. (LANG_DECL_HAS_MIN): Add CONCEPT_DECL. (template_info_decl_check): Factor macro check into an inline function. (DECL_TEMPLATE_INFO): Use new check facility. (finish_concept_definition): New. Don't invalid concept declarations with invalid initializers. (find_template_parameters): New. (concept_definition_p): New. (concept_check_p): New. (variable_concept_check_p): New. (force_paren_expr_uneval): New. (ovl_iterator::using_p): A USING_DECL by itself was also introduced by a using-declaration. (struct tree_template_info): Use tree_base instead of tree_common. Add tmpl and args fields. (TI_TEMPLATE, TI_ARGS): Adjust. (DECLTYPE_FOR_INIT_CAPTURE): Remove. (CONSTR_CHECK, CONSTR_INFO, CONSTR_EXPR, CONSTR_CONTEXT): New. (ATOMIC_CONSTR_MAP, TRAIT_EXPR_LOCATION): New. (struct tree_trait_expr): Add locus field. (enum tsubst_flags): Add tf_norm as a hint to generate normalization context when diagnosing constraint failure. * cp-tree.def: Remove unused _CONSTR nodes and rename PRED_CONSTR to ATOMIC_CONSTR. (CONCEPT_DECL): New. * cxx-pretty-print.c: Remove constraint printing code. (pp_cxx_concept_definition): New. (pp_cxx_template_declaration): Print concept definitions. (pp_cxx_check_constraint): Update printing for concept definitions. (pp_cxx_nested_name_specifier): Fix a weird case where we're printing '::::' for concepts. (simple_type_specifier): Print requirements for placeholder types. (pp_cxx_constrained_type_spec): Print the associated requirements of a placeholder type. (pp_cxx_compound_requirement): Add space before the '->'. (pp_cxx_parameter_mapping): Print the parameter mapping. (pp_cxx_atomic_constraint): Use the function above. * decl.c (redeclaration_error_message): New error for concepts. (grokdeclarator): Check for and disallow decltype(auto) in parameter declarations. (grokfndecl): Don't normalize constraints. Add check for constraints on declaration. (grokvardecl): Don't normalize constraints. (grok_special_member_properties): Don't set TYPE_HAS_COMPLEX_*. (function_requirements_equivalent_p): New. Compare trailing requires clauses. Compare combined constraints in pre-C++20 mode. (decls_match): Compare trailing requires clauses. Compare template heads for function templates. Remove old constraint comparison. Simplify comparison of functions, function templates. (duplicate_function_template_decls): New. Refactor a nasty if condition into a single predicate. (require_deduced_type): Don't complain if we already complained about deduction failure. (finish_function): Perform auto deduction to ensure that constraints are checked even when functions contain no return statements. Only do auto deduction if we haven't previously seen any return statements. This prevents multiple diagnostics of the same error. (store_decomp_type): Remove. (cp_finish_decomp): Use hash_map_safe_put. * error.c: Remove constraint printing code. (dump_decl): Dump concept definitions. Handle wildcard declarations. (dump_template_decl): Likewise. (dump_type): Print associated requirements for placeholder types. (rebuild_concept_check): New. (maybe_print_single_constraint_context): New. (maybe_print_constraint_context): Recursively print nested contexts. * init.c (get_nsdmi): Use hash_map_safe_*. * lambda.c (maybe_add_lambda_conv_op): Bail if deduction failed. (add_capture): Copy parameter packs from init. (lambda_capture_field_type): Always use auto for init-capture. * logic.cc: Completely rewrite. (constraint_hash): New. (clause/ctor): Save atoms in the hash table. (replace): Save atoms during replacement. (insert): Save atoms during insertion. (contains): Only search the hash table for containment. (clause): Keep a hash of atomic constraints. (clause::clause): Explicitly copy the hash table when copying. (disjunction_p, conjunction_p, atomic_p, dnf_size, cnf_size): New. (diagnose_constraint_size): New. (subsumes_constraints_nonnull): Compare the sizes of normalized formula to determine the cheapest decomposition. * name-lookup.c (diagnose_name_conflict): Diagnose name issues with concepts. (matching_fn_p): Check constraints. (push_class_level_binding_1): Move overloaded functions case down, accept FUNCTION_DECL as target_decl. * parser.c (enum required_token): New required token for auto. (make_location): Add overload taking lexer as last parm. (cp_parser_required_error): Diagnose missing auto. (cp_parser_diagnose_ungrouped_constraint_plain): New. (cp_parser_diagnose_ungrouped_constraint_plain): New. (cp_parser_constraint_primary_expression): New. Tentatively parse the primary expression. If that fails tentatively parse a lower precedence expression in order to diagnose the error. (cp_parser_check_non_logical_constraint): New. Performs a trial parse of the right-hand-side of non-logical operators in order to generate good diagnostics. (cp_parser_constraint_logical_and_expression): New. (cp_parser_constraint_logical_or_expression): New. (cp_parser_requires_clause_expression): New. (cp_parser_requires_clause): Renamed to cp_parser_constraint_expression. (cp_parser_requires_clause_opt): Parse the requires-clause differently in -fconcepts and -std=c++2a modes. (cp_parser_requirement_list): Rename to cp_parser_requirement_seq. Rewrite so that semicolons are parsed along with requirements, not the sequence. (cp_parser_simple_requirement): Expect a semicolon at end. (cp_parser_compound_requirement): Expect a semicolon at end. Only allow trailing-return-type with -fconcepts-ts. (cp_parser_nested_requirement): Expect a semicolon at end. Parse constraint-expressions. (cp_parser_concept_definition): New. Don't fail parsing the concept definition if the initializer is ill-formed. Don't declare the concept before parsing the initializer. (cp_parser_constraint_expression): Declare earlier. (cp_parser_type_requirement): Current scope is not valid. (cp_parser_requires_expression): Commit to the tentative parse. (cp_parser_decl_specifier_seq): Warn when concept appears to be used as a decl-specifier. (cp_parser_template_declaration_after_parameters): Parse concept definitions. (cp_parser_template_id): Don't try to resolve a concept template-id yet. (cp_parser_template_id_expr): Resolve it as a concept check. (cp_parser_decl_specifier_seq): Warn on 'concept bool'. (cp_parser_type_parameter): Combine expressions not constraints. (cp_parser_explicit_template_declaration): Combine expressions not constraints. (cp_parser_maybe_concept_name): Removed. (cp_parser_simple_type_specifier): Handle an error condition of a bad constrained type specifier. Expect auto or decltype after a concept name. Also handle the case where we have a template-id as a concept check. (cp_parser_template_introduction): Diagnose errors on invalid introductions. Give up if it doesn't start with a concept name. Pedwarn if not -fconcepts-ts. (synthesize_implicit_template_parm): Don't do consistent binding. Use a new flag for constrained parameters. Combine expressions, not constraints. Fail if we get a placeholder in block scope. Placeholders that do not constrain types are not allowed in parameter declarations, so don't handle them. (cp_parser_placeholder_type_specifier): New. Implement parsing of placeholder type specifiers following a concept name or partial concept check. Disallow decltype(auto) parameters. (cp_parser_nested_name_specifier_opt): If the token is already CPP_NESTED_NAME_SPECIFIER, leave it alone. (cp_parser_id_expression, cp_parser_unqualified_id): Call cp_parser_template_id_expr. (cp_parser_placeholder_type_specifier): Add tentative parm. Don't expect a WILDCARD_DECL. (cp_parser_trait_expr): Pass trait_loc down. (cp_parser_postfix_expression): Do set location of dependent member call. * pt.c (finish_concept_definition): New. (push_template_decl_real): Handle concept definitions. (start_concept_definition): Let push_template_decl_real handle the creation of the template. (get_constraints): Return null if the table hasn't been initialized. (tsubst_copy_and_build): Build template-id expressions for concept checks. [TRAIT_EXPR]: Pass trait_loc down. (lookup_template_class_1): Add the template name to the constraint failure diagnostic. (lookup_and_finish_template_variable): Build concept checks with the correct arguments. (tsubst_function_decl): Don't substitute through constraints. Always associate constraints with functions. (template_parm_level_and_index): Make non-static. (for_each_template_parm_r): Handle requires expressions. (keep_template_parm): New. (find_template_parameters): New. (more_specialized_fn): Change how winners and losers are chosen. (make_constrained_auto): Don't normalize constraints. (template_parameters_equivalent_p): New. Compare template parameters. Add a comparison for implicitly vs. explicitly declared parameters. (template_parameter_lists_equivalent_p): New. Compare template parameter lists. (template_requirements_equivalent_p): New. (template_heads_equivalent_p): New. Compare template heads. (template_parameter_constraints_equivalent_p): New. (is_compatible_template_arg): Use weakly_subsumes. (maybe_new_partial_specialization): Use new constraint comparison for finding specializations. (process_partial_specialization): Pass main template as argument. (more_specialized_partial_spec): Don't immediately return when detecting a winner. (make_constrained_auto): Handle concept definitions. (do_auto_deduction): Update auto deduction for new concept model. Extract the function concept correctly; rename constr to check to reflect the kind of node. (tsubst): Adjust wildcard argument during substitution. [DECLTYPE_TYPE]: Remove init-capture handling. (tsubst_copy_and_build): Build concept checks, not template ids. Defer checks of function concepts. Handle concepts before variable templates. Handle calls to function concepts explicitly. (coerce_template_parms): Use concept_definition_p. Handle a deduction error where a potentially empty pack can be supplied after the last parameter of a concept. (finish_template_variable): Don't process concepts here. (instantiation_dependent_r): Use concept_check_p. (tsubst_template_args): Make non-static. (make_constrained_placeholder_type): New. Refactored from make_constrained_auto. (make_constrained_auto) Use make_constrained_placeholder_type. (make_constrained_decltype_auto) New. (tsubst_function_parms): New. (value_dependent_expression_p) [TEMPLATE_ID_EXPR]: Use concept_definition_p. (push_access_scope, pop_access_scope): No longer static. (tsubst_template_parm): Substitute TEMPLATE_PARM_CONSTRAINTS. (tsubst_friend_function): Use tsubst_constraint. Use generic_targs_for. (get_underlying_template) Use generic_targs_for. (uses_parameter_packs): Return tree. (gen_elem_of_pack_expansion_instantiation): Don't push local_specialization_stack. (prepend_one_capture): New. (tsubst_lambda_expr): Use prepend_one_capture. Don't touch local_specializations. (template_parms_level_to_args): No longer static. (add_outermost_template_args): Likewise. (find_template_parameter_info): New. Provide context for finding template parameters. (keep_template_parm): Don't keep parameters declared at depth levels greater than those of the template parameters of the source declaration. Don't propagate cv-qualified types. Return 0, so we find all template parameters, not the just first. (any_template_parm_r): New. Handle cases that are mishandled by for_each_template_parm_r. (generic_targs_for): Factor out of coerce_template_args_for_ttp. (tsubst_argument_pack): Factor out of tsubst_template_args. (constraint_sat_entry): Removed. (constraint_sat_hasher): Removed. (concept_spec_entry): Removed. (concept_spec_hasher): Removed. (constraint_memos): Removed. (concept_memos): Removed. (lookup_constraint_satisfaction): Removed. (memoize_constraint_satisfaction): Removed. (lookup_concept_satisfaction): Removed. (memoize_concept_satisfaction): Removed. (concept_expansions): Removed. (get_concept_expansion): Removed. (save_concept_expansion): Removed. (init_constraint_processing): Remove initialization of non-existing resources. (find_template_requirement): New. Search for the sub-requirement within the associated constraints. (convert_generic_types_to_packs): Also transform the associated constraint and update the current template requirements. (store_defaulted_ttp, lookup_defaulted_ttp): Remove. (add_defaults_to_ttp): Use hash_map_safe_*. * semantics.c (finish_call_expr): Diagnose calls to concepts. Handle concept checks explicitly. (finish_id_expression): Evaluate variable concepts as part of id-expression processing. Don't treat variable concepts as variables, and don't process function concepts as plain id-expressions. (force_paren_expr): Add even_uneval parm. (finish_trait_expr): Add location parm. * tree.c (special_memfn_p): New. (cp_expr_location): Handle TRAIT_EXPR. * typeck.c (check_return_expr): Actually use the diagnostic kind when performing return-type deduction. * typeck2.c (build_functional_cast): Don't rely on the location of 'auto'. gcc/testsuite/ * lib/target-supports.exp (check_effective_target_concepts): Check for std=c++2a. gcc/ * doc/invoke.texi: Document -fconcepts-ts. From-SVN: r276764
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c951
1 files changed, 682 insertions, 269 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c61e0b2..b6e738c 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -169,6 +169,7 @@ enum required_token {
RT_TRY, /* try */
RT_CATCH, /* catch */
RT_THROW, /* throw */
+ RT_AUTO, /* auto */
RT_LABEL, /* __label__ */
RT_AT_TRY, /* @try */
RT_AT_SYNCHRONIZED, /* @synchronized */
@@ -2196,6 +2197,8 @@ static tree cp_parser_type_specifier
int *, bool *);
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
+static tree cp_parser_placeholder_type_specifier
+ (cp_parser *, location_t, tree, bool);
static tree cp_parser_type_name
(cp_parser *, bool);
static tree cp_parser_nonclass_name
@@ -2369,6 +2372,8 @@ static tree cp_parser_type_parameter
(cp_parser *, bool *);
static tree cp_parser_template_id
(cp_parser *, bool, bool, enum tag_types, bool);
+static tree cp_parser_template_id_expr
+ (cp_parser *, bool, bool, bool);
static tree cp_parser_template_name
(cp_parser *, bool, bool, bool, enum tag_types, bool *);
static tree cp_parser_template_argument_list
@@ -2444,7 +2449,9 @@ static void cp_parser_label_declaration
/* Concept Extensions */
-static tree cp_parser_requires_clause
+static tree cp_parser_concept_definition
+ (cp_parser *);
+static tree cp_parser_constraint_expression
(cp_parser *);
static tree cp_parser_requires_clause_opt
(cp_parser *);
@@ -2454,7 +2461,7 @@ static tree cp_parser_requirement_parameter_list
(cp_parser *);
static tree cp_parser_requirement_body
(cp_parser *);
-static tree cp_parser_requirement_list
+static tree cp_parser_requirement_seq
(cp_parser *);
static tree cp_parser_requirement
(cp_parser *);
@@ -2687,11 +2694,6 @@ static bool cp_parser_init_statement_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
//
@@ -4874,6 +4876,8 @@ class token_pair
m_open_loc);
}
+ location_t open_location () const { return m_open_loc; }
+
private:
location_t m_open_loc;
};
@@ -4948,7 +4952,7 @@ cp_parser_statement_expr (cp_parser *parser)
This returns the tree code corresponding to the matched operator
as an int. When the current token matches a compound assignment
- opertor, the resulting tree code is the negative value of the
+ operator, the resulting tree code is the negative value of the
non-assignment operator. */
static int
@@ -5904,11 +5908,10 @@ cp_parser_id_expression (cp_parser *parser,
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
- id = cp_parser_template_id (parser,
- /*template_keyword_p=*/false,
- /*check_dependency_p=*/true,
- none_type,
- declarator_p);
+ id = cp_parser_template_id_expr (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ declarator_p);
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
@@ -5983,10 +5986,9 @@ cp_parser_unqualified_id (cp_parser* parser,
template-id. */
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
- id = cp_parser_template_id (parser, template_keyword_p,
- check_dependency_p,
- none_type,
- declarator_p);
+ id = cp_parser_template_id_expr (parser, template_keyword_p,
+ check_dependency_p,
+ declarator_p);
/* If it worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
@@ -5995,10 +5997,9 @@ cp_parser_unqualified_id (cp_parser* parser,
}
case CPP_TEMPLATE_ID:
- return cp_parser_template_id (parser, template_keyword_p,
- check_dependency_p,
- none_type,
- declarator_p);
+ return cp_parser_template_id_expr (parser, template_keyword_p,
+ check_dependency_p,
+ declarator_p);
case CPP_COMPL:
{
@@ -6239,10 +6240,9 @@ cp_parser_unqualified_id (cp_parser* parser,
/* This could be a template-id, so we try that first. */
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
- id = cp_parser_template_id (parser, template_keyword_p,
- /*check_dependency_p=*/true,
- none_type,
- declarator_p);
+ id = cp_parser_template_id_expr (parser, template_keyword_p,
+ /*check_dependency_p=*/true,
+ declarator_p);
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
@@ -9638,6 +9638,8 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
current.lhs = error_mark_node;
else
{
+ current.lhs.maybe_add_location_wrapper ();
+ rhs.maybe_add_location_wrapper ();
current.lhs
= build_min (current.tree_type,
TREE_CODE_CLASS (current.tree_type)
@@ -14059,10 +14061,26 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
case RID_CONCEPT:
ds = ds_concept;
cp_lexer_consume_token (parser->lexer);
+
+ /* Warn for concept as a decl-specifier. We'll rewrite these as
+ concept declarations later. */
+ if (!flag_concepts_ts)
+ {
+ cp_token *next = cp_lexer_peek_token (parser->lexer);
+ if (next->keyword == RID_BOOL)
+ pedwarn (next->location, 0, "the %<bool%> keyword is not "
+ "allowed in a C++20 concept definition");
+ else
+ pedwarn (token->location, 0, "C++20 concept definition syntax "
+ "is %<concept <name> = <expr>%> ");
+ }
+
/* In C++20 a concept definition is just 'concept name = expr;'
- Support that syntax by pretending we've seen 'bool'. */
+ Support that syntax as a TS extension by pretending we've seen
+ the 'bool' specifier. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
- && cp_lexer_nth_token_is (parser->lexer, 2, CPP_EQ))
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_EQ)
+ && !decl_specs->any_type_specifiers_p)
{
cp_parser_set_decl_spec_type (decl_specs, boolean_type_node,
token, /*type_definition*/false);
@@ -15800,15 +15818,15 @@ get_unqualified_id (cp_declarator *declarator)
return NULL_TREE;
}
-/* Returns true if DECL represents a constrained-parameter. */
+/* Returns true if TYPE would declare a constrained constrained-parameter. */
static inline bool
-is_constrained_parameter (tree decl)
+is_constrained_parameter (tree type)
{
- return (decl
- && TREE_CODE (decl) == TYPE_DECL
- && CONSTRAINED_PARM_CONCEPT (decl)
- && DECL_P (CONSTRAINED_PARM_CONCEPT (decl)));
+ 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. */
@@ -15894,8 +15912,8 @@ cp_parser_constrained_template_template_parm (cp_parser *parser,
declarator. */
static tree
-constrained_non_type_template_parm (bool *is_non_type,
- cp_parameter_declarator *parm)
+cp_parser_constrained_non_type_template_parm (bool *is_non_type,
+ cp_parameter_declarator *parm)
{
*is_non_type = true;
cp_declarator *decl = parm->declarator;
@@ -15912,20 +15930,13 @@ constrained_non_type_template_parm (bool *is_non_type,
static tree
finish_constrained_parameter (cp_parser *parser,
cp_parameter_declarator *parmdecl,
- bool *is_non_type,
- bool *is_parameter_pack)
+ bool *is_non_type)
{
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)
@@ -15934,7 +15945,7 @@ finish_constrained_parameter (cp_parser *parser,
parm = cp_parser_constrained_template_template_parm (parser, proto, id,
parmdecl);
else
- parm = constrained_non_type_template_parm (is_non_type, parmdecl);
+ parm = cp_parser_constrained_non_type_template_parm (is_non_type, parmdecl);
if (parm == error_mark_node)
return error_mark_node;
@@ -15949,14 +15960,13 @@ finish_constrained_parameter (cp_parser *parser,
/* Returns true if the parsed type actually represents the declaration
of a type template-parameter. */
-static inline bool
+static 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. */
@@ -16132,12 +16142,11 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
cp_lexer_consume_token (parser->lexer);
}
- // The parameter may have been constrained.
+ /* The parameter may have been constrained type parameter. */
if (is_constrained_parameter (parameter_declarator))
return finish_constrained_parameter (parser,
parameter_declarator,
- is_non_type,
- is_parameter_pack);
+ is_non_type);
// Now we're sure that the parameter is a non-type parameter.
*is_non_type = true;
@@ -16263,8 +16272,8 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
if (flag_concepts)
{
tree reqs = get_shorthand_constraints (current_template_parms);
- if (tree r = cp_parser_requires_clause_opt (parser))
- reqs = conjoin_constraints (reqs, normalize_expression (r));
+ if (tree dreqs = cp_parser_requires_clause_opt (parser))
+ reqs = combine_constraint_expressions (reqs, dreqs);
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
@@ -16370,6 +16379,7 @@ cp_parser_template_id (cp_parser *parser,
/* If the next token corresponds to a template-id, there is no need
to reparse it. */
cp_token *token = cp_lexer_peek_token (parser->lexer);
+
if (token->type == CPP_TEMPLATE_ID)
{
cp_lexer_consume_token (parser->lexer);
@@ -16512,7 +16522,7 @@ cp_parser_template_id (cp_parser *parser,
= make_location (token->location, token->location, parser->lexer);
/* Check for concepts autos where they don't belong. We could
- identify types in some cases of idnetifier TEMPL, looking ahead
+ identify types in some cases of identifier TEMPL, looking ahead
for a CPP_SCOPE, but that would buy us nothing: we accept auto in
types. We reject them in functions, but if what we have is an
identifier, even with none_type we can't conclude it's NOT a
@@ -16538,11 +16548,13 @@ 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 (concept_definition_p (templ))
+ {
+ /* The caller will decide whether this is a concept check or type
+ constraint. */
+ template_id = build2_loc (combined_loc, TEMPLATE_ID_EXPR,
+ boolean_type_node, templ, arguments);
+ }
else if (variable_template_p (templ))
{
template_id = lookup_template_variable (templ, arguments);
@@ -16599,6 +16611,23 @@ cp_parser_template_id (cp_parser *parser,
return template_id;
}
+/* Like cp_parser_template_id, called in non-type context. */
+
+static tree
+cp_parser_template_id_expr (cp_parser *parser,
+ bool template_keyword_p,
+ bool check_dependency_p,
+ bool is_declaration)
+{
+ tree x = cp_parser_template_id (parser, template_keyword_p, check_dependency_p,
+ none_type, is_declaration);
+ if (TREE_CODE (x) == TEMPLATE_ID_EXPR
+ && concept_check_p (x))
+ /* We didn't check the arguments in cp_parser_template_id; do that now. */
+ return build_concept_id (x);
+ return x;
+}
+
/* Parse a template-name.
template-name:
@@ -17019,11 +17048,7 @@ cp_parser_template_argument (cp_parser* parser)
/*check_dependency=*/true,
/*ambiguous_decls=*/NULL,
argument_start_token->location);
- /* 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
+ if (TREE_CODE (argument) != TEMPLATE_DECL
&& TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
cp_parser_error (parser, "expected template-name");
}
@@ -17772,7 +17797,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
else if (!flag_concepts)
pedwarn (token->location, 0,
"use of %<auto%> in parameter declaration "
- "only available with %<-fconcepts%>");
+ "only available with %<-fconcepts-ts%>");
}
else
type = make_auto ();
@@ -17888,6 +17913,10 @@ cp_parser_simple_type_specifier (cp_parser* parser,
if (flags & CP_PARSER_FLAGS_OPTIONAL)
cp_parser_parse_tentatively (parser);
+ /* Remember current tentative parsing state -- if we know we need
+ a type, we can give better diagnostics here. */
+ bool tent = cp_parser_parsing_tentatively (parser);
+
token = cp_lexer_peek_token (parser->lexer);
/* Look for the optional `::' operator. */
@@ -17942,13 +17971,44 @@ cp_parser_simple_type_specifier (cp_parser* parser,
type = NULL_TREE;
}
+ if (!type && flag_concepts && decl_specs)
+ {
+ /* Try for a type-constraint with template arguments. We check
+ decl_specs here to avoid trying this for a functional cast. */
+
+ cp_parser_parse_tentatively (parser);
+
+ type = cp_parser_template_id (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ none_type,
+ /*is_declaration=*/false);
+ if (type && concept_check_p (type))
+ {
+ location_t loc = EXPR_LOCATION (type);
+ type = cp_parser_placeholder_type_specifier (parser, loc,
+ type, tent);
+ if (tent && type == error_mark_node)
+ /* Perhaps it's a concept-check expression. */
+ cp_parser_simulate_error (parser);
+ }
+ else
+ cp_parser_simulate_error (parser);
+
+ if (!cp_parser_parse_definitely (parser))
+ type = NULL_TREE;
+ }
+
if (!type && cxx_dialect >= cxx17)
{
- /* Try class template argument deduction. */
+ /* Try class template argument deduction or type-constraint without
+ template arguments. */
tree name = cp_parser_identifier (parser);
if (name && TREE_CODE (name) == IDENTIFIER_NODE
&& parser->scope != error_mark_node)
{
+ location_t loc
+ = cp_lexer_previous_token (parser->lexer)->location;
tree tmpl = cp_parser_lookup_name (parser, name,
none_type,
/*is_template=*/false,
@@ -17960,6 +18020,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
&& (DECL_CLASS_TEMPLATE_P (tmpl)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
type = make_template_placeholder (tmpl);
+ else if (flag_concepts && tmpl && concept_definition_p (tmpl))
+ type = cp_parser_placeholder_type_specifier (parser, loc,
+ tmpl, tent);
else
{
type = error_mark_node;
@@ -18031,6 +18094,140 @@ cp_parser_simple_type_specifier (cp_parser* parser,
return type;
}
+/* Parse the remainder of a placholder-type-specifier.
+
+ placeholder-type-specifier:
+ type-constraint_opt auto
+ type-constraint_opt decltype(auto)
+
+ The raw form of the constraint is parsed in cp_parser_simple_type_specifier
+ and passed as TMPL. This function converts TMPL to an actual type-constraint,
+ parses the placeholder type, and performs some contextual syntactic analysis.
+
+ LOC provides the location of the template name.
+
+ TENTATIVE is true if the type-specifier parsing is tentative; in that case,
+ don't give an error if TMPL isn't a valid type-constraint, as the template-id
+ might actually be a concept-check,
+
+ Note that the Concepts TS allows the auto or decltype(auto) to be
+ omitted in a constrained-type-specifier. */
+
+tree
+cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
+ tree tmpl, bool tentative)
+{
+ if (tmpl == error_mark_node)
+ return error_mark_node;
+
+ tree orig_tmpl = tmpl;
+
+ /* Get the arguments as written for subsequent analysis. */
+ tree args = NULL_TREE;
+ if (TREE_CODE (tmpl) == TEMPLATE_ID_EXPR)
+ {
+ args = TREE_OPERAND (tmpl, 1);
+ tmpl = TREE_OPERAND (tmpl, 0);
+ }
+ if (args == NULL_TREE)
+ /* A concept-name with no arguments can't be an expression. */
+ tentative = false;
+
+ tsubst_flags_t complain = tentative ? tf_none : tf_warning_or_error;
+
+ /* 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)
+ return error_mark_node;
+
+ /* As per the standard, require auto or decltype(auto), except in some
+ cases (template parameter lists, -fconcepts-ts enabled). */
+ cp_token *placeholder = NULL, *open_paren = NULL, *close_paren = NULL;
+ if (cxx_dialect >= cxx2a)
+ {
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
+ placeholder = cp_lexer_consume_token (parser->lexer);
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DECLTYPE))
+ {
+ placeholder = cp_lexer_consume_token (parser->lexer);
+ open_paren = cp_parser_require (parser, CPP_OPEN_PAREN,
+ RT_OPEN_PAREN);
+ cp_parser_require_keyword (parser, RID_AUTO, RT_AUTO);
+ close_paren = cp_parser_require (parser, CPP_CLOSE_PAREN,
+ RT_CLOSE_PAREN,
+ open_paren->location);
+ }
+ }
+
+ /* A type constraint constrains a contextually determined type or type
+ parameter pack. However, the the Concepts TS does allow concepts
+ to introduce non-type and template template parameters. */
+ if (TREE_CODE (proto) != TYPE_DECL)
+ {
+ if (!flag_concepts_ts
+ || !processing_template_parmlist)
+ {
+ 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)
+ return build_constrained_parameter (con, proto, args);
+
+ /* Diagnose issues placeholder issues. */
+ if (!flag_concepts_ts
+ && !parser->in_result_type_constraint_p
+ && !placeholder)
+ {
+ tree id = build_nt (TEMPLATE_ID_EXPR, tmpl, args);
+ tree expr = DECL_P (orig_tmpl) ? DECL_NAME (con) : id;
+ error_at (input_location,
+ "expected %<auto%> or %<decltype(auto)%> after %qE", expr);
+ /* Fall through. This is an error of omission. */
+ }
+ else if (parser->in_result_type_constraint_p && placeholder)
+ {
+ /* A trailing return type only allows type-constraints. */
+ error_at (input_location,
+ "unexpected placeholder in constrained result type");
+ }
+
+ /* In a parameter-declaration-clause, a placeholder-type-specifier
+ results in an invented template parameter. */
+ if (parser->auto_is_implicit_function_template_parm_p)
+ {
+ if (placeholder && token_is_decltype (placeholder))
+ {
+ location_t loc = make_location (placeholder->location,
+ placeholder->location,
+ close_paren->location);
+ error_at (loc, "cannot declare a parameter with %<decltype(auto)%>");
+ return error_mark_node;
+ }
+ tree parm = build_constrained_parameter (con, proto, args);
+ return synthesize_implicit_template_parm (parser, parm);
+ }
+
+ /* Determine if the type should be deduced using template argument
+ deduction or decltype deduction. Note that the latter is always
+ used for type-constraints in trailing return types. */
+ bool decltype_p = placeholder
+ ? placeholder->keyword == RID_DECLTYPE
+ : parser->in_result_type_constraint_p;
+
+ /* Otherwise, this is the type of a variable or return type. */
+ if (decltype_p)
+ return make_constrained_decltype_auto (con, args);
+ else
+ return make_constrained_auto (con, args);
+}
+
/* Parse a type-name.
type-name:
@@ -18103,8 +18300,6 @@ cp_parser_type_name (cp_parser* parser, bool typename_keyword_p)
&& 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);
@@ -18116,105 +18311,6 @@ cp_parser_type_name (cp_parser* parser, bool typename_keyword_p)
return type_decl;
}
-/* 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 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)
-{
- 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,
- 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.
@@ -18245,10 +18341,6 @@ 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 (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)))
{
@@ -26886,30 +26978,279 @@ cp_parser_label_declaration (cp_parser* parser)
}
// -------------------------------------------------------------------------- //
+// Concept definitions
+
+static tree
+cp_parser_concept_definition (cp_parser *parser)
+{
+ gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT));
+ cp_lexer_consume_token (parser->lexer);
+
+ cp_expr id = cp_parser_identifier (parser);
+ if (id == error_mark_node)
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return NULL_TREE;
+ }
+
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return error_mark_node;
+ }
+
+ processing_constraint_expression_sentinel parsing_constraint;
+ tree init = cp_parser_constraint_expression (parser);
+ if (init == error_mark_node)
+ cp_parser_skip_to_end_of_statement (parser);
+
+ /* Consume the trailing ';'. Diagnose the problem if it isn't there,
+ but continue as if it were. */
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ return finish_concept_definition (id, init);
+}
+
+// -------------------------------------------------------------------------- //
// 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.
+/* Diagnose an expression that should appear in ()'s within a requires-clause
+ and suggest where to place those parentheses. */
+
+static void
+cp_parser_diagnose_ungrouped_constraint_plain (location_t loc)
+{
+ error_at (loc, "expression after %<requires%> must be enclosed "
+ "in parentheses");
+}
+
+static void
+cp_parser_diagnose_ungrouped_constraint_rich (location_t loc)
+{
+ gcc_rich_location richloc (loc);
+ richloc.add_fixit_insert_before ("(");
+ richloc.add_fixit_insert_after (")");
+ error_at (&richloc, "expression after %<requires%> must be enclosed "
+ "in parentheses");
+}
+
+/* Parse a primary expression within a constraint. */
+
+static cp_expr
+cp_parser_constraint_primary_expression (cp_parser *parser)
+{
+ cp_parser_parse_tentatively (parser);
+ cp_id_kind idk;
+ location_t loc = input_location;
+ cp_expr expr = cp_parser_primary_expression (parser,
+ /*address_p=*/false,
+ /*cast_p=*/false,
+ /*template_arg_p=*/false,
+ &idk);
+ expr.maybe_add_location_wrapper ();
+ if (expr != error_mark_node)
+ expr = finish_constraint_primary_expr (expr);
+ if (cp_parser_parse_definitely (parser))
+ return expr;
+
+ /* Retry the parse at a lower precedence. If that succeeds, diagnose the
+ error, but return the expression as if it were valid. */
+ cp_parser_parse_tentatively (parser);
+ expr = cp_parser_simple_cast_expression (parser);
+ if (cp_parser_parse_definitely (parser))
+ {
+ cp_parser_diagnose_ungrouped_constraint_rich (expr.get_location());
+ return expr;
+ }
+
+ /* Otherwise, something has gone wrong, but we can't generate a more
+ meaningful diagnostic or recover. */
+ cp_parser_diagnose_ungrouped_constraint_plain (loc);
+ return error_mark_node;
+}
+
+/* Examine the token following EXPR. If it is an operator in a non-logical
+ binary expression, diagnose that as an error. Returns ERROR_MARK_NODE. */
+
+static cp_expr
+cp_parser_check_non_logical_constraint (cp_parser *parser, cp_expr lhs)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ switch (token->type)
+ {
+ default:
+ return lhs;
+
+ /* Arithmetic operators. */
+ case CPP_PLUS:
+ case CPP_MINUS:
+ case CPP_MULT:
+ case CPP_DIV:
+ case CPP_MOD:
+ /* Bitwise operators. */
+ case CPP_AND:
+ case CPP_OR:
+ case CPP_XOR:
+ case CPP_RSHIFT:
+ case CPP_LSHIFT:
+ /* Relational operators. */
+ /* FIXME: Handle '<=>'. */
+ case CPP_EQ_EQ:
+ case CPP_NOT_EQ:
+ case CPP_LESS:
+ case CPP_GREATER:
+ case CPP_LESS_EQ:
+ case CPP_GREATER_EQ:
+ /* Conditional operator */
+ case CPP_QUERY:
+ /* Pointer-to-member. */
+ case CPP_DOT_STAR:
+ case CPP_DEREF_STAR:
+ /* Assignment operators. */
+ case CPP_PLUS_EQ:
+ case CPP_MINUS_EQ:
+ case CPP_MULT_EQ:
+ case CPP_DIV_EQ:
+ case CPP_MOD_EQ:
+ case CPP_AND_EQ:
+ case CPP_OR_EQ:
+ case CPP_XOR_EQ:
+ case CPP_RSHIFT_EQ:
+ case CPP_LSHIFT_EQ:
+ break;
+
+ case CPP_EQ: {
+ /* An equal sign may be part of the the definition of a function,
+ and not an assignment operator, when parsing the expression
+ for a trailing requires-clause. For example:
+
+ template<typename T>
+ struct S {
+ S() requires C<T> = default;
+ }
+
+ This is not an error. */
+ if (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_DELETE)
+ || cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_DEFAULT))
+ return lhs;
+
+ break;
+ }
+ }
+
+ /* Try to parse the RHS as either the remainder of a conditional-expression
+ or a logical-or-expression so we can form a good diagnostic. */
+ cp_parser_parse_tentatively (parser);
+ cp_expr rhs;
+ if (token->type == CPP_QUERY)
+ rhs = cp_parser_question_colon_clause (parser, lhs);
+ else
+ {
+ cp_lexer_consume_token (parser->lexer);
+ rhs = cp_parser_binary_expression (parser, false, false, false,
+ PREC_NOT_OPERATOR, NULL);
+ }
+
+ /* If we couldn't parse the RHS, then emit the best diagnostic we can. */
+ if (!cp_parser_parse_definitely (parser))
+ {
+ cp_parser_diagnose_ungrouped_constraint_plain (token->location);
+ return error_mark_node;
+ }
+
+ /* Otherwise, emit a fixit for the complete binary expression. */
+ location_t loc = make_location (token->location,
+ lhs.get_start(),
+ rhs.get_finish());
+ cp_parser_diagnose_ungrouped_constraint_rich (loc);
+ return error_mark_node;
+}
+
+/* Parse a constraint-logical-and-expression.
+
+ constraint-logical-and-expression:
+ primary-expression
+ constraint-logical-and-expression '&&' primary-expression */
+
+static cp_expr
+cp_parser_constraint_logical_and_expression (cp_parser *parser)
+{
+ cp_expr lhs = cp_parser_constraint_primary_expression (parser);
+ while (cp_lexer_next_token_is (parser->lexer, CPP_AND_AND))
+ {
+ cp_token *op = cp_lexer_consume_token (parser->lexer);
+ tree rhs = cp_parser_constraint_primary_expression (parser);
+ lhs = finish_constraint_and_expr (op->location, lhs, rhs);
+ }
+ return cp_parser_check_non_logical_constraint (parser, lhs);
+}
+
+/* Parse a constraint-logical-or-expression.
+
+ constraint-logical-or-expression:
+ constraint-logical-and-expression
+ constraint-logical-or-expression '||' constraint-logical-and-expression */
+
+static cp_expr
+cp_parser_constraint_logical_or_expression (cp_parser *parser)
+{
+ cp_expr lhs = cp_parser_constraint_logical_and_expression (parser);
+ while (cp_lexer_next_token_is (parser->lexer, CPP_OR_OR))
+ {
+ cp_token *op = cp_lexer_consume_token (parser->lexer);
+ cp_expr rhs = cp_parser_constraint_logical_and_expression (parser);
+ lhs = finish_constraint_or_expr (op->location, lhs, rhs);
+ }
+ return cp_parser_check_non_logical_constraint (parser, lhs);
+}
+
+/* Parse the expression after a requires-clause. This has a different grammar
+ than that in the concepts TS. */
+
static tree
-cp_parser_requires_clause (cp_parser *parser)
+cp_parser_requires_clause_expression (cp_parser *parser)
{
- // Parse the requires clause so that it is not automatically folded.
+ processing_constraint_expression_sentinel parsing_constraint;
++processing_template_decl;
- tree expr = cp_parser_binary_expression (parser, false, false,
- PREC_NOT_OPERATOR, NULL);
+ cp_expr expr = cp_parser_constraint_logical_or_expression (parser);
if (check_for_bare_parameter_packs (expr))
expr = error_mark_node;
--processing_template_decl;
return expr;
}
-// Optionally parse a requires clause:
+/* Parse a expression after a requires clause.
+
+ constraint-expression:
+ 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_constraint_expression (cp_parser *parser)
+{
+ processing_constraint_expression_sentinel parsing_constraint;
+ ++processing_template_decl;
+ cp_expr expr = cp_parser_binary_expression (parser, false, true,
+ PREC_NOT_OPERATOR, NULL);
+ if (check_for_bare_parameter_packs (expr))
+ expr = error_mark_node;
+ --processing_template_decl;
+ expr.maybe_add_location_wrapper ();
+ return expr;
+}
+
+/* Optionally parse a requires clause:
+
+ requires-clause:
+ `requires` constraint-logical-or-expression.
+ [ConceptsTS]
+ `requires constraint-expression. */
+
static tree
cp_parser_requires_clause_opt (cp_parser *parser)
{
@@ -26920,17 +27261,21 @@ cp_parser_requires_clause_opt (cp_parser *parser)
&& tok->u.value == ridpointers[RID_REQUIRES])
{
error_at (cp_lexer_peek_token (parser->lexer)->location,
- "%<requires%> only available with %<-fconcepts%>");
+ "%<requires%> only available with "
+ "%<-std=c++2a%> or %<-fconcepts%>");
/* Parse and discard the requires-clause. */
cp_lexer_consume_token (parser->lexer);
- cp_parser_requires_clause (parser);
+ cp_parser_constraint_expression (parser);
}
return NULL_TREE;
}
cp_lexer_consume_token (parser->lexer);
- return cp_parser_requires_clause (parser);
-}
+ if (!flag_concepts_ts)
+ return cp_parser_requires_clause_expression (parser);
+ else
+ return cp_parser_constraint_expression (parser);
+}
/*---------------------------------------------------------------------------
Requires expressions
@@ -26940,6 +27285,7 @@ cp_parser_requires_clause_opt (cp_parser *parser)
requirement-expression:
'requires' requirement-parameter-list [opt] requirement-body */
+
static tree
cp_parser_requires_expression (cp_parser *parser)
{
@@ -26957,6 +27303,9 @@ cp_parser_requires_expression (cp_parser *parser)
return error_mark_node;
}
+ /* This is definitely a requires-expression. */
+ cp_parser_commit_to_tentative_parse (parser);
+
tree parms, reqs;
{
/* Local parameters are delared as variables within the scope
@@ -26997,13 +27346,15 @@ cp_parser_requires_expression (cp_parser *parser)
/* 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);
+ loc = make_location (loc, loc, parser->lexer);
+ return finish_requires_expr (loc, parms, reqs);
}
/* Parse a parameterized requirement.
requirement-parameter-list:
'(' parameter-declaration-clause ')' */
+
static tree
cp_parser_requirement_parameter_list (cp_parser *parser)
{
@@ -27031,7 +27382,7 @@ cp_parser_requirement_body (cp_parser *parser)
if (!braces.require_open (parser))
return error_mark_node;
- tree reqs = cp_parser_requirement_list (parser);
+ tree reqs = cp_parser_requirement_seq (parser);
if (!braces.require_close (parser))
return error_mark_node;
@@ -27039,34 +27390,28 @@ cp_parser_requirement_body (cp_parser *parser)
return reqs;
}
-/* Parse a list of requirements.
+/* Parse a sequence of requirements.
- requirement-list:
+ requirement-seq:
requirement
- requirement-list ';' requirement[opt] */
+ requirement-seq requirement */
+
static tree
-cp_parser_requirement_list (cp_parser *parser)
+cp_parser_requirement_seq (cp_parser *parser)
{
tree result = NULL_TREE;
- while (true)
+ do
{
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);
+ if (req != error_mark_node)
+ result = tree_cons (NULL_TREE, req, result);
+ } while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE));
- /* Stop processing at the end of the list. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
- break;
- }
+ /* If there are no valid requirements, this is not a valid expression. */
+ if (!result)
+ return error_mark_node;
- /* Reverse the order of requirements so they are analyzed in
- declaration order. */
+ /* Reverse the order of requirements so they are analyzed in order. */
return nreverse (result);
}
@@ -27077,6 +27422,7 @@ cp_parser_requirement_list (cp_parser *parser)
compound-requirement
type-requirement
nested-requirement */
+
static tree
cp_parser_requirement (cp_parser *parser)
{
@@ -27094,17 +27440,26 @@ cp_parser_requirement (cp_parser *parser)
simple-requirement:
expression ';' */
+
static tree
cp_parser_simple_requirement (cp_parser *parser)
{
- tree expr = cp_parser_expression (parser, NULL, false, false);
+ location_t start = cp_lexer_peek_token (parser->lexer)->location;
+ cp_expr expr = cp_parser_expression (parser, NULL, false, false);
+ if (expr == error_mark_node)
+ cp_parser_skip_to_end_of_statement (parser);
+
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
if (!expr || expr == error_mark_node)
return error_mark_node;
- if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
- return error_mark_node;
+ /* Sometimes we don't get locations, so use the cached token location
+ as a reasonable approximation. */
+ if (expr.get_location() == UNKNOWN_LOCATION)
+ expr.set_location (start);
- return finish_simple_requirement (expr);
+ return finish_simple_requirement (expr.get_location (), expr);
}
/* Parse a type requirement
@@ -27115,16 +27470,18 @@ cp_parser_simple_requirement (cp_parser *parser)
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);
+ cp_token *start_tok = cp_lexer_consume_token (parser->lexer);
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
// 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_global_scope_opt (parser, /*current_scope_valid_p=*/false);
cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/true,
/*check_dependency_p=*/false,
@@ -27156,18 +27513,20 @@ cp_parser_type_requirement (cp_parser *parser)
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;
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
if (type == error_mark_node)
return error_mark_node;
- return finish_type_requirement (type);
+ loc = make_location (loc, start_tok->location, parser->lexer);
+ return finish_type_requirement (loc, type);
}
/* Parse a compound requirement
compound-requirement:
'{' expression '}' 'noexcept' [opt] trailing-return-type [opt] ';' */
+
static tree
cp_parser_compound_requirement (cp_parser *parser)
{
@@ -27176,12 +27535,26 @@ cp_parser_compound_requirement (cp_parser *parser)
if (!braces.require_open (parser))
return error_mark_node;
+ cp_token *expr_token = cp_lexer_peek_token (parser->lexer);
+
tree expr = cp_parser_expression (parser, NULL, false, false);
- if (!expr || expr == error_mark_node)
- return error_mark_node;
+ if (expr == error_mark_node)
+ cp_parser_skip_to_closing_brace (parser);
if (!braces.require_close (parser))
- return error_mark_node;
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return error_mark_node;
+ }
+
+ /* If the expression was invalid, skip the remainder of the requirement. */
+ if (!expr || expr == error_mark_node)
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return error_mark_node;
+ }
/* Parse the optional noexcept. */
bool noexcept_p = false;
@@ -27196,29 +27569,69 @@ cp_parser_compound_requirement (cp_parser *parser)
if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
{
cp_lexer_consume_token (parser->lexer);
+ cp_token *tok = cp_lexer_peek_token (parser->lexer);
+
bool saved_result_type_constraint_p = parser->in_result_type_constraint_p;
parser->in_result_type_constraint_p = true;
+ /* C++2a allows either a type-id or a type-constraint. Parsing
+ a type-id will subsume the parsing for a type-constraint but
+ allow for more syntactic forms (e.g., const C<T>*). */
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;
+
+ location_t type_loc = make_location (tok->location, tok->location,
+ parser->lexer);
+
+ /* Check that we haven't written something like 'const C<T>*'. */
+ if (type_uses_auto (type))
+ {
+ if (!is_auto (type))
+ {
+ error_at (type_loc,
+ "result type is not a plain type-constraint");
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return error_mark_node;
+ }
+ }
+ else if (!flag_concepts_ts)
+ /* P1452R2 removed the trailing-return-type option. */
+ error_at (type_loc,
+ "return-type-requirement is not a type-constraint");
}
- return finish_compound_requirement (expr, type, noexcept_p);
+ location_t loc = make_location (expr_token->location,
+ braces.open_location (),
+ parser->lexer);
+
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ if (expr == error_mark_node || type == error_mark_node)
+ return error_mark_node;
+
+ return finish_compound_requirement (loc, 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);
+ gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES));
+ cp_token *tok = cp_lexer_consume_token (parser->lexer);
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ tree req = cp_parser_constraint_expression (parser);
+ if (req == error_mark_node)
+ cp_parser_skip_to_end_of_statement (parser);
+ loc = make_location (loc, tok->location, parser->lexer);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
if (req == error_mark_node)
return error_mark_node;
- return finish_nested_requirement (req);
+ return finish_nested_requirement (loc, req);
}
/* Support Functions */
@@ -28145,6 +28558,11 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser,
else if (cxx_dialect >= cxx11
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
decl = cp_parser_alias_declaration (parser);
+ else if (cxx_dialect >= cxx2a /* Implies flag_concept. */
+ && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)
+ && !cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_BOOL))
+ /* Allow 'concept bool' to be handled as per the TS. */
+ decl = cp_parser_concept_definition (parser);
else
{
/* There are no access checks when parsing a template, as we do not
@@ -28264,6 +28682,8 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p)
tree saved_object_scope = parser->object_scope;
tree saved_qualifying_scope = parser->qualifying_scope;
+ cp_token *start_token = cp_lexer_peek_token (parser->lexer);
+
/* Look for the optional `::' operator. */
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
@@ -28285,12 +28705,14 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p)
parser->object_scope = saved_object_scope;
parser->qualifying_scope = saved_qualifying_scope;
- if (concept_name == error_mark_node)
+ if (concept_name == error_mark_node
+ || (seen_error () && !concept_definition_p (tmpl_decl)))
cp_parser_simulate_error (parser);
/* Look for opening brace for introduction. */
matching_braces braces;
braces.require_open (parser);
+ location_t open_loc = input_location;
if (!cp_parser_parse_definitely (parser))
return false;
@@ -28321,15 +28743,26 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p)
}
/* Build and associate the constraint. */
- tree parms = finish_template_introduction (tmpl_decl, introduction_list);
+ location_t introduction_loc = make_location (open_loc,
+ start_token->location,
+ parser->lexer);
+ tree parms = finish_template_introduction (tmpl_decl,
+ introduction_list,
+ introduction_loc);
if (parms && parms != error_mark_node)
{
+ if (!flag_concepts_ts)
+ pedwarn (introduction_loc, 0, "template-introductions"
+ " are not part of C++20 concepts [-fconcepts-ts]");
+
cp_parser_template_declaration_after_parameters (parser, parms,
member_p);
return true;
}
- error_at (token->location, "no matching concept for template-introduction");
+ if (parms == NULL_TREE)
+ error_at (token->location, "no matching concept for template-introduction");
+
return true;
}
@@ -28397,8 +28830,8 @@ cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p)
if (flag_concepts)
{
tree reqs = get_shorthand_constraints (current_template_parms);
- if (tree r = cp_parser_requires_clause_opt (parser))
- reqs = conjoin_constraints (reqs, normalize_expression (r));
+ if (tree treqs = cp_parser_requires_clause_opt (parser))
+ reqs = combine_constraint_expressions (reqs, treqs);
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
@@ -29635,6 +30068,9 @@ cp_parser_required_error (cp_parser *parser,
case RT_THROW:
gmsgid = G_("expected %<throw%>");
break;
+ case RT_AUTO:
+ gmsgid = G_("expected %<auto%>");
+ break;
case RT_LABEL:
gmsgid = G_("expected %<__label__%>");
break;
@@ -41910,36 +42346,15 @@ make_generic_type_name ()
static tree
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.
-
- NOTE: We can generate implicit parameters when tentatively
- parsing a nested name specifier, only to reject that parse
- later. However, matching the same template-id as part of a
- direct-declarator should generate an identical template
- parameter, so this rule will merge them. */
- if (parser->implicit_template_scope && constr)
- {
- tree t = parser->implicit_template_parms;
- while (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);
- }
+ /* A requires-clause is not a function and cannot have placeholders. */
+ if (current_binding_level->kind == sk_block)
+ {
+ error ("placeholder type not allowed in this context");
+ return error_mark_node;
}
+ gcc_assert (current_binding_level->kind == sk_function_parms);
+
/* 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
@@ -42050,18 +42465,9 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
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;
- }
+ /* Synthesize the type template parameter. */
+ gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL);
+ 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);
@@ -42073,6 +42479,13 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
/*non_type=*/non_type,
/*param_pack=*/false);
+ /* Mark the synthetic declaration "virtual". This is used when
+ comparing template-heads to determine if whether an abbreviated
+ function template is equivalent to an explicit template.
+
+ Note that DECL_ARTIFICIAL is used elsewhere for template parameters. */
+ DECL_VIRTUAL_P (TREE_VALUE (new_parm)) = true;
+
// Chain the new parameter to the list of implicit parameters.
if (parser->implicit_template_parms)
parser->implicit_template_parms
@@ -42111,7 +42524,7 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
if (tree req = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
{
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
- reqs = conjoin_constraints (reqs, req);
+ reqs = combine_constraint_expressions (reqs, req);
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}