Implement P0091R2, Template argument deduction for class templates.

* parser.c (cp_parser_simple_type_specifier): Parse class placeholder.
Use the location of the beginning of the type-specifier.
(cp_parser_init_declarator): Parse deduction guide.
(cp_parser_diagnose_invalid_type_name): Mention class deduction.
(cp_parser_type_id_1): Don't accept class placeholder as template arg.
* cp-tree.h (CLASS_PLACEHOLDER_TEMPLATE): New.
* decl.c (grokdeclarator): Check for uninitialized auto here.
(start_decl_1): Not here.
(cp_finish_decl): Or here.  Don't collapse a list when doing
class deduction.
(grokfndecl): Check deduction guide scope and body.
* error.c (dump_decl, dump_function_decl, dump_function_name):
Handle deduction guides.
* pt.c (make_template_placeholder, do_class_deduction): New.
(build_deduction_guide, rewrite_template_parm): New.
(dguide_name, dguide_name_p, deduction_guide_p): New.
(do_auto_deduction): Call do_class_deduction.
(splice_late_return_type, is_auto): Handle class placeholders.
(template_parms_level_to_args): Split from template_parms_to_args.
(tsubst_template_parms_level): Split from tsubst_template_parms.
* typeck2.c (build_functional_cast): Handle class placeholder.

From-SVN: r240756
This commit is contained in:
Jason Merrill 2016-10-04 16:42:58 -04:00 committed by Jason Merrill
parent 8ff04ff92d
commit 76b294d48d
27 changed files with 792 additions and 67 deletions

View File

@ -1,3 +1,28 @@
2016-10-04 Jason Merrill <jason@redhat.com>
Implement P0091R2, Template argument deduction for class templates.
* parser.c (cp_parser_simple_type_specifier): Parse class placeholder.
Use the location of the beginning of the type-specifier.
(cp_parser_init_declarator): Parse deduction guide.
(cp_parser_diagnose_invalid_type_name): Mention class deduction.
(cp_parser_type_id_1): Don't accept class placeholder as template arg.
* cp-tree.h (CLASS_PLACEHOLDER_TEMPLATE): New.
* decl.c (grokdeclarator): Check for uninitialized auto here.
(start_decl_1): Not here.
(cp_finish_decl): Or here. Don't collapse a list when doing
class deduction.
(grokfndecl): Check deduction guide scope and body.
* error.c (dump_decl, dump_function_decl, dump_function_name):
Handle deduction guides.
* pt.c (make_template_placeholder, do_class_deduction): New.
(build_deduction_guide, rewrite_template_parm): New.
(dguide_name, dguide_name_p, deduction_guide_p): New.
(do_auto_deduction): Call do_class_deduction.
(splice_late_return_type, is_auto): Handle class placeholders.
(template_parms_level_to_args): Split from template_parms_to_args.
(tsubst_template_parms_level): Split from tsubst_template_parms.
* typeck2.c (build_functional_cast): Handle class placeholder.
2016-10-04 Martin Sebor <msebor@redhat.com> 2016-10-04 Martin Sebor <msebor@redhat.com>
PR c++/77804 PR c++/77804

View File

