mirror of git://gcc.gnu.org/git/gcc.git
Fix C++17 template placeholder for template template parm.
* parser.c (cp_parser_simple_type_specifier): Allow placeholder for template template parameter. (cp_parser_type_id_1): Improve diagnostic. * decl.c (grokdeclarator): Handle class deduction diagnostics here. * pt.c (splice_late_return_type): Not here. (tsubst) [TEMPLATE_TYPE_PARM]: Substitute into placeholder template. (do_class_deduction): Handle non-class templates. From-SVN: r242018
This commit is contained in:
parent
4a826ca6fe
commit
e922b25690
|
|
@ -1,5 +1,13 @@
|
||||||
2016-11-09 Jason Merrill <jason@redhat.com>
|
2016-11-09 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
|
* parser.c (cp_parser_simple_type_specifier): Allow placeholder
|
||||||
|
for template template parameter.
|
||||||
|
(cp_parser_type_id_1): Improve diagnostic.
|
||||||
|
* decl.c (grokdeclarator): Handle class deduction diagnostics here.
|
||||||
|
* pt.c (splice_late_return_type): Not here.
|
||||||
|
(tsubst) [TEMPLATE_TYPE_PARM]: Substitute into placeholder template.
|
||||||
|
(do_class_deduction): Handle non-class templates.
|
||||||
|
|
||||||
Implement P0127R2, Declaring non-type parameters with auto.
|
Implement P0127R2, Declaring non-type parameters with auto.
|
||||||
* cp-tree.h (enum auto_deduction_context): Add adc_unify.
|
* cp-tree.h (enum auto_deduction_context): Add adc_unify.
|
||||||
* decl.c (grokdeclarator): Allow 'auto' in C++17 template non-type
|
* decl.c (grokdeclarator): Allow 'auto' in C++17 template non-type
|
||||||
|
|
|
||||||
|
|
@ -9490,6 +9490,11 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
if (initialized > 1)
|
if (initialized > 1)
|
||||||
funcdef_flag = true;
|
funcdef_flag = true;
|
||||||
|
|
||||||
|
location_t typespec_loc = smallest_type_quals_location (type_quals,
|
||||||
|
declspecs->locations);
|
||||||
|
if (typespec_loc == UNKNOWN_LOCATION)
|
||||||
|
typespec_loc = declspecs->locations[ds_type_spec];
|
||||||
|
|
||||||
/* Look inside a declarator for the name being declared
|
/* Look inside a declarator for the name being declared
|
||||||
and get it as a string, for an error message. */
|
and get it as a string, for an error message. */
|
||||||
for (id_declarator = declarator;
|
for (id_declarator = declarator;
|
||||||
|
|
@ -10011,6 +10016,16 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
/* We might have ignored or rejected some of the qualifiers. */
|
/* We might have ignored or rejected some of the qualifiers. */
|
||||||
type_quals = cp_type_quals (type);
|
type_quals = cp_type_quals (type);
|
||||||
|
|
||||||
|
if (cxx_dialect >= cxx1z && type && is_auto (type)
|
||||||
|
&& innermost_code != cdk_function
|
||||||
|
&& id_declarator && declarator != id_declarator)
|
||||||
|
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type))
|
||||||
|
{
|
||||||
|
error_at (typespec_loc, "template placeholder type %qT must be followed "
|
||||||
|
"by a simple declarator-id", type);
|
||||||
|
inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", tmpl);
|
||||||
|
}
|
||||||
|
|
||||||
staticp = 0;
|
staticp = 0;
|
||||||
inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline);
|
inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline);
|
||||||
virtualp = decl_spec_seq_has_spec_p (declspecs, ds_virtual);
|
virtualp = decl_spec_seq_has_spec_p (declspecs, ds_virtual);
|
||||||
|
|
@ -10247,12 +10262,7 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
{
|
{
|
||||||
if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type))
|
if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type))
|
||||||
{
|
{
|
||||||
location_t loc;
|
warning_at (typespec_loc, OPT_Wignored_qualifiers, "type "
|
||||||
loc = smallest_type_quals_location (type_quals,
|
|
||||||
declspecs->locations);
|
|
||||||
if (loc == UNKNOWN_LOCATION)
|
|
||||||
loc = declspecs->locations[ds_type_spec];
|
|
||||||
warning_at (loc, OPT_Wignored_qualifiers, "type "
|
|
||||||
"qualifiers ignored on function return type");
|
"qualifiers ignored on function return type");
|
||||||
}
|
}
|
||||||
/* We now know that the TYPE_QUALS don't apply to the
|
/* We now know that the TYPE_QUALS don't apply to the
|
||||||
|
|
@ -10301,11 +10311,12 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id;
|
funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id;
|
||||||
|
|
||||||
/* Handle a late-specified return type. */
|
/* Handle a late-specified return type. */
|
||||||
|
tree late_return_type = declarator->u.function.late_return_type;
|
||||||
if (funcdecl_p)
|
if (funcdecl_p)
|
||||||
{
|
{
|
||||||
if (type_uses_auto (type))
|
if (tree auto_node = type_uses_auto (type))
|
||||||
{
|
{
|
||||||
if (!declarator->u.function.late_return_type)
|
if (!late_return_type)
|
||||||
{
|
{
|
||||||
if (current_class_type
|
if (current_class_type
|
||||||
&& LAMBDA_TYPE_P (current_class_type))
|
&& LAMBDA_TYPE_P (current_class_type))
|
||||||
|
|
@ -10333,8 +10344,32 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
name, type);
|
name, type);
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
|
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
else
|
||||||
|
error_at (typespec_loc, "deduced class type %qT "
|
||||||
|
"in function return type", type);
|
||||||
|
inform (DECL_SOURCE_LOCATION (tmpl),
|
||||||
|
"%qD declared here", tmpl);
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (declarator->u.function.late_return_type
|
else if (late_return_type
|
||||||
&& sfk != sfk_conversion)
|
&& sfk != sfk_conversion)
|
||||||
{
|
{
|
||||||
if (cxx_dialect < cxx11)
|
if (cxx_dialect < cxx11)
|
||||||
|
|
@ -10348,12 +10383,11 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
type = splice_late_return_type
|
type = splice_late_return_type (type, late_return_type);
|
||||||
(type, declarator->u.function.late_return_type);
|
|
||||||
if (type == error_mark_node)
|
if (type == error_mark_node)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
|
|
||||||
if (declarator->u.function.late_return_type)
|
if (late_return_type)
|
||||||
late_return_type_p = true;
|
late_return_type_p = true;
|
||||||
|
|
||||||
if (ctype == NULL_TREE
|
if (ctype == NULL_TREE
|
||||||
|
|
|
||||||
|
|
@ -16596,7 +16596,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
|
||||||
/*ambiguous_decls=*/NULL,
|
/*ambiguous_decls=*/NULL,
|
||||||
token->location);
|
token->location);
|
||||||
if (tmpl && tmpl != error_mark_node
|
if (tmpl && tmpl != error_mark_node
|
||||||
&& DECL_CLASS_TEMPLATE_P (tmpl))
|
&& (DECL_CLASS_TEMPLATE_P (tmpl)
|
||||||
|
|| DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
|
||||||
type = make_template_placeholder (tmpl);
|
type = make_template_placeholder (tmpl);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -20311,26 +20312,35 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg,
|
||||||
&& (!flag_concepts || parser->in_type_id_in_expr_p)
|
&& (!flag_concepts || parser->in_type_id_in_expr_p)
|
||||||
/* None of the valid uses of 'auto' in C++14 involve the type-id
|
/* None of the valid uses of 'auto' in C++14 involve the type-id
|
||||||
nonterminal, but it is valid in a trailing-return-type. */
|
nonterminal, but it is valid in a trailing-return-type. */
|
||||||
&& !(cxx_dialect >= cxx14 && is_trailing_return)
|
&& !(cxx_dialect >= cxx14 && is_trailing_return))
|
||||||
&& type_uses_auto (type_specifier_seq.type))
|
if (tree auto_node = type_uses_auto (type_specifier_seq.type))
|
||||||
{
|
{
|
||||||
/* A type-id with type 'auto' is only ok if the abstract declarator
|
/* A type-id with type 'auto' is only ok if the abstract declarator
|
||||||
is a function declarator with a late-specified return type.
|
is a function declarator with a late-specified return type.
|
||||||
|
|
||||||
A type-id with 'auto' is also valid in a trailing-return-type
|
A type-id with 'auto' is also valid in a trailing-return-type
|
||||||
in a compound-requirement. */
|
in a compound-requirement. */
|
||||||
if (abstract_declarator
|
if (abstract_declarator
|
||||||
&& abstract_declarator->kind == cdk_function
|
&& abstract_declarator->kind == cdk_function
|
||||||
&& abstract_declarator->u.function.late_return_type)
|
&& abstract_declarator->u.function.late_return_type)
|
||||||
/* OK */;
|
/* OK */;
|
||||||
else if (parser->in_result_type_constraint_p)
|
else if (parser->in_result_type_constraint_p)
|
||||||
/* OK */;
|
/* OK */;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error ("invalid use of %<auto%>");
|
location_t loc = type_specifier_seq.locations[ds_type_spec];
|
||||||
return error_mark_node;
|
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
|
||||||
}
|
{
|
||||||
}
|
error_at (loc, "missing template arguments after %qT",
|
||||||
|
auto_node);
|
||||||
|
inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here",
|
||||||
|
tmpl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error_at (loc, "invalid use of %qT", auto_node);
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return groktypename (&type_specifier_seq, abstract_declarator,
|
return groktypename (&type_specifier_seq, abstract_declarator,
|
||||||
is_template_arg);
|
is_template_arg);
|
||||||
|
|
|
||||||
40
gcc/cp/pt.c
40
gcc/cp/pt.c
|
|
@ -13314,7 +13314,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||||
PLACEHOLDER_TYPE_CONSTRAINTS (r)
|
PLACEHOLDER_TYPE_CONSTRAINTS (r)
|
||||||
= tsubst_constraint (constr, args, complain, in_decl);
|
= tsubst_constraint (constr, args, complain, in_decl);
|
||||||
else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t))
|
else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t))
|
||||||
CLASS_PLACEHOLDER_TEMPLATE (r) = pl;
|
{
|
||||||
|
if (DECL_TEMPLATE_TEMPLATE_PARM_P (pl))
|
||||||
|
pl = tsubst (pl, args, complain, in_decl);
|
||||||
|
CLASS_PLACEHOLDER_TEMPLATE (r) = pl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM)
|
if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM)
|
||||||
|
|
@ -24625,13 +24629,23 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
|
||||||
return ded_tmpl;
|
return ded_tmpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deduce template arguments for the class template TMPL based on the
|
/* Deduce template arguments for the class template placeholder PTYPE for
|
||||||
initializer INIT, and return the resulting type. */
|
template TMPL based on the initializer INIT, and return the resulting
|
||||||
|
type. */
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_class_deduction (tree tmpl, tree init, tsubst_flags_t complain)
|
do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain)
|
||||||
{
|
{
|
||||||
gcc_assert (DECL_CLASS_TEMPLATE_P (tmpl));
|
if (!DECL_CLASS_TEMPLATE_P (tmpl))
|
||||||
|
{
|
||||||
|
/* We should have handled this in the caller. */
|
||||||
|
if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
|
||||||
|
return ptype;
|
||||||
|
if (complain & tf_error)
|
||||||
|
error ("non-class template %qT used without template arguments", tmpl);
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
|
|
||||||
tree type = TREE_TYPE (tmpl);
|
tree type = TREE_TYPE (tmpl);
|
||||||
|
|
||||||
vec<tree,va_gc> *args;
|
vec<tree,va_gc> *args;
|
||||||
|
|
@ -24733,7 +24747,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
|
||||||
|
|
||||||
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
|
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
|
||||||
/* C++17 class template argument deduction. */
|
/* C++17 class template argument deduction. */
|
||||||
return do_class_deduction (tmpl, init, complain);
|
return do_class_deduction (type, tmpl, init, complain);
|
||||||
|
|
||||||
/* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto
|
/* [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
|
with either a new invented type template parameter U or, if the
|
||||||
|
|
@ -24881,20 +24895,6 @@ 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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// { dg-do compile { target c++11 } }
|
// { dg-do compile { target c++11 } }
|
||||||
template<typename ... Elements> class Tuple;
|
template<typename ... Elements> class Tuple;
|
||||||
Tuple<>* t; // OK: Elements is empty
|
Tuple<>* t; // OK: Elements is empty
|
||||||
Tuple* u; // { dg-error "template-name" }
|
Tuple* u; // { dg-error "" }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
|
||||||
|
template<class T, class D = int>
|
||||||
|
struct S { T t; };
|
||||||
|
template<class U>
|
||||||
|
S(U) -> S<typename U::type>;
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
using type = short;
|
||||||
|
operator type();
|
||||||
|
};
|
||||||
|
S s{A()}; // OK
|
||||||
|
S x(A()); // { dg-error "return type" }
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
|
||||||
|
template <template <class> class T>
|
||||||
|
void f()
|
||||||
|
{
|
||||||
|
T t = 42; // { dg-error "B" }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
A(T);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> using B = T;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
f<A>();
|
||||||
|
f<B>(); // { dg-message "here" }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
A(T);
|
||||||
|
};
|
||||||
|
|
||||||
|
A a = 42;
|
||||||
|
A *ap = &a; // { dg-error "placeholder" }
|
||||||
|
|
@ -20,7 +20,7 @@ template<template<class> class D,class E> class C
|
||||||
|
|
||||||
template<template<class> class D,class E> int C<D,E>::f()
|
template<template<class> class D,class E> int C<D,E>::f()
|
||||||
{
|
{
|
||||||
return d.f(); // { dg-error "" } d not properly declared
|
return d.f(); // { dg-prune-output "was not declared" }
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue