PR c++/79316 - default argument in deduction guide

PR c++/79350 - explicit deduction guide
	* parser.c (cp_parser_constructor_declarator_p)
	(cp_parser_direct_declarator): Parse deduction guides more like
	constructors.
	* cp-tree.h (enum special_function_kind): Add sfk_deduction_guide.
	* tree.c (special_function_p): Return it.
	* decl.c (check_special_function_return_type): Handle it.
	(grokdeclarator, grokfndecl): Adjust.
	(cp_finish_decl): Pass flags to do_auto_deduction.
	* error.c (dump_decl_name): Use TFF_UNQUALIFIED_NAME.
	* pt.c (dguide_name_p): Take a const_tree.
	(do_class_deduction): Handle explicit.
	(do_auto_deduction): Pass flags through.
	(build_deduction_guide): Copy explicit flag.

From-SVN: r245314
This commit is contained in:
Jason Merrill 2017-02-09 15:55:54 -05:00 committed by Jason Merrill
parent 388dde26a5
commit a56c0ac082
10 changed files with 191 additions and 66 deletions

View File

@ -1,3 +1,21 @@
2017-02-09 Jason Merrill <jason@redhat.com>
PR c++/79316 - default argument in deduction guide
PR c++/79350 - explicit deduction guide
* parser.c (cp_parser_constructor_declarator_p)
(cp_parser_direct_declarator): Parse deduction guides more like
constructors.
* cp-tree.h (enum special_function_kind): Add sfk_deduction_guide.
* tree.c (special_function_p): Return it.
* decl.c (check_special_function_return_type): Handle it.
(grokdeclarator, grokfndecl): Adjust.
(cp_finish_decl): Pass flags to do_auto_deduction.
* error.c (dump_decl_name): Use TFF_UNQUALIFIED_NAME.
* pt.c (dguide_name_p): Take a const_tree.
(do_class_deduction): Handle explicit.
(do_auto_deduction): Pass flags through.
(build_deduction_guide): Copy explicit flag.
2017-02-09 Jakub Jelinek <jakub@redhat.com>
PR c++/79429

View File

