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>
|
||||
|
||||
* 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
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)
|
||||
= 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;
|
||||
|
||||
|
|
|
@ -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 "" }
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
return d.f(); // { dg-error "" } d not properly declared
|
||||
return d.f(); // { dg-prune-output "was not declared" }
|
||||
}
|
||||
|
||||
int main()
|
||||
|
|
Loading…
Reference in New Issue