@ -1199,6 +1199,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
#define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER] #define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER]
/* The name of the std namespace. */ /* The name of the std namespace. */
#define std_identifier cp_global_trees[CPTI_STD_IDENTIFIER] #define std_identifier cp_global_trees[CPTI_STD_IDENTIFIER]
/* The name of a C++17 deduction guide. */
#define lang_name_c cp_global_trees[CPTI_LANG_NAME_C] #define lang_name_c cp_global_trees[CPTI_LANG_NAME_C]
#define lang_name_cplusplus cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS] #define lang_name_cplusplus cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
@ -5104,6 +5105,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
#define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \ #define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \
(TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE))) (TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE)))
/* For a C++17 class deduction placeholder, the template it represents. */
#define CLASS_PLACEHOLDER_TEMPLATE(NODE) \
(DECL_INITIAL (TYPE_NAME (TEMPLATE_TYPE_PARM_CHECK (NODE))))
/* Contexts in which auto deduction occurs. These flags are /* Contexts in which auto deduction occurs. These flags are
used to control diagnostics in do_auto_deduction. */ used to control diagnostics in do_auto_deduction. */
@ -6027,6 +6032,7 @@ extern int num_template_headers_for_class (tree);
extern void check_template_variable (tree); extern void check_template_variable (tree);
extern tree make_auto (void); extern tree make_auto (void);
extern tree make_decltype_auto (void); extern tree make_decltype_auto (void);
extern tree make_template_placeholder (tree);
extern tree do_auto_deduction (tree, tree, tree); extern tree do_auto_deduction (tree, tree, tree);
extern tree do_auto_deduction (tree, tree, tree, extern tree do_auto_deduction (tree, tree, tree,
tsubst_flags_t, tsubst_flags_t,
@ -6158,6 +6164,9 @@ extern void register_local_specialization (tree, tree);
extern tree retrieve_local_specialization (tree); extern tree retrieve_local_specialization (tree);
extern tree extract_fnparm_pack (tree, tree *); extern tree extract_fnparm_pack (tree, tree *);
extern tree template_parm_to_arg (tree); extern tree template_parm_to_arg (tree);
extern tree dguide_name (tree);
extern bool dguide_name_p (tree);
extern bool deduction_guide_p (tree);
/* in repo.c */ /* in repo.c */
extern void init_repo (void); extern void init_repo (void);

View File

@ -5140,7 +5140,7 @@ start_decl_1 (tree decl, bool initialized)
else if (aggregate_definition_p && !complete_p) else if (aggregate_definition_p && !complete_p)
{ {
if (type_uses_auto (type)) if (type_uses_auto (type))
error ("declaration of %q#D has no initializer", decl); gcc_unreachable ();
else else
error ("aggregate %q#D has incomplete type and cannot be defined", error ("aggregate %q#D has incomplete type and cannot be defined",
decl); decl);
@ -6695,12 +6695,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
return; return;
} }
error ("declaration of %q#D has no initializer", decl); gcc_unreachable ();
TREE_TYPE (decl) = error_mark_node;
return;
} }
d_init = init; d_init = init;
if (TREE_CODE (d_init) == TREE_LIST) if (TREE_CODE (d_init) == TREE_LIST
&& !CLASS_PLACEHOLDER_TEMPLATE (auto_node))
d_init = build_x_compound_expr_from_list (d_init, ELK_INIT, d_init = build_x_compound_expr_from_list (d_init, ELK_INIT,
tf_warning_or_error); tf_warning_or_error);
d_init = resolve_nondeduced_context (d_init, tf_warning_or_error); d_init = resolve_nondeduced_context (d_init, tf_warning_or_error);
@ -8182,7 +8181,27 @@ grokfndecl (tree ctype,
} }
} }
if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)) if (deduction_guide_p (decl))
{
if (!DECL_NAMESPACE_SCOPE_P (decl))
{
error_at (location, "deduction guide %qD must be declared at "
"namespace scope", decl);
return NULL_TREE;
}
tree type = TREE_TYPE (DECL_NAME (decl));
if (CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type))
{
error_at (location, "deduction guide %qD must be declared in the "
"same scope as %qT", decl, type);
inform (location_of (type), " declared here");
return NULL_TREE;
}
if (funcdef_flag)
error_at (location,
"deduction guide %qD must not have a function body", decl);
}
else if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))
&& !grok_op_properties (decl, /*complain=*/true)) && !grok_op_properties (decl, /*complain=*/true))
return NULL_TREE; return NULL_TREE;
else if (UDLIT_OPER_P (DECL_NAME (decl))) else if (UDLIT_OPER_P (DECL_NAME (decl)))
@ -11063,12 +11082,19 @@ grokdeclarator (const cp_declarator *declarator,
} }
else if (decl_context == FIELD) else if (decl_context == FIELD)
{ {
if (!staticp && !friendp && TREE_CODE (type) != METHOD_TYPE if (!staticp && !friendp && TREE_CODE (type) != METHOD_TYPE)
&& type_uses_auto (type)) if (tree auto_node = type_uses_auto (type))
{ {
error ("non-static data member declared %<auto%>"); location_t loc = declspecs->locations[ds_type_spec];
type = error_mark_node; if (CLASS_PLACEHOLDER_TEMPLATE (auto_node))
} error_at (loc, "invalid use of template-name %qE without an "
"argument list",
CLASS_PLACEHOLDER_TEMPLATE (auto_node));
else
error_at (loc, "non-static data member declared with "
"placeholder %qT", auto_node);
type = error_mark_node;
}
/* The C99 flexible array extension. */ /* The C99 flexible array extension. */
if (!staticp && TREE_CODE (type) == ARRAY_TYPE if (!staticp && TREE_CODE (type) == ARRAY_TYPE
@ -11543,6 +11569,22 @@ grokdeclarator (const cp_declarator *declarator,
} }
} }
if (VAR_P (decl) && !initialized)
if (tree auto_node = type_uses_auto (type))
{
location_t loc = declspecs->locations[ds_type_spec];
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
{
error_at (loc, "invalid use of template-name %qE without an "
"argument list", tmpl);
inform (loc, "class template argument deduction "
"requires an initializer");
}
else
error_at (loc, "declaration of %q#D has no initializer", decl);
TREE_TYPE (decl) = error_mark_node;
}
if (storage_class == sc_extern && initialized && !funcdef_flag) if (storage_class == sc_extern && initialized && !funcdef_flag)
{ {
if (toplevel_bindings_p ()) if (toplevel_bindings_p ())

View File

@ -1159,6 +1159,9 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
dump_type (pp, TREE_TYPE (t), flags); dump_type (pp, TREE_TYPE (t), flags);
break; break;
} }
else if (dguide_name_p (t))
dump_decl (pp, CLASSTYPE_TI_TEMPLATE (TREE_TYPE (t)),
TFF_PLAIN_IDENTIFIER);
else else
pp_cxx_tree_identifier (pp, t); pp_cxx_tree_identifier (pp, t);
break; break;
@ -1552,8 +1555,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
/* Print the return type? */ /* Print the return type? */
if (show_return) if (show_return)
show_return = !DECL_CONV_FN_P (t) && !DECL_CONSTRUCTOR_P (t) show_return = (!DECL_CONV_FN_P (t) && !DECL_CONSTRUCTOR_P (t)
&& !DECL_DESTRUCTOR_P (t); && !DECL_DESTRUCTOR_P (t) && !deduction_guide_p (t));
if (show_return) if (show_return)
{ {
tree ret = fndecl_declared_return_type (t); tree ret = fndecl_declared_return_type (t);
@ -1598,6 +1601,11 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
if (show_return) if (show_return)
dump_type_suffix (pp, TREE_TYPE (fntype), flags); dump_type_suffix (pp, TREE_TYPE (fntype), flags);
else if (deduction_guide_p (t))
{
pp_cxx_ws_string (pp, "->");
dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags);
}
if (flag_concepts) if (flag_concepts)
if (tree ci = get_constraints (t)) if (tree ci = get_constraints (t))
@ -1767,10 +1775,6 @@ dump_function_name (cxx_pretty_printer *pp, tree t, int flags)
pp_cxx_ws_string (pp, "operator"); pp_cxx_ws_string (pp, "operator");
dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags); dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags);
} }
else if (name && IDENTIFIER_OPNAME_P (name))
pp_cxx_tree_identifier (pp, name);
else if (name && UDLIT_OPER_P (name))
pp_cxx_tree_identifier (pp, name);
else else
dump_decl (pp, name, flags); dump_decl (pp, name, flags);

