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
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;
/* 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);
{
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
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))
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)
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
/*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
{
&& (!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.
-
- 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;
- }
- }
+ && !(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
+ {
+ 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);
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)
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;
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
{
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;
// { 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 "" }
--- /dev/null
+// { 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" }
--- /dev/null
+// { 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" }
+}
--- /dev/null
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+ A(T);
+};
+
+A a = 42;
+A *ap = &a; // { dg-error "placeholder" }
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()