diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index c09d212..664d8f0 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -238,13 +238,43 @@ deduce_constrained_parameter (tree expr, tree& check, tree& proto) gcc_unreachable (); } +// Given a call expression or template-id expression to a concept, EXPR, +// deduce the concept being checked and return the template parameters. +// Returns NULL_TREE if deduction fails. +static tree +deduce_concept_introduction (tree expr) +{ + if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) + { + // Get the parameters from the template expression. + tree decl = TREE_OPERAND (expr, 0); + tree args = TREE_OPERAND (expr, 1); + tree var = DECL_TEMPLATE_RESULT (decl); + tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (decl)); + + parms = coerce_template_parms (parms, args, var); + // Check that we are returned a proper set of parameters. + if (parms == error_mark_node) + return NULL_TREE; + return parms; + } + else if (TREE_CODE (expr) == CALL_EXPR) + { + // Resolve the constraint check and return parameters. + if (tree info = resolve_constraint_check (expr)) + return TREE_PURPOSE (info); + return NULL_TREE; + } + else + gcc_unreachable (); +} + // -------------------------------------------------------------------------- // -// Requirement Reduction +// Normalization // -// Reduces a template requirement to a logical formula written in terms of +// Normalize a template requirement to a logical formula written in terms of // atomic propositions, returing the new expression. If the expression cannot -// be reduced, a NULL_TREE is returned, indicating failure to reduce the -// original requirment. +// be normalized, a NULL_TREE is returned. namespace { @@ -1080,7 +1110,8 @@ build_call_check (tree id) // arguments to the target are given by ARG and REST. If the target is // a function (overload set or baselink reffering to an overload set), // then ths builds the call expression TARGET(). If REST is -// NULL_TREE, then the resulting check is just TARGET(). +// NULL_TREE, then the resulting check is just TARGET(). If ARG is +// NULL_TREE, then the resulting check is TARGET(). tree build_concept_check (tree target, tree arg, tree rest) { @@ -1089,19 +1120,26 @@ build_concept_check (tree target, tree arg, tree rest) // Build a template-id that acts as the call target using TARGET as // the template and ARG as the only explicit argument. int n = rest ? TREE_VEC_LENGTH (rest) : 0; - tree targs = make_tree_vec (n + 1); - TREE_VEC_ELT (targs, 0) = arg; - if (rest) - for (int i = 0; i < n; ++i) - TREE_VEC_ELT (targs, i + 1) = TREE_VEC_ELT (rest, i); - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, n + 1); - if (variable_template_p (target)) - return lookup_template_variable (target, targs); + tree targs; + if (arg) + { + targs = make_tree_vec (n + 1); + TREE_VEC_ELT (targs, 0) = arg; + if (rest) + for (int i = 0; i < n; ++i) + TREE_VEC_ELT (targs, i + 1) = TREE_VEC_ELT (rest, i); + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, n + 1); + } else { - tree id = lookup_template_function (target, targs); - return build_call_check (id); + gcc_assert (rest != NULL_TREE); + targs = rest; } + + if (variable_template_p (target)) + return lookup_template_variable (target, targs); + else + return build_call_check (lookup_template_function (target, targs)); } // Returns a TYPE_DECL that contains sufficient information to build @@ -1185,6 +1223,125 @@ finish_shorthand_constraint (tree decl, tree constr) return check; } +// Returns and chains a new parmater for PARAMETER_LIST which will conform to the +// prototype given by SRC_PARM. The new parameter will have it's identifier +// and location set according to IDENT and PARM_LOC respectively. +static tree +process_introduction_parm (tree parameter_list, tree src_parm) +{ + // If we have a pack, we should have a single pack argument which is the + // placeholder we want to look at. + bool is_parameter_pack = ARGUMENT_PACK_P (src_parm); + if (is_parameter_pack) + src_parm = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (src_parm), 0); + + // At this point we should have a INTRODUCED_PARM_DECL, but we want to grab + // the associated decl from it. Also grab the stored identifier and location + // that should be chained to it in a PARM_DECL. + gcc_assert (TREE_CODE (src_parm) == INTRODUCED_PARM_DECL); + + tree ident = DECL_NAME (src_parm); + location_t parm_loc = DECL_SOURCE_LOCATION (src_parm); + + // If we expect a pack and the deduced template is not a pack, or if the + // template is using a pack and we didn't declare a pack, throw an error. + if (is_parameter_pack != INTRODUCED_PACK_P (src_parm)) + { + error_at (parm_loc, "can not match pack for introduced parameter"); + tree err_parm = build_tree_list (error_mark_node, error_mark_node); + return chainon (parameter_list, err_parm); + } + + src_parm = TREE_TYPE (src_parm); + + tree parm; + bool is_non_type; + if (TREE_CODE (src_parm) == TYPE_DECL) + { + is_non_type = false; + parm = finish_template_type_parm (class_type_node, ident); + } + else if (TREE_CODE (src_parm) == TEMPLATE_DECL) + { + is_non_type = false; + current_template_parms = DECL_TEMPLATE_PARMS (src_parm); + parm = finish_template_template_parm (class_type_node, ident); + } + else + { + is_non_type = true; + + // Since we don't have a declarator, so we can copy the source + // parameter and change the name and eventually the location. + parm = copy_decl (src_parm); + DECL_NAME (parm) = ident; + } + + // Wrap in a TREE_LIST for process_template_parm. Introductions do not + // retain the defaults from the source template. + parm = build_tree_list (NULL_TREE, parm); + + return process_template_parm (parameter_list, parm_loc, parm, + is_non_type, is_parameter_pack); +} + +// Associates a constraint check to the current template based on the +// introduction parameters. INTRO_LIST should be a TREE_VEC of +// INTRODUCED_PARM_DECLs containing a chained PARM_DECL which contains the +// identifier as well as the source location. TMPL_DECL is the decl for the +// concept being used. If we take some concept, C, this will form a check in +// the form of C filling in any extra arguments needed by the +// defaults deduced. +// +// Returns the template parameters as given from end_template_parm_list or +// NULL_TREE if the process fails. +tree +finish_concept_introduction (tree tmpl_decl, tree intro_list) +{ + // Deduce the concept check. + tree expr = build_concept_check (tmpl_decl, NULL_TREE, intro_list); + if (expr == error_mark_node) + return NULL_TREE; + + tree parms = deduce_concept_introduction (expr); + if (!parms) + return NULL_TREE; + + // Build template parameter scope for introduction. + tree parm_list = NULL_TREE; + begin_template_parm_list (); + + // Produce a parameter for each introduction argument according to the + // deduced form. + int nargs = MIN (TREE_VEC_LENGTH (parms), TREE_VEC_LENGTH (intro_list)); + for (int n = 0; n < nargs; ++n) + parm_list = process_introduction_parm (parm_list, TREE_VEC_ELT (parms, n)); + + parm_list = end_template_parm_list (parm_list); + + // Build a concept check for our constraint. + tree check_args = make_tree_vec (TREE_VEC_LENGTH (parms)); + + // Start with introduction parameters. + int n = 0; + for (; n < TREE_VEC_LENGTH (parm_list); ++n) + { + tree parm = TREE_VEC_ELT (parm_list, n); + TREE_VEC_ELT (check_args, n) = template_parm_to_arg (parm); + } + // If the template expects more parameters we should be able to use the + // defaults from our deduced form. + for (; n < TREE_VEC_LENGTH (parms); ++n) + TREE_VEC_ELT (check_args, n) = TREE_VEC_ELT (parms, n); + + // Associate the constraint. + tree reqs = build_concept_check (tmpl_decl, NULL_TREE, check_args); + current_template_reqs = save_leading_constraints (reqs); + TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = current_template_reqs; + + return parm_list; +} + // -------------------------------------------------------------------------- // // Substitution Rules // diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index c889332..ffa1c2e 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -253,6 +253,7 @@ cp_common_init_ts (void) { MARK_TS_DECL_NON_COMMON (USING_DECL); MARK_TS_DECL_COMMON (TEMPLATE_DECL); + MARK_TS_DECL_COMMON (INTRODUCED_PARM_DECL); MARK_TS_COMMON (TEMPLATE_TEMPLATE_PARM); MARK_TS_COMMON (TEMPLATE_TYPE_PARM); diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index ef95815..6aacf85 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -500,6 +500,10 @@ DEFTREECODE (VALIDTYPE_EXPR, "validtype_expr", tcc_expression, 1) can be evaluated at compile time. */ DEFTREECODE (CONSTEXPR_EXPR, "contexpr_expr", tcc_expression, 1) +/* Alternative PLACEHOLDER_EXPR which is used for concept introductions. This + is a temporary type which is used to produce normal template parameters. */ +DEFTREECODE (INTRODUCED_PARM_DECL, "introduced_parm_decl", tcc_declaration, 0) + /* Local variables: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a362fb0..05a48ff 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -88,6 +88,7 @@ c-common.h, not after. PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION) TINFO_RECHECK_ACCESS_P (in TEMPLATE_INFO) SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR) + INTRODUCED_PACK_P (in INTRODUCED_PARM_DECL) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -3063,6 +3064,14 @@ extern void decl_shadowed_for_var_insert (tree, tree); /* True iff this pack expansion is within a function context. */ #define PACK_EXPANSION_LOCAL_P(NODE) TREE_LANG_FLAG_0 (NODE) +/* True iff the introudced parm matches a template parameter pack. */ +#define INTRODUCED_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE) + +/* True iff this is a introduction representing a pack in an introduction + list. */ +#define IS_INTRODUCED_PACK(NODE) \ + (TREE_CODE (NODE) == INTRODUCED_PARM_DECL && INTRODUCED_PACK_P (NODE)) + /* Determine if this is an argument pack. */ #define ARGUMENT_PACK_P(NODE) \ (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK \ @@ -6436,6 +6445,7 @@ extern tree build_constrained_parameter (tree, tree, tree = NULL_TREE); extern bool deduce_constrained_parameter (tree, tree&, tree&); extern tree resolve_constraint_check (tree); +extern tree finish_concept_introduction (tree, tree); extern tree finish_template_constraints (tree); extern tree save_leading_constraints (tree); extern tree save_trailing_constraints (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a31513d..69ebbc6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11267,8 +11267,15 @@ cp_parser_declaration (cp_parser* parser) /* We must have either a block declaration or a function definition. */ else - /* Try to parse a block-declaration, or a function-definition. */ - cp_parser_block_declaration (parser, /*statement_p=*/false); + { + /* At this point we may have a concept introduction. */ + cp_parser_parse_tentatively (parser); + cp_parser_template_declaration (parser, /*member_p=*/false); + + if (!cp_parser_parse_definitely (parser)) + /* Try to parse a block-declaration, or a function-definition. */ + cp_parser_block_declaration (parser, /*statement_p=*/false); + } /* Free any declarators allocated. */ obstack_free (&declarator_obstack, p); @@ -13207,6 +13214,63 @@ 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 INTRODUCED_PARM_DECLs. If the parameter is a pack + then the introduced parm will have INTORDUCED_PACK_P set. In addition, the + INTRODUCED_PARM_DECL will also have DECL_NAME set and token location in + DECL_SOURCE_LOCATION. */ + +static tree +cp_parser_introduction_list (cp_parser *parser) +{ + tree introduction_list = NULL_TREE; + + 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 (INTRODUCED_PARM_DECL); + DECL_SOURCE_LOCATION (parm) = cp_lexer_peek_token (parser->lexer)->location; + DECL_NAME (parm) = cp_parser_identifier (parser); + INTRODUCED_PACK_P (parm) = is_pack; + introduction_list = chainon (introduction_list, + build_tree_list (NULL_TREE, 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 TREE_LIST into a TREE_VEC, similar to what is done in + // end_template_parm_list. + tree introduction_vec = make_tree_vec (list_length (introduction_list)); + int n = 0; + while (introduction_list != NULL_TREE) + { + tree next = TREE_CHAIN (introduction_list); + TREE_VEC_ELT (introduction_vec, n) = TREE_VALUE (introduction_list); + TREE_CHAIN (introduction_list) = NULL_TREE; + + introduction_list = next; + ++n; + } + + return introduction_vec; +} + // Given a declarator, get the declarator-id part, or NULL_TREE if this // is an abstract declarator. static inline cp_declarator* @@ -21108,6 +21172,13 @@ cp_parser_member_declaration (cp_parser* parser) return; } + /* Tentatively parse for a template since we may have a concept + introduction. */ + cp_parser_parse_tentatively (parser); + cp_parser_template_declaration (parser, /*member_p=*/true); + if (cp_parser_parse_definitely (parser)) + return; + parser->colon_corrects_to_scope_p = false; if (cp_parser_using_declaration (parser, /*access_declaration=*/true)) @@ -24176,6 +24247,69 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, return fn; } +/* Parse a concept introduction header for a template-declaration. If + successful, returns the template parameters. Otherwise returns + error_mark_node. */ + +static tree +cp_parser_template_introduction (cp_parser* parser) +{ + // Look for the optional `::' operator. + cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/true); + // 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); + if (concept_name == error_mark_node) + return error_mark_node; + + // Look for opening brace for introduction + if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + return error_mark_node; + + // This must be a concept introduction. + if (cp_parser_parsing_tentatively (parser)) + cp_parser_commit_to_tentative_parse (parser); + + // 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 ("an introduction-list shall not be empty"); + return error_mark_node; + } + + // Look for closing brace for introduction + if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE)) + return error_mark_node; + + // 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); + if (tmpl_decl == error_mark_node) + { + cp_parser_name_lookup_error (parser, concept_name, tmpl_decl, NLE_NULL, + token->location); + return error_mark_node; + } + + // Build and associate the constraint. + if (tree p = finish_concept_introduction (tmpl_decl, introduction_list)) + return p; + + error_at (token->location, "no matching concept for introduction-list"); + return error_mark_node; +} + /* 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. */ @@ -24189,93 +24323,131 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) bool friend_p = false; bool need_lang_pop; cp_token *token; + tree saved_template_reqs; /* 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) + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) { - /* 14.5.2.2 [temp.mem] + if (cp_parser_parsing_tentatively (parser)) + cp_parser_commit_to_tentative_parse (parser); + cp_lexer_consume_token (parser->lexer); - 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] + /* Look for 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 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; + 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] - /* 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); + 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; - // Save the current template requirements. - tree saved_template_reqs = release (current_template_reqs); + /* 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); + + // Save the current template requirements. + saved_template_reqs = release (current_template_reqs); + + /* 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); + } + + /* 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 (); + + /* 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, r); + current_template_reqs = save_leading_constraints (reqs); - /* 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)) + // Attach the constraints to the template parameter list. + // This is used to pass template requirements to out-of-class + // member definitions. + TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) + = current_template_reqs; + } + } + else if(flag_concepts) { - cp_parser_error (parser, "invalid explicit specialization"); - begin_specialization (); - parameter_list = NULL_TREE; + need_lang_pop = false; + checks = NULL; + saved_template_reqs = release (current_template_reqs); + push_deferring_access_checks (dk_deferred); + + // Scope may be changed by a nested-name-specifier. + tree saved_scope = parser->scope; + tree saved_qualifying_scope = parser->qualifying_scope; + tree saved_object_scope = parser->object_scope; + + parameter_list = cp_parser_template_introduction (parser); + if (parameter_list == error_mark_node) + { + // Restore template requirements before returning. + current_template_reqs = saved_template_reqs; + return; + } + + parser->scope = saved_scope; + parser->qualifying_scope = saved_qualifying_scope; + parser->object_scope = saved_object_scope; } else { - /* Parse the template parameters. */ - parameter_list = cp_parser_template_parameter_list (parser); + if (!cp_parser_simulate_error (parser)) + error ("expected template header"); + return; } - /* 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 (); - - /* 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; - // 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, r); - current_template_reqs = save_leading_constraints (reqs); - - // Attach the constraints to the template parameter list. - // This is used to pass template requirements to out-of-class - // member definitions. - TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) - = current_template_reqs; - } - - /* 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); + /* Look for another template. We need to start a tentative parse here as + the next header could be a concept introduction. */ + cp_parser_parse_tentatively (parser); + cp_parser_template_declaration_after_export (parser, member_p); + if (cp_parser_parse_definitely (parser)) + /* Found another template. */; else if (cxx_dialect >= cxx11 && cp_lexer_next_token_is_keyword (parser->lexer, RID_USING)) decl = cp_parser_alias_declaration (parser); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 553b138..00ddbb6 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6769,7 +6769,8 @@ convert_template_argument (tree parm, int is_type, requires_type, is_tmpl_type, requires_tmpl_type; // Trivially convert placeholders. - if (TREE_CODE (arg) == PLACEHOLDER_EXPR) + if (TREE_CODE (arg) == PLACEHOLDER_EXPR + || TREE_CODE (arg) == INTRODUCED_PARM_DECL) return convert_placeholder_argument (parm, arg); if (TREE_CODE (arg) == TREE_LIST @@ -7086,6 +7087,15 @@ coerce_template_parameter_pack (tree parms, packed_args = make_tree_vec (TREE_VEC_LENGTH (packed_parms)); } + /* Check if we have a placeholder pack, which indicates we're in the context + of a introduction list. In that case we want to simply match this pack to + the single placeholder. */ + else if (arg_idx < nargs + && IS_INTRODUCED_PACK (TREE_VEC_ELT (inner_args, arg_idx))) + { + nargs = arg_idx + 1; + packed_args = make_tree_vec (1); + } else packed_args = make_tree_vec (nargs - arg_idx); @@ -21590,7 +21600,8 @@ type_dependent_expression_p (tree expression) /* An unresolved name is always dependent. */ if (identifier_p (expression) || TREE_CODE (expression) == USING_DECL - || TREE_CODE (expression) == PLACEHOLDER_EXPR) + || TREE_CODE (expression) == PLACEHOLDER_EXPR + || TREE_CODE (expression) == INTRODUCED_PARM_DECL) return true; /* Some expression forms are never type-dependent. */ diff --git a/gcc/testsuite/g++.dg/concepts/introduction1.C b/gcc/testsuite/g++.dg/concepts/introduction1.C new file mode 100644 index 0000000..1b5f5d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/introduction1.C @@ -0,0 +1,38 @@ +// { dg-options "-std=c++1z" } + +template + concept bool C = __is_class(T); + +C{T} void f1(); + +struct S1 +{ + C{T} void f2(); + C{T} static void f3(); +}; + +int main() +{ + S1 s; + + f1(); + s.f2(); + S1::f3(); + + return 0; +} + +template + void f1() requires C + { + } + +template + void S1::f2() requires C + { + } + +template + void S1::f3() requires C + { + } diff --git a/gcc/testsuite/g++.dg/concepts/introduction2.C b/gcc/testsuite/g++.dg/concepts/introduction2.C new file mode 100644 index 0000000..5cdcae0 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/introduction2.C @@ -0,0 +1,28 @@ +// { dg-do run } +// { dg-options "-std=c++1z" } + +#include + +template + concept bool C() { return __is_class(T); } + +template + concept bool P() { return true; } + +C{A} struct S1 +{ + P{B} int f1(); +}; + +struct S2 {}; + +int main() +{ + S1 s; + + assert(s.f1<10>() == sizeof(S2) + 10); + return 0; +} + +C{A} P{B} int S1::f1() { return B + sizeof(A); } + diff --git a/gcc/testsuite/g++.dg/concepts/introduction3.C b/gcc/testsuite/g++.dg/concepts/introduction3.C new file mode 100644 index 0000000..d4486a0 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/introduction3.C @@ -0,0 +1,17 @@ +// { dg-options "-std=c++1z" } + +template + concept bool C1 = true; + +template + concept bool C2 = true; + +C1{...A} void f1() {}; +C2{...A} void f2() {}; + +int main() +{ + f1(); + f2<1, 2, 3>(); + return 0; +} diff --git a/gcc/testsuite/g++.dg/concepts/introduction4.C b/gcc/testsuite/g++.dg/concepts/introduction4.C new file mode 100644 index 0000000..7b32148 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/introduction4.C @@ -0,0 +1,32 @@ +// { dg-options "-std=c++1z" } + +template + concept bool C1 = true; + +template + concept bool C2 = true; + +template + concept bool C3 = __is_class(T); + +template + concept bool C4() { return true; } +template + concept bool C4() { return true; } + +template + concept bool C5() { return __is_class(U); } + +C1{...A, B} void f1() {}; // { dg-error "no matching concept" } +C1{A} void f2() {} // { dg-error "match pack" } +C2{A, B} void f3() {}; // { dg-error "match pack" } +C3{...A} void f4() {}; // { dg-error "match pack" } +C4{A} void f5() {}; // { dg-error "no matching concept" } +C5{A, B} void f6() {}; + +int main() +{ + // Defaults should not transfer + f6(); // { dg-error "no matching" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/concepts/introduction5.C b/gcc/testsuite/g++.dg/concepts/introduction5.C new file mode 100644 index 0000000..309928e --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/introduction5.C @@ -0,0 +1,15 @@ +// { dg-options "-std=c++1z" } + +template + concept bool C() + { + return sizeof(U) == sizeof(int); + } + +C{A} void f1() {} + +int main() +{ + f1(); + return 0; +}