View File

@ -3155,6 +3155,9 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
error_at (location, error_at (location,
"invalid use of template-name %qE without an argument list", "invalid use of template-name %qE without an argument list",
decl); decl);
if (DECL_CLASS_TEMPLATE_P (decl) && cxx_dialect < cxx1z)
inform (location, "class template argument deduction is only available "
"with -std=c++1z or -std=gnu++1z");
inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
} }
else if (TREE_CODE (id) == BIT_NOT_EXPR) else if (TREE_CODE (id) == BIT_NOT_EXPR)
@ -12224,6 +12227,9 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
linkage-specification linkage-specification
namespace-definition namespace-definition
C++17:
deduction-guide
GNU extension: GNU extension:
declaration: declaration:
@ -16150,7 +16156,7 @@ cp_parser_type_specifier (cp_parser* parser,
double double
void void
C++0x Extension: C++11 Extension:
simple-type-specifier: simple-type-specifier:
auto auto
@ -16159,6 +16165,10 @@ cp_parser_type_specifier (cp_parser* parser,
char32_t char32_t
__underlying_type ( type-id ) __underlying_type ( type-id )
C++17 extension:
nested-name-specifier(opt) template-name
GNU Extension: GNU Extension:
simple-type-specifier: simple-type-specifier:
@ -16429,9 +16439,11 @@ cp_parser_simple_type_specifier (cp_parser* parser,
/* Don't gobble tokens or issue error messages if this is an /* Don't gobble tokens or issue error messages if this is an
optional type-specifier. */ optional type-specifier. */
if (flags & CP_PARSER_FLAGS_OPTIONAL) if ((flags & CP_PARSER_FLAGS_OPTIONAL) || cxx_dialect >= cxx1z)
cp_parser_parse_tentatively (parser); cp_parser_parse_tentatively (parser);
token = cp_lexer_peek_token (parser->lexer);
/* Look for the optional `::' operator. */ /* Look for the optional `::' operator. */
global_p global_p
= (cp_parser_global_scope_opt (parser, = (cp_parser_global_scope_opt (parser,
@ -16445,7 +16457,6 @@ cp_parser_simple_type_specifier (cp_parser* parser,
/*type_p=*/false, /*type_p=*/false,
/*is_declaration=*/false) /*is_declaration=*/false)
!= NULL_TREE); != NULL_TREE);
token = cp_lexer_peek_token (parser->lexer);
/* If we have seen a nested-name-specifier, and the next token /* If we have seen a nested-name-specifier, and the next token
is `template', then we are using the template-id production. */ is `template', then we are using the template-id production. */
if (parser->scope if (parser->scope
@ -16476,9 +16487,50 @@ cp_parser_simple_type_specifier (cp_parser* parser,
&& identifier_p (DECL_NAME (type))) && identifier_p (DECL_NAME (type)))
maybe_note_name_used_in_class (DECL_NAME (type), type); maybe_note_name_used_in_class (DECL_NAME (type), type);
/* If it didn't work out, we don't have a TYPE. */ /* If it didn't work out, we don't have a TYPE. */
if ((flags & CP_PARSER_FLAGS_OPTIONAL) if (((flags & CP_PARSER_FLAGS_OPTIONAL) || cxx_dialect >= cxx1z)
&& !cp_parser_parse_definitely (parser)) && !cp_parser_parse_definitely (parser))
type = NULL_TREE; type = NULL_TREE;
if (!type && cxx_dialect >= cxx1z)
{
if (flags & CP_PARSER_FLAGS_OPTIONAL)
cp_parser_parse_tentatively (parser);
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/false,
/*check_dependency_p=*/true,
/*type_p=*/false,
/*is_declaration=*/false);
tree name = cp_parser_identifier (parser);
if (name && TREE_CODE (name) == IDENTIFIER_NODE
&& parser->scope != error_mark_node)
{
tree tmpl = cp_parser_lookup_name (parser, name,
none_type,
/*is_template=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true,
/*ambiguous_decls=*/NULL,
token->location);
if (tmpl && tmpl != error_mark_node
&& DECL_CLASS_TEMPLATE_P (tmpl))
type = make_template_placeholder (tmpl);
else
{
type = error_mark_node;
if (!cp_parser_simulate_error (parser))
cp_parser_name_lookup_error (parser, name, tmpl,
NLE_TYPE, token->location);
}
}
else
type = error_mark_node;
if ((flags & CP_PARSER_FLAGS_OPTIONAL)
&& !cp_parser_parse_definitely (parser))
type = NULL_TREE;
}
if (type && decl_specs) if (type && decl_specs)
cp_parser_set_decl_spec_type (decl_specs, type, cp_parser_set_decl_spec_type (decl_specs, type,
token, token,
@ -18577,10 +18629,28 @@ cp_parser_init_declarator (cp_parser* parser,
declared. */ declared. */
resume_deferring_access_checks (); resume_deferring_access_checks ();
/* Parse the declarator. */
token = cp_lexer_peek_token (parser->lexer); token = cp_lexer_peek_token (parser->lexer);
cp_parser_declarator_kind cdk = CP_PARSER_DECLARATOR_NAMED;
if (token->type == CPP_OPEN_PAREN
&& decl_specifiers->type
&& is_auto (decl_specifiers->type)
&& CLASS_PLACEHOLDER_TEMPLATE (decl_specifiers->type))
{
// C++17 deduction guide.
cdk = CP_PARSER_DECLARATOR_ABSTRACT;
for (int i = 0; i < ds_last; ++i)
if (i != ds_type_spec
&& decl_specifiers->locations[i]
&& !cp_parser_simulate_error (parser))
error_at (decl_specifiers->locations[i],
"decl-specifier in declaration of deduction guide");
}
/* Parse the declarator. */
declarator declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, = cp_parser_declarator (parser, cdk,
&ctor_dtor_or_conv_p, &ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL, /*parenthesized_p=*/NULL,
member_p, friend_p); member_p, friend_p);
@ -18594,6 +18664,17 @@ cp_parser_init_declarator (cp_parser* parser,
if (declarator == cp_error_declarator) if (declarator == cp_error_declarator)
return error_mark_node; return error_mark_node;
if (cdk == CP_PARSER_DECLARATOR_ABSTRACT)
{
gcc_assert (declarator->kind == cdk_function
&& !declarator->declarator);
tree t = CLASS_PLACEHOLDER_TEMPLATE (decl_specifiers->type);
declarator->declarator = make_id_declarator (NULL_TREE, dguide_name (t),
sfk_none);
declarator->declarator->id_loc
= decl_specifiers->locations[ds_type_spec];
}
/* Check that the number of template-parameter-lists is OK. */ /* Check that the number of template-parameter-lists is OK. */
if (!cp_parser_check_declarator_template_parameters (parser, declarator, if (!cp_parser_check_declarator_template_parameters (parser, declarator,
token->location)) token->location))
@ -20118,6 +20199,16 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg,
cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, cp_parser_type_specifier_seq (parser, /*is_declaration=*/false,
is_trailing_return, is_trailing_return,
&type_specifier_seq); &type_specifier_seq);
if (is_template_arg && type_specifier_seq.type
&& TREE_CODE (type_specifier_seq.type) == TEMPLATE_TYPE_PARM
&& CLASS_PLACEHOLDER_TEMPLATE (type_specifier_seq.type))
/* A bare template name as a template argument is a template template
argument, not a placeholder, so fail parsing it as a type argument. */
{
gcc_assert (cp_parser_uncommitted_to_tentative_parse_p (parser));
cp_parser_simulate_error (parser);
return error_mark_node;
}
if (type_specifier_seq.type == error_mark_node) if (type_specifier_seq.type == error_mark_node)
return error_mark_node; return error_mark_node;

View File

@ -4272,6 +4272,23 @@ template_parm_to_arg (tree t)
return t; return t;
} }
/* Given a single level of template parameters (a TREE_VEC), return it
as a set of template arguments. */
static tree
template_parms_level_to_args (tree parms)
{
tree a = copy_node (parms);
TREE_TYPE (a) = NULL_TREE;
for (int i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
if (CHECKING_P)
SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
return a;
}
/* Given a set of template parameters, return them as a set of template /* Given a set of template parameters, return them as a set of template
arguments. The template parameters are represented as a TREE_VEC, in arguments. The template parameters are represented as a TREE_VEC, in
the form documented in cp-tree.h for template arguments. */ the form documented in cp-tree.h for template arguments. */
@ -4292,15 +4309,7 @@ template_parms_to_args (tree parms)
for (header = parms; header; header = TREE_CHAIN (header)) for (header = parms; header; header = TREE_CHAIN (header))
{ {
tree a = copy_node (TREE_VALUE (header)); tree a = template_parms_level_to_args (TREE_VALUE (header));
int i;
TREE_TYPE (a) = NULL_TREE;
for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
if (CHECKING_P)
SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
if (length > 1) if (length > 1)
TREE_VEC_ELT (args, --l) = a; TREE_VEC_ELT (args, --l) = a;
@ -11357,6 +11366,30 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return t; return t;
} }
/* Substitute ARGS into one level PARMS of template parameters. */
static tree
tsubst_template_parms_level (tree parms, tree args, tsubst_flags_t complain)
{
if (parms == error_mark_node)
return error_mark_node;
tree new_vec = make_tree_vec (TREE_VEC_LENGTH (parms));
for (int i = 0; i < TREE_VEC_LENGTH (new_vec); ++i)
{
tree tuple = TREE_VEC_ELT (parms, i);
if (tuple == error_mark_node)
continue;
TREE_VEC_ELT (new_vec, i) =
tsubst_template_parm (tuple, args, complain);
}
return new_vec;
}
/* Return the result of substituting ARGS into the template parameters /* Return the result of substituting ARGS into the template parameters
given by PARMS. If there are m levels of ARGS and m + n levels of given by PARMS. If there are m levels of ARGS and m + n levels of
PARMS, then the result will contain n levels of PARMS. For PARMS, then the result will contain n levels of PARMS. For
@ -11381,26 +11414,8 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
new_parms = &(TREE_CHAIN (*new_parms)), new_parms = &(TREE_CHAIN (*new_parms)),
parms = TREE_CHAIN (parms)) parms = TREE_CHAIN (parms))
{ {
tree new_vec = tree new_vec = tsubst_template_parms_level (TREE_VALUE (parms),
make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms))); args, complain);
int i;
for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i)
{
tree tuple;
if (parms == error_mark_node)
continue;
tuple = TREE_VEC_ELT (TREE_VALUE (parms), i);
if (tuple == error_mark_node)
continue;
TREE_VEC_ELT (new_vec, i) =
tsubst_template_parm (tuple, args, complain);
}
*new_parms = *new_parms =
tree_cons (size_int (TMPL_PARMS_DEPTH (parms) tree_cons (size_int (TMPL_PARMS_DEPTH (parms)
- TMPL_ARGS_DEPTH (args)), - TMPL_ARGS_DEPTH (args)),
@ -23940,6 +23955,16 @@ make_auto (void)
return make_auto_1 (get_identifier ("auto"), true); return make_auto_1 (get_identifier ("auto"), true);
} }
/* Return a C++17 deduction placeholder for class template TMPL. */
tree
make_template_placeholder (tree tmpl)
{
tree t = make_auto_1 (DECL_NAME (tmpl), true);
CLASS_PLACEHOLDER_TEMPLATE (t) = tmpl;
return t;
}
/* Make a "constrained auto" type-specifier. This is an /* Make a "constrained auto" type-specifier. This is an
auto type with constraints that must be associated after auto type with constraints that must be associated after
deduction. The constraint is formed from the given deduction. The constraint is formed from the given
@ -24097,6 +24122,316 @@ extract_autos (tree type)
return tree_vec; return tree_vec;
} }
/* The stem for deduction guide names. */
const char *const dguide_base = "__dguide_";
/* Return the name for a deduction guide for class template TMPL. */
tree
dguide_name (tree tmpl)
{
tree type = (TYPE_P (tmpl) ? tmpl : TREE_TYPE (tmpl));
tree tname = TYPE_IDENTIFIER (type);
char *buf = (char *) alloca (1 + strlen (dguide_base)
+ IDENTIFIER_LENGTH (tname));
memcpy (buf, dguide_base, strlen (dguide_base));
memcpy (buf + strlen (dguide_base), IDENTIFIER_POINTER (tname),
IDENTIFIER_LENGTH (tname) + 1);
tree dname = get_identifier (buf);
TREE_TYPE (dname) = type;
return dname;
}
/* True if NAME is the name of a deduction guide. */
bool
dguide_name_p (tree name)
{
return (TREE_TYPE (name)
&& !strncmp (IDENTIFIER_POINTER (name), dguide_base,
strlen (dguide_base)));
}
/* True if FN is a deduction guide. */
bool
deduction_guide_p (tree fn)
{
if (tree name = DECL_NAME (fn))
return dguide_name_p (name);
return false;
}
/* OLDDECL is a _DECL for a template parameter. Return a similar parameter at
LEVEL:INDEX, using tsubst_args and complain for substitution into non-type
template parameter types. Note that the handling of template template
parameters relies on current_template_parms being set appropriately for the
new template. */
static tree
rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
tree tsubst_args, tsubst_flags_t complain)
{
tree oldidx = get_template_parm_index (olddecl);
tree newtype;
if (TREE_CODE (olddecl) == TYPE_DECL
|| TREE_CODE (olddecl) == TEMPLATE_DECL)
{
newtype = copy_type (TREE_TYPE (olddecl));
TYPE_MAIN_VARIANT (newtype) = newtype;
}
else
newtype = tsubst (TREE_TYPE (olddecl), tsubst_args,
complain, NULL_TREE);
tree newdecl
= build_decl (DECL_SOURCE_LOCATION (olddecl), TREE_CODE (olddecl),
DECL_NAME (olddecl), newtype);
SET_DECL_TEMPLATE_PARM_P (newdecl);
tree newidx;
if (TREE_CODE (olddecl) == TYPE_DECL
|| TREE_CODE (olddecl) == TEMPLATE_DECL)
{
newidx = TEMPLATE_TYPE_PARM_INDEX (newtype)
= build_template_parm_index (index, level, level,
newdecl, newtype);
TYPE_STUB_DECL (newtype) = TYPE_NAME (newtype) = newdecl;
TYPE_CANONICAL (newtype) = canonical_type_parameter (newtype);
if (TREE_CODE (olddecl) == TEMPLATE_DECL)
{
DECL_TEMPLATE_RESULT (newdecl)
= build_decl (DECL_SOURCE_LOCATION (olddecl), TYPE_DECL,
DECL_NAME (olddecl), newtype);
DECL_ARTIFICIAL (DECL_TEMPLATE_RESULT (newdecl)) = true;
// First create a copy (ttargs) of tsubst_args with an
// additional level for the template template parameter's own
// template parameters (ttparms).
tree ttparms = (INNERMOST_TEMPLATE_PARMS
(DECL_TEMPLATE_PARMS (olddecl)));
const int depth = TMPL_ARGS_DEPTH (tsubst_args);
tree ttargs = make_tree_vec (depth + 1);
for (int i = 0; i < depth; ++i)
TREE_VEC_ELT (ttargs, i) = TREE_VEC_ELT (tsubst_args, i);
TREE_VEC_ELT (ttargs, depth)
= template_parms_level_to_args (ttparms);
// Substitute ttargs into ttparms to fix references to
// other template parameters.
ttparms = tsubst_template_parms_level (ttparms, ttargs,
complain);
// Now substitute again with args based on tparms, to reduce
// the level of the ttparms.
ttargs = current_template_args ();
ttparms = tsubst_template_parms_level (ttparms, ttargs,
complain);
// Finally, tack the adjusted parms onto tparms.
ttparms = tree_cons (size_int (depth), ttparms,
current_template_parms);
DECL_TEMPLATE_PARMS (newdecl) = ttparms;
}
}
else
{
tree oldconst = TEMPLATE_PARM_DECL (oldidx);
tree newconst
= build_decl (DECL_SOURCE_LOCATION (oldconst),
TREE_CODE (oldconst),
DECL_NAME (oldconst), newtype);
TREE_CONSTANT (newconst) = TREE_CONSTANT (newdecl)
= TREE_READONLY (newconst) = TREE_READONLY (newdecl) = true;
SET_DECL_TEMPLATE_PARM_P (newconst);
newidx = build_template_parm_index (index, level, level,
newconst, newtype);
DECL_INITIAL (newdecl) = DECL_INITIAL (newconst) = newidx;
}
TEMPLATE_PARM_PARAMETER_PACK (newidx)
= TEMPLATE_PARM_PARAMETER_PACK (oldidx);
return newdecl;
}
/* Returns a C++17 class deduction guide template based on the constructor
CTOR. */
static tree
build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
{
if (outer_args)
ctor = tsubst (ctor, outer_args, complain, ctor);
tree type = DECL_CONTEXT (ctor);
tree fn_tmpl;
if (TREE_CODE (ctor) == TEMPLATE_DECL)
{
fn_tmpl = ctor;
ctor = DECL_TEMPLATE_RESULT (fn_tmpl);
}
else
fn_tmpl = DECL_TI_TEMPLATE (ctor);
tree tparms = DECL_TEMPLATE_PARMS (fn_tmpl);
/* If type is a member class template, DECL_TI_ARGS (ctor) will have fully
specialized args for the enclosing class. Strip those off, as the
deduction guide won't have those template parameters. */
tree targs = get_innermost_template_args (DECL_TI_ARGS (ctor),
TMPL_PARMS_DEPTH (tparms));
/* Discard the 'this' parameter. */
tree fparms = FUNCTION_ARG_CHAIN (ctor);
tree fargs = TREE_CHAIN (DECL_ARGUMENTS (ctor));
tree ci = get_constraints (ctor);
if (PRIMARY_TEMPLATE_P (fn_tmpl))
{
/* For a member template constructor, we need to flatten the two template
parameter lists into one, and then adjust the function signature
accordingly. This gets...complicated. */
++processing_template_decl;
tree save_parms = current_template_parms;
/* For a member template we should have two levels of parms/args, one for
the class and one for the constructor. We stripped specialized args
for further enclosing classes above. */
const int depth = 2;
gcc_assert (TMPL_ARGS_DEPTH (targs) == depth);
/* Template args for translating references to the two-level template
parameters into references to the one-level template parameters we are
creating. */
tree tsubst_args = copy_node (targs);
TMPL_ARGS_LEVEL (tsubst_args, depth)
= copy_node (TMPL_ARGS_LEVEL (tsubst_args, depth));
/* Template parms for the constructor template. */
tree ftparms = TREE_VALUE (tparms);
unsigned flen = TREE_VEC_LENGTH (ftparms);
/* Template parms for the class template. */
tparms = TREE_CHAIN (tparms);
tree ctparms = TREE_VALUE (tparms);
unsigned clen = TREE_VEC_LENGTH (ctparms);
/* Template parms for the deduction guide start as a copy of the template
parms for the class. We set current_template_parms for
lookup_template_class_1. */
current_template_parms = tparms = copy_node (tparms);
tree new_vec = TREE_VALUE (tparms) = make_tree_vec (flen + clen);
for (unsigned i = 0; i < clen; ++i)
TREE_VEC_ELT (new_vec, i) = TREE_VEC_ELT (ctparms, i);
/* Now we need to rewrite the constructor parms to append them to the
class parms. */
for (unsigned i = 0; i < flen; ++i)
{
unsigned index = i + clen;
unsigned level = 1;
tree oldelt = TREE_VEC_ELT (ftparms, i);
tree olddecl = TREE_VALUE (oldelt);
tree newdecl = rewrite_template_parm (olddecl, index, level,
tsubst_args, complain);
tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt),
tsubst_args, complain, ctor);
tree list = build_tree_list (newdef, newdecl);
TEMPLATE_PARM_CONSTRAINTS (list)
= tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
tsubst_args, complain, ctor);
TREE_VEC_ELT (new_vec, index) = list;
TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list);
}
/* Now we have a final set of template parms to substitute into the
function signature. */
targs = template_parms_to_args (tparms);
fparms = tsubst (fparms, tsubst_args, complain, ctor);
fargs = tsubst (fargs, tsubst_args, complain, ctor);
if (ci)
ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor);
current_template_parms = save_parms;
--processing_template_decl;
}
tree fntype = build_function_type (type, fparms);
tree ded_fn = build_lang_decl_loc (DECL_SOURCE_LOCATION (ctor),
FUNCTION_DECL,
dguide_name (type), fntype);
DECL_ARGUMENTS (ded_fn) = fargs;
tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false);
DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn;
TREE_TYPE (ded_tmpl) = TREE_TYPE (ded_fn);
DECL_TEMPLATE_INFO (ded_fn) = build_template_info (ded_tmpl, targs);
if (ci)
set_constraints (ded_tmpl, ci);
return ded_tmpl;
}
/* Deduce template arguments for the class template TMPL based on the
initializer INIT, and return the resulting type. */
tree
do_class_deduction (tree tmpl, tree init, tsubst_flags_t complain)
{
gcc_assert (DECL_CLASS_TEMPLATE_P (tmpl));
tree type = TREE_TYPE (tmpl);
vec<tree,va_gc> *args;
if (TREE_CODE (init) == TREE_LIST)
args = make_tree_vector_from_list (init);
else
args = make_tree_vector_single (init);
if (args->length() == 1)
{
/* First try to deduce directly, since we don't have implicitly-declared
constructors yet. */
tree parms = build_tree_list (NULL_TREE, type);
tree tparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
int err = type_unification_real (tparms, targs, parms, &(*args)[0],
1, /*subr*/false, DEDUCE_CALL,
LOOKUP_NORMAL, NULL, /*explain*/false);
if (err == 0)
return tsubst (type, targs, complain, tmpl);
}
tree dname = dguide_name (tmpl);
tree cands = lookup_qualified_name (CP_DECL_CONTEXT (tmpl), dname,
/*type*/false, /*complain*/false,
/*hidden*/false);
if (cands == error_mark_node)
cands = NULL_TREE;
tree outer_args = NULL_TREE;
if (DECL_CLASS_SCOPE_P (tmpl)
&& CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (tmpl)))
{
outer_args = CLASSTYPE_TI_ARGS (DECL_CONTEXT (tmpl));
type = TREE_TYPE (most_general_template (tmpl));
}
if (CLASSTYPE_METHOD_VEC (type))
// FIXME cache artificial deduction guides
for (tree fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
tree guide = build_deduction_guide (fn, outer_args, complain);
cands = ovl_cons (guide, cands);
}
if (cands == NULL_TREE)
{
error ("cannot deduce template arguments for %qT, as it has "
"no deduction guides or user-declared constructors", type);
return error_mark_node;
}
tree t = build_new_function_call (cands, &args, /*koenig*/false,
complain|tf_decltype);
release_tree_vector (args);
return TREE_TYPE (t);
}
/* Replace occurrences of 'auto' in TYPE with the appropriate type deduced /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. */ from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. */
@ -24175,6 +24510,9 @@ do_auto_deduction (tree type, tree init, tree auto_node,
return error_mark_node; return error_mark_node;
} }
} }
else if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
/* C++17 class template argument deduction. */
return do_class_deduction (tmpl, init, complain);
else else
{ {
tree parms = build_tree_list (NULL_TREE, type); tree parms = build_tree_list (NULL_TREE, type);
@ -24274,6 +24612,20 @@ splice_late_return_type (tree type, tree late_return_type)
{ {
if (is_auto (type)) if (is_auto (type))
{ {
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type))
{
if (!late_return_type)
error ("deduction guide must have trailing return type");
else if (CLASS_TYPE_P (late_return_type)
&& CLASSTYPE_TEMPLATE_INFO (late_return_type)
&& CLASSTYPE_TI_TEMPLATE (late_return_type) == tmpl)
/* OK */;
else
error ("trailing return type %qT of deduction guide is not "
"a specialization of %qT",
late_return_type, TREE_TYPE (tmpl));
}
if (late_return_type) if (late_return_type)
return late_return_type; return late_return_type;
@ -24288,14 +24640,15 @@ splice_late_return_type (tree type, tree late_return_type)
} }
/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto' or /* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto' or
'decltype(auto)'. */ 'decltype(auto)' or a deduced class template. */
bool bool
is_auto (const_tree type) is_auto (const_tree type)
{ {
if (TREE_CODE (type) == TEMPLATE_TYPE_PARM if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
&& (TYPE_IDENTIFIER (type) == get_identifier ("auto") && (TYPE_IDENTIFIER (type) == get_identifier ("auto")
|| TYPE_IDENTIFIER (type) == get_identifier ("decltype(auto)"))) || TYPE_IDENTIFIER (type) == get_identifier ("decltype(auto)")
|| CLASS_PLACEHOLDER_TEMPLATE (type)))
return true; return true;
else else
return false; return false;

View File

@ -1952,11 +1952,23 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
return error_mark_node; return error_mark_node;
} }
if (type_uses_auto (type)) if (tree anode = type_uses_auto (type))
{ {
if (complain & tf_error) if (!CLASS_PLACEHOLDER_TEMPLATE (anode))
error ("invalid use of %<auto%>"); {
return error_mark_node; if (complain & tf_error)
error ("invalid use of %qT", anode);
return error_mark_node;
}
else if (!parms)
{
if (complain & tf_error)
error ("cannot deduce template arguments for %qT from ()", anode);
return error_mark_node;
}
else
type = do_auto_deduction (type, parms, anode, complain,
adc_variable_type);
} }
if (processing_template_decl) if (processing_template_decl)

View File

@ -0,0 +1,17 @@
// { dg-options "-std=c++1z -fconcepts" }
template <class T>
concept bool Isint = __is_same_as(T,int);
template <class T>
struct A
{
int i;
A(...);
};
template <Isint I>
A(I) -> A<I>;
A a(1);
A a2(1.0); // { dg-error "" }

View File

@ -10,5 +10,5 @@ concept bool C2 = true;
template<C1 T> // { dg-error "not a type" } template<C1 T> // { dg-error "not a type" }
constexpr bool f1( ) { return true; } constexpr bool f1( ) { return true; }
template<C2<int> T> // { dg-error "expected" } template<C2<int> T> // { dg-error "expected|not a type" }
constexpr bool f2( ) { return true; } constexpr bool f2( ) { return true; }

View File

@ -0,0 +1,9 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
A(T);
};
A a (42);

View File

@ -0,0 +1,11 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
int i;
A(...);
};
template <class T>
A(T) -> A<T> { } // { dg-error "1:function body" }

View File

@ -0,0 +1,11 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
int i;
A(...);
};
template <class T>
static A(T) -> A<T>; // { dg-error "1:decl-specifier" }

View File

@ -0,0 +1,17 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
template<class U, template<U u> class P>
A(T,U,P<42>);
};
template <int I> struct B { };
int i;
A a(&i,2,B<42>());
template <class,class> class same;
template <class T> class same<T,T> {};
same<decltype(a), A<int*>> s;

View File

@ -0,0 +1,18 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
template <class U>
struct B
{
template <class V>
B(T,U,V);
};
};
A<int>::B b(1,2.0,'\3');
template <class,class> class same;
template <class T> class same<T,T> {};
same<decltype(b), A<int>::B<double>> s;

View File

@ -0,0 +1,10 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
template <class U>
A(T, U);
};
A a (42, 1.0);

View File

@ -0,0 +1,14 @@
// { dg-options -std=c++1z }
template <int I>
struct A { };
template <int I>
struct B
{
template<template<int>class T>
B(T<I>);
};
A<42> a;
B b (a);

View File

@ -0,0 +1,19 @@
// { dg-options -std=c++1z }
template <int I, int J>
struct A { };
template <int I>
struct B
{
template<int J>
B(A<I,J>);
};
A<42,24> a;
B b (a);
int main()
{
(B(a));
}

View File

@ -0,0 +1,10 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
int i;
};
A<int> a1;
A a(a1);

View File

@ -0,0 +1,11 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
int i;
};
struct B : A<int> {} b;
A a(b);

View File

@ -0,0 +1,10 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
int i;
};
template <class T>
A(T); // { dg-error "must have trailing return type" }

View File

@ -0,0 +1,15 @@
// { dg-options -std=c++1z }
template <class T>
struct A
{
int i;
A(...); // { dg-message "candidate" }
};
A a(42); // { dg-error "" }
template <class T>
A(T) -> A<T>;
A a2(42);

View File

@ -0,0 +1,18 @@
// { dg-options -std=c++1z }
namespace N {
template <class T>
struct A
{
int i;
A(...);
};
}
template <class T>
N::A(T) -> N::A<T>; // { dg-error "scope" }
namespace N {
template <class T>
A(T) -> A<T>;
}

View File

@ -8,4 +8,4 @@ template<int> struct A
}; };
// Instead of the bogus error we get a different error. // Instead of the bogus error we get a different error.
// { dg-error "template-name" "" { target *-*-* } 7 } // { dg-error "template-name|expected" "" { target *-*-* } 7 }

View File

@ -5,13 +5,12 @@
namespace N namespace N
{ {
template<typename> template<typename>
struct X { }; // { dg-message "N::X" } struct X { };
} }
N::X X; // { dg-error "" "" } N::X X; // { dg-error "" "" }
int main() int main()
{ {
return sizeof(X); // { dg-error "" "" } return sizeof(X); // { dg-prune-output "not declared in this scope" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } 15 }
} }

View File

@ -3,5 +3,5 @@ namespace N {
} }
int main() { int main() {
N::C(); // { dg-error "template" } N::C(); // { dg-error "template|deduction" }
} }

View File

@ -17,7 +17,7 @@ int main()
find_if( l.begin(), l.end(), find_if( l.begin(), l.end(),
// This is a typo, it should be bind2nd, but an // This is a typo, it should be bind2nd, but an
// ICE is not a very helpful diagnostic! // ICE is not a very helpful diagnostic!
binder2nd( equal_to<int>(), 2 ) ); // { dg-error "" } binder2nd( equal_to<int>(), 2 ) ); // { dg-error "" "" { target c++14_down } }
assert( *(it) == 2 ); assert( *(it) == 2 );
} }

View File

@ -16,7 +16,7 @@ int main()
std::find_if( l.begin(), l.end(), std::find_if( l.begin(), l.end(),
// This is a typo, it should be bind2nd, but an // This is a typo, it should be bind2nd, but an
// ICE is not a very helpful diagnostic! // ICE is not a very helpful diagnostic!
std::binder2nd( std::equal_to<int>(), 2 ) ); // { dg-error "" } std::binder2nd( std::equal_to<int>(), 2 ) ); // { dg-error "" "" { target c++14_down } }
assert( *(it) == 2 ); assert( *(it) == 2 );
} }