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:
Jason Merrill 2016-11-09 15:02:56 -05:00 committed by Jason Merrill
parent 4a826ca6fe
commit e922b25690
9 changed files with 150 additions and 54 deletions

View File

@ -1,5 +1,13 @@
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.
* cp-tree.h (enum auto_deduction_context): Add adc_unify.
* decl.c (grokdeclarator): Allow 'auto' in C++17 template non-type

View File

@ -9490,6 +9490,11 @@ grokdeclarator (const cp_declarator *declarator,
if (initialized > 1)
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
and get it as a string, for an error message. */
for (id_declarator = declarator;
@ -10011,6 +10016,16 @@ grokdeclarator (const cp_declarator *declarator,
/* We might have ignored or rejected some of the qualifiers. */
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;
inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline);
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))
{
location_t loc;
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 "
warning_at (typespec_loc, OPT_Wignored_qualifiers, "type "
"qualifiers ignored on function return type");
}
/* 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;
/* Handle a late-specified return type. */
tree late_return_type = declarator->u.function.late_return_type;
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
&& LAMBDA_TYPE_P (current_class_type))
@ -10333,8 +10344,32 @@ grokdeclarator (const cp_declarator *declarator,
name, type);
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)
{
if (cxx_dialect < cxx11)
@ -10348,12 +10383,11 @@ grokdeclarator (const cp_declarator *declarator,
return error_mark_node;
}
}
type = splice_late_return_type
(type, declarator->u.function.late_return_type);
type = splice_late_return_type (type, late_return_type);
if (type == error_mark_node)
return error_mark_node;
if (declarator->u.function.late_return_type)
if (late_return_type)
late_return_type_p = true;
if (ctype == NULL_TREE

View File

@ -16596,7 +16596,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
/*ambiguous_decls=*/NULL,
token->location);
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);
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)
/* None of the valid uses of 'auto' in C++14 involve the type-id
nonterminal, but it is valid in a trailing-return-type. */
&& !(cxx_dialect >= cxx14 && is_trailing_return)
&& type_uses_auto (type_specifier_seq.type))
{
/* A type-id with type 'auto' is only ok if the abstract declarator
is a function declarator with a late-specified return type.
&& !(cxx_dialect >= cxx14 && is_trailing_return))
if (tree auto_node = type_uses_auto (type_specifier_seq.type))
{
/* A type-id with type 'auto' is only ok if the abstract declarator
is a function declarator with a late-specified return type.
A type-id with 'auto' is also valid in a trailing-return-type
in a compound-requirement. */
if (abstract_declarator
&& abstract_declarator->kind == cdk_function
&& abstract_declarator->u.function.late_return_type)
/* OK */;
else if (parser->in_result_type_constraint_p)
/* OK */;
else
{
error ("invalid use of %<auto%>");
return error_mark_node;
}
}
A type-id with 'auto' is also valid in a trailing-return-type
in a compound-requirement. */
if (abstract_declarator
&& abstract_declarator->kind == cdk_function
&& abstract_declarator->u.function.late_return_type)
/* OK */;
else if (parser->in_result_type_constraint_p)
/* OK */;
else
{
location_t loc = type_specifier_seq.locations[ds_type_spec];
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,
is_template_arg);

View File

@ -13314,7 +13314,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
PLACEHOLDER_TYPE_CONSTRAINTS (r)
= tsubst_constraint (constr, args, complain, in_decl);
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)
@ -24625,13 +24629,23 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
return ded_tmpl;
}
/* Deduce template arguments for the class template TMPL based on the
initializer INIT, and return the resulting type. */
/* Deduce template arguments for the class template placeholder PTYPE for
template TMPL based on the initializer INIT, and return the resulting
type. */
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);
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))
/* 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
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 (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)
return late_return_type;

View File

@ -1,4 +1,4 @@
// { dg-do compile { target c++11 } }
template<typename ... Elements> class Tuple;
Tuple<>* t; // OK: Elements is empty
Tuple* u; // { dg-error "template-name" }
Tuple* u; // { dg-error "" }

View File

@ -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" }

View File

@ -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" }
}

View File

@ -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" }

View File

@ -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()
{
return d.f(); // { dg-error "" } d not properly declared
return d.f(); // { dg-prune-output "was not declared" }
}
int main()