+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
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 */
};
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,
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);
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)
"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);
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 ();
}
{
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));
#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)
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);
}
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);
if (decl == NULL_TREE)
return error_mark_node;
+ if (explicitp == 2)
+ DECL_NONCONVERTING_P (decl) = 1;
if (staticp == 1)
{
int invalid_static = 0;
if (dguide_name_p (t))
{
dump_decl (pp, CLASSTYPE_TI_TEMPLATE (TREE_TYPE (t)),
- TFF_PLAIN_IDENTIFIER);
+ TFF_UNQUALIFIED_NAME);
return;
}
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);
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))
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))
/* [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
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.
}
/* 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)
|| 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;
};
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,
/*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
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))));
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)
/* 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))
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;
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))
{
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);
/* 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. */
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;
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
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;
}
--- /dev/null
+// 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>;
--- /dev/null
+// 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 "" }
}
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>