@ -4733,6 +4733,7 @@ enum special_function_kind {
deletes the object after it has been
destroyed. */
sfk_conversion, /* A conversion operator. */
sfk_deduction_guide, /* A class template deduction guide. */
sfk_inheriting_constructor /* An inheriting constructor */
};
@ -6150,7 +6151,8 @@ extern tree do_auto_deduction (tree, tree, tree);
extern tree do_auto_deduction (tree, tree, tree,
tsubst_flags_t,
auto_deduction_context,
tree = NULL_TREE);
tree = NULL_TREE,
int = LOOKUP_NORMAL);
extern tree type_uses_auto (tree);
extern tree type_uses_auto_or_concept (tree);
extern void append_type_to_template_for_access_check (tree, tree, tree,
@ -6280,7 +6282,7 @@ extern tree extract_fnparm_pack (tree, 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);
extern bool deduction_guide_p (const_tree);
/* in repo.c */
extern void init_repo (void);

View File

@ -6821,7 +6821,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
adc = adc_decomp_type;
type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
tf_warning_or_error, adc);
tf_warning_or_error, adc,
NULL_TREE, flags);
if (type == error_mark_node)
return;
if (TREE_CODE (type) == FUNCTION_TYPE)
@ -8730,14 +8731,6 @@ grokfndecl (tree ctype,
"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);
@ -9758,6 +9751,20 @@ check_special_function_return_type (special_function_kind sfk,
type = optype;
break;
case sfk_deduction_guide:
if (type)
error ("return type specified for deduction guide");
else if (type_quals != TYPE_UNQUALIFIED)
error_at (smallest_type_quals_location (type_quals, locations),
"qualifiers are not allowed on declaration of "
"deduction guide");
type = make_template_placeholder (CLASSTYPE_TI_TEMPLATE (optype));
for (int i = 0; i < ds_last; ++i)
if (i != ds_explicit && locations[i])
error_at (locations[i],
"decl-specifier in declaration of deduction guide");
break;
default:
gcc_unreachable ();
}
@ -10105,7 +10112,6 @@ grokdeclarator (const cp_declarator *declarator,
{
gcc_assert (flags == NO_SPECIAL);
flags = TYPENAME_FLAG;
ctor_return_type = TREE_TYPE (dname);
sfk = sfk_conversion;
if (is_typename_at_global_scope (dname))
name = identifier_to_locale (IDENTIFIER_POINTER (dname));
@ -10285,8 +10291,9 @@ grokdeclarator (const cp_declarator *declarator,
#endif
typedef_type = type;
if (sfk != sfk_conversion)
if (sfk == sfk_conversion || sfk == sfk_deduction_guide)
ctor_return_type = TREE_TYPE (dname);
else
ctor_return_type = ctype;
if (sfk != sfk_none)
@ -10906,12 +10913,13 @@ grokdeclarator (const cp_declarator *declarator,
if (!late_return_type)
{
if (dguide_name_p (unqualified_id))
error_at (typespec_loc, "deduction guide for "
"%qT must have trailing return type",
TREE_TYPE (tmpl));
error_at (declarator->id_loc, "deduction guide "
"for %qT must have trailing return "
"type", TREE_TYPE (tmpl));
else
error_at (typespec_loc, "deduced class type %qT "
"in function return type", type);
error_at (declarator->id_loc, "deduced class "
"type %qT in function return type",
type);
inform (DECL_SOURCE_LOCATION (tmpl),
"%qD declared here", tmpl);
}
@ -11039,6 +11047,11 @@ grokdeclarator (const cp_declarator *declarator,
if (late_return_type_p)
error ("a conversion function cannot have a trailing return type");
}
else if (sfk == sfk_deduction_guide)
{
if (explicitp == 1)
explicitp = 2;
}
arg_types = grokparms (declarator->u.function.parameters,
&parms);
@ -12207,6 +12220,8 @@ grokdeclarator (const cp_declarator *declarator,
if (decl == NULL_TREE)
return error_mark_node;
if (explicitp == 2)
DECL_NONCONVERTING_P (decl) = 1;
if (staticp == 1)
{
int invalid_static = 0;

View File

@ -1015,7 +1015,7 @@ dump_decl_name (cxx_pretty_printer *pp, tree t, int flags)
if (dguide_name_p (t))
{
dump_decl (pp, CLASSTYPE_TI_TEMPLATE (TREE_TYPE (t)),
TFF_PLAIN_IDENTIFIER);
TFF_UNQUALIFIED_NAME);
return;
}

View File

@ -19050,26 +19050,9 @@ cp_parser_init_declarator (cp_parser* parser,
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
= cp_parser_declarator (parser, cdk,
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
member_p, friend_p);
@ -19083,17 +19066,6 @@ cp_parser_init_declarator (cp_parser* parser,
if (declarator == cp_error_declarator)
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. */
if (!cp_parser_check_declarator_template_parameters (parser, declarator,
token->location))
@ -19136,6 +19108,25 @@ cp_parser_init_declarator (cp_parser* parser,
if (function_declarator_p (declarator))
{
/* Handle C++17 deduction guides. */
if (!decl_specifiers->type
&& ctor_dtor_or_conv_p <= 0
&& cxx_dialect >= cxx1z)
{
cp_declarator *id = get_id_declarator (declarator);
tree name = id->u.id.unqualified_name;
parser->scope = id->u.id.qualifying_scope;
tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc);
if (tmpl
&& (DECL_CLASS_TEMPLATE_P (tmpl)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
{
id->u.id.unqualified_name = dguide_name (tmpl);
id->u.id.sfk = sfk_deduction_guide;
ctor_dtor_or_conv_p = 1;
}
}
/* Check to see if the token indicates the start of a
function-definition. */
if (cp_parser_token_starts_function_definition_p (token))
@ -19202,8 +19193,8 @@ cp_parser_init_declarator (cp_parser* parser,
/* [dcl.dcl]
Only in function declarations for constructors, destructors, and
type conversions can the decl-specifier-seq be omitted.
Only in function declarations for constructors, destructors, type
conversions, and deduction guides can the decl-specifier-seq be omitted.
We explicitly postpone this check past the point where we handle
function-definitions because we tolerate function-definitions
@ -19453,8 +19444,8 @@ cp_parser_init_declarator (cp_parser* parser,
attributes [opt] direct-abstract-declarator
If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to
detect constructor, destructor or conversion operators. It is set
to -1 if the declarator is a name, and +1 if it is a
detect constructors, destructors, deduction guides, or conversion operators.
It is set to -1 if the declarator is a name, and +1 if it is a
function. Otherwise it is set to zero. Usually you just want to
test for >0, but internally the negative value is used.
@ -25929,8 +25920,8 @@ cp_parser_global_scope_opt (cp_parser* parser, bool current_scope_valid_p)
}
/* Returns TRUE if the upcoming token sequence is the start of a
constructor declarator. If FRIEND_P is true, the declarator is
preceded by the `friend' specifier. */
constructor declarator or C++17 deduction guide. If FRIEND_P is true, the
declarator is preceded by the `friend' specifier. */
static bool
cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
@ -25975,8 +25966,10 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
|| friend_p);
/* Outside of a class-specifier, there must be a
nested-name-specifier. */
if (!nested_name_specifier && outside_class_specifier_p)
nested-name-specifier. Except in C++17 mode, where we
might be declaring a guiding declaration. */
if (!nested_name_specifier && outside_class_specifier_p
&& cxx_dialect < cxx1z)
constructor_p = false;
else if (nested_name_specifier == error_mark_node)
constructor_p = false;
@ -26007,6 +26000,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
};
we must recognize that the nested `S' names a class. */
if (cxx_dialect >= cxx1z)
cp_parser_parse_tentatively (parser);
tree type_decl;
type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
@ -26015,6 +26011,24 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
/*check_dependency_p=*/false,
/*class_head_p=*/false,
/*is_declaration=*/false);
if (cxx_dialect >= cxx1z
&& !cp_parser_parse_definitely (parser))
{
type_decl = NULL_TREE;
tree tmpl = cp_parser_template_name (parser,
/*template_keyword*/false,
/*check_dependency_p*/false,
/*is_declaration*/false,
none_type,
/*is_identifier*/NULL);
if (DECL_CLASS_TEMPLATE_P (tmpl)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
/* It's a deduction guide, return true. */;
else
cp_parser_simulate_error (parser);
}
/* If there was no class-name, then this is not a constructor.
Otherwise, if we are in a class-specifier and we aren't
handling a friend declaration, check that its type matches
@ -26022,6 +26036,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
is left alone for error recovery purposes. */
constructor_p = (!cp_parser_error_occurred (parser)
&& (outside_class_specifier_p
|| type_decl == NULL_TREE
|| type_decl == error_mark_node
|| same_type_p (current_class_type,
TREE_TYPE (type_decl))));
@ -26056,7 +26071,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
in the scope of the class. */
if (current_class_type)
type = NULL_TREE;
else
else if (type_decl)
{
type = TREE_TYPE (type_decl);
if (TREE_CODE (type) == TYPENAME_TYPE)

View File

@ -24786,7 +24786,7 @@ dguide_name_p (tree name)
/* True if FN is a deduction guide. */
bool
deduction_guide_p (tree fn)
deduction_guide_p (const_tree fn)
{
if (DECL_P (fn))
if (tree name = DECL_NAME (fn))
@ -24999,6 +24999,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
dguide_name (type), fntype);
DECL_ARGUMENTS (ded_fn) = fargs;
DECL_ARTIFICIAL (ded_fn) = true;
DECL_NONCONVERTING_P (ded_fn) = DECL_NONCONVERTING_P (ctor);
tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false);
DECL_ARTIFICIAL (ded_tmpl) = true;
DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn;
@ -25015,8 +25016,9 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
template TMPL based on the initializer INIT, and return the resulting
type. */
tree
do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain)
static tree
do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
tsubst_flags_t complain)
{
if (!DECL_CLASS_TEMPLATE_P (tmpl))
{
@ -25083,9 +25085,48 @@ do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain)
return error_mark_node;
}
/* Prune explicit deduction guides in copy-initialization context. */
tree old_cands = cands;
if (flags & LOOKUP_ONLYCONVERTING)
{
tree t = cands;
for (; t; t = OVL_NEXT (t))
if (DECL_NONCONVERTING_P (DECL_TEMPLATE_RESULT (OVL_CURRENT (t))))
break;
if (t)
{
tree pruned = NULL_TREE;
for (t = cands; t; t = OVL_NEXT (t))
{
tree f = OVL_CURRENT (t);
if (!DECL_NONCONVERTING_P (DECL_TEMPLATE_RESULT (f)))
pruned = build_overload (f, pruned);
}
cands = pruned;
if (cands == NULL_TREE)
{
error ("cannot deduce template arguments for copy-initialization"
" of %qT, as it has no non-explicit deduction guides or "
"user-declared constructors", type);
return error_mark_node;
}
}
}
++cp_unevaluated_operand;
tree t = build_new_function_call (cands, &args, /*koenig*/false,
complain|tf_decltype);
tf_decltype);
if (t == error_mark_node && (complain & tf_warning_or_error))
{
error ("class template argument deduction failed:");
t = build_new_function_call (cands, &args, /*koenig*/false,
complain | tf_decltype);
if (old_cands != cands)
inform (input_location, "explicit deduction guides not considered "
"for copy-initialization");
}
--cp_unevaluated_operand;
release_tree_vector (args);
@ -25106,7 +25147,10 @@ do_auto_deduction (tree type, tree init, tree auto_node)
/* 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.
The CONTEXT determines the context in which auto deduction is performed
and is used to control error diagnostics.
and is used to control error diagnostics. FLAGS are the LOOKUP_* flags.
OUTER_TARGS are used during template argument deduction
(context == adc_unify) to properly substitute the result, and is ignored
in other contexts.
For partial-concept-ids, extra args may be appended to the list of deduced
template arguments prior to determining constraint satisfaction. */
@ -25114,7 +25158,7 @@ do_auto_deduction (tree type, tree init, tree auto_node)
tree
do_auto_deduction (tree type, tree init, tree auto_node,
tsubst_flags_t complain, auto_deduction_context context,
tree outer_targs)
tree outer_targs, int flags)
{
tree targs;
@ -25129,7 +25173,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
/* C++17 class template argument deduction. */
return do_class_deduction (type, tmpl, init, complain);
return do_class_deduction (type, tmpl, init, flags, complain);
/* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto
with either a new invented type template parameter U or, if the

View File

@ -4374,6 +4374,8 @@ special_function_p (const_tree decl)
return sfk_deleting_destructor;
if (DECL_CONV_FN_P (decl))
return sfk_conversion;
if (deduction_guide_p (decl))
return sfk_deduction_guide;
return sfk_none;
}

View File

@ -0,0 +1,5 @@
// PR c++/79316
// { dg-options -std=c++1z }
template<typename T> struct S { S(T t) {} };
template<typename T> S(T, int = 7) -> S<T>;

View File

@ -0,0 +1,24 @@
// PR c++/79350
// { dg-options -std=c++1z }
template <class T>
struct A
{
explicit A(T);
};
A a (42);
A a2 = 42; // { dg-error "" }
template <class T>
struct B
{
B(T*);
};
template <class T>
explicit B(T) -> B<T*>;
B b1 (0);
B b2 = 0; // { dg-error "" }

View File

@ -10,7 +10,7 @@ namespace N {
}
template <class T>
N::A(T) -> N::A<T>; // { dg-error "scope" }
N::A(T) -> N::A<T>; // { dg-error "should have been declared inside .N" }
namespace N {
template <class T>