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:
parent
8ff04ff92d
commit
76b294d48d
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 ())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
103
gcc/cp/parser.c
103
gcc/cp/parser.c
|
@ -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;
|
||||||
|
|
||||||
|
|
415
gcc/cp/pt.c
415
gcc/cp/pt.c
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 "" }
|
|
@ -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; }
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
A(T);
|
||||||
|
};
|
||||||
|
|
||||||
|
A a (42);
|
|
@ -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" }
|
|
@ -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" }
|
|
@ -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;
|
|
@ -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;
|
|
@ -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);
|
|
@ -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);
|
|
@ -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));
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
A<int> a1;
|
||||||
|
A a(a1);
|
|
@ -0,0 +1,11 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B : A<int> {} b;
|
||||||
|
|
||||||
|
A a(b);
|
|
@ -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" }
|
|
@ -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);
|
|
@ -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>;
|
||||||
|
}
|
|
@ -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 }
|
||||||
|
|
|
@ -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 }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,5 @@ namespace N {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
N::C(); // { dg-error "template" }
|
N::C(); // { dg-error "template|deduction" }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue