aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2017-02-09 15:55:54 -0500
committerJason Merrill <jason@gcc.gnu.org>2017-02-09 15:55:54 -0500
commita56c0ac08242269bbcc4bd1f480eda2378336776 (patch)
treefdb30ba42b1dd45219d4eab973e41db807ec03b7 /gcc
parent388dde26a5b5a6740018340953955eb05abba817 (diff)
downloadgcc-a56c0ac08242269bbcc4bd1f480eda2378336776.zip
gcc-a56c0ac08242269bbcc4bd1f480eda2378336776.tar.gz
gcc-a56c0ac08242269bbcc4bd1f480eda2378336776.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog18
-rw-r--r--gcc/cp/cp-tree.h6
-rw-r--r--gcc/cp/decl.c49
-rw-r--r--gcc/cp/error.c2
-rw-r--r--gcc/cp/parser.c91
-rw-r--r--gcc/cp/pt.c58
-rw-r--r--gcc/cp/tree.c2
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction27.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction28.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction9.C2
10 files changed, 191 insertions, 66 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 6639fbd..caa1df9 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 77bf614..a410926 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d1d485a..734a6c7 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 92137f7..d8c5d5e 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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;
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index aadf44d..8812f8c 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8863c28..58d6016 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index afd442f..785dfaf 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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;
}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction27.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction27.C
new file mode 100644
index 0000000..ce5c5d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction27.C
@@ -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>;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction28.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction28.C
new file mode 100644
index 0000000..c91ec0d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction28.C
@@ -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 "" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C
index 5a2b4f6..149ef43 100644
--- a/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C
@@ -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>