Commit 44780b91 by Alexandre Oliva Committed by Alexandre Oliva

[PR c++/84979] reject auto in explicit tmpl args for tmpl-fn

With concepts, we accept auto in explicit template arguments, but we
should only accept them for template classes.  Passing them to
template functions or variables is not allowed.  So, reject it, at
parse time if possible, at specialization time otherwise.


for  gcc/cp/ChangeLog

	PR c++/84979
	* pt.c (check_auto_in_tmpl_args): New.
	(tsubst_qualified_id): Use it to reject template args
	referencing auto for non-type templates.
	* parser.c (cp_parser_template_id): Likewise.
	* cp-tree.h (check_auto_in_tmpl_args): Declare.
	* typeck2.c (build_functional_cast): Report correct location
	for invalid use of auto.

for  gcc/testsuite/ChangeLog

	PR c++/84979
	* g++.dg/concepts/pr84979.C: New.
	* g++.dg/concepts/pr84979-2.C: New.
	* g++.dg/concepts/pr84979-3.C: New.

From-SVN: r259124
parent da0c8d97
2018-04-05 Alexandre Oliva <aoliva@redhat.com>
PR c++/84979
* pt.c (check_auto_in_tmpl_args): New.
(tsubst_qualified_id): Use it to reject template args
referencing auto for non-type templates.
* parser.c (cp_parser_template_id): Likewise.
* cp-tree.h (check_auto_in_tmpl_args): Declare.
* typeck2.c (build_functional_cast): Report correct location
for invalid use of auto.
2018-04-04 Jason Merrill <jason@redhat.com>
PR c++/85215 - ICE with copy-init from conversion.
......
......@@ -6500,6 +6500,7 @@ extern void maybe_show_extern_c_location (void);
/* in pt.c */
extern bool check_template_shadow (tree);
extern bool check_auto_in_tmpl_args (tree, tree);
extern tree get_innermost_template_args (tree, int);
extern void maybe_begin_member_template_processing (tree);
extern void maybe_end_member_template_processing (void);
......
......@@ -15826,8 +15826,16 @@ cp_parser_template_id (cp_parser *parser,
location_t combined_loc
= make_location (token->location, token->location, finish_loc);
/* Check for concepts autos where they don't belong. We could
identify types in some cases of idnetifier TEMPL, looking ahead
for a CPP_SCOPE, but that would buy us nothing: we accept auto in
types. We reject them in functions, but if what we have is an
identifier, even with none_type we can't conclude it's NOT a
type, we have to wait for template substitution. */
if (flag_concepts && check_auto_in_tmpl_args (templ, arguments))
template_id = error_mark_node;
/* Build a representation of the specialization. */
if (identifier_p (templ))
else if (identifier_p (templ))
template_id = build_min_nt_loc (combined_loc,
TEMPLATE_ID_EXPR,
templ, arguments);
......@@ -14906,6 +14906,15 @@ tsubst_qualified_id (tree qualified_id, tree args,
if (is_template)
{
/* We may be repeating a check already done during parsing, but
if it was well-formed and passed then, it will pass again
now, and if it didn't, we wouldn't have got here. The case
we want to catch is when we couldn't tell then, and can now,
namely when templ prior to substitution was an
identifier. */
if (flag_concepts && check_auto_in_tmpl_args (expr, template_args))
return error_mark_node;
if (variable_template_p (expr))
expr = lookup_and_finish_template_variable (expr, template_args,
complain);
......@@ -26550,6 +26559,49 @@ type_uses_auto (tree type)
return find_type_usage (type, is_auto);
}
/* Report ill-formed occurrences of auto types in ARGUMENTS. If
concepts are enabled, auto is acceptable in template arguments, but
only when TEMPL identifies a template class. Return TRUE if any
such errors were reported. */
bool
check_auto_in_tmpl_args (tree tmpl, tree args)
{
/* If there were previous errors, nevermind. */
if (!args || TREE_CODE (args) != TREE_VEC)
return false;
/* If TMPL is an identifier, we're parsing and we can't tell yet
whether TMPL is supposed to be a type, a function or a variable.
We'll only be able to tell during template substitution, so we
expect to be called again then. If concepts are enabled and we
know we have a type, we're ok. */
if (flag_concepts
&& (identifier_p (tmpl)
|| (DECL_P (tmpl)
&& (DECL_TYPE_TEMPLATE_P (tmpl)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))))
return false;
/* Quickly search for any occurrences of auto; usually there won't
be any, and then we'll avoid allocating the vector. */
if (!type_uses_auto (args))
return false;
bool errors = false;
tree vec = extract_autos (args);
for (int i = 0; i < TREE_VEC_LENGTH (vec); i++)
{
tree xauto = TREE_VALUE (TREE_VEC_ELT (vec, i));
error_at (DECL_SOURCE_LOCATION (xauto),
"invalid use of %qT in template argument", xauto);
errors = true;
}
return errors;
}
/* For a given template T, return the vector of typedefs referenced
in T for which access check is needed at T instantiation time.
T is either a FUNCTION_DECL or a RECORD_TYPE.
......
......@@ -2081,7 +2081,8 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
if (!CLASS_PLACEHOLDER_TEMPLATE (anode))
{
if (complain & tf_error)
error ("invalid use of %qT", anode);
error_at (DECL_SOURCE_LOCATION (TEMPLATE_TYPE_DECL (anode)),
"invalid use of %qT", anode);
return error_mark_node;
}
else if (!parms)
......
2018-04-05 Alexandre Oliva <aoliva@redhat.com>
PR c++/84979
* g++.dg/concepts/pr84979.C: New.
* g++.dg/concepts/pr84979-2.C: New.
* g++.dg/concepts/pr84979-3.C: New.
2018-04-04 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/80026
......
// { dg-do compile { target c++11 } }
// { dg-options "-fconcepts" }
template <typename T>
void foo1(T& t) {
typename T::template C<void> tcv = t;
typename T::template C<auto> u = tcv;
T::template C<auto>::f (tcv, u); // { dg-error "incomplete" }
(typename T::template D<auto> (t)); // { dg-error "invalid" }
}
struct T1 {
template <typename T> struct C {
C(T1&);
static void f(T1&, C&);
};
template <typename T> struct D {
D(T1&);
};
};
template <typename T>
void foo2(T& t) {
typename T::template C<void> tcv = t;
typename T::template C<auto> u = tcv;
T::template C<auto>::f (tcv, u); // { dg-error "incomplete" }
T::template D<auto> (t); // { dg-error "invalid" }
}
struct T2 {
template <typename T> struct C {
C(T2&);
static void f(T2&, C&);
};
template <typename T> static void D(T2&);
};
void f(T1& t1, T2& t2) {
foo1 (t1);
foo2 (t2);
}
// { dg-do compile { target c++11 } }
// { dg-options "-fconcepts" }
// This is like pr84979-2.C, except that we swap the types passed to
// the template functions foo1 and foo2, so that the expectations WRT
// D's typeness are not met.
template <typename T>
void foo1(T& t) {
typename T::template C<void> tcv = t;
typename T::template C<auto> u = tcv;
T::template C<auto>::f (tcv, u); // { dg-error "incomplete" }
(typename T::template D<auto> (t)); // { dg-error "invalid" }
}
struct T1 {
template <typename T> struct C {
C(T1&);
static void f(T1&, C&);
};
template <typename T> struct D {
D(T1&);
};
};
template <typename T>
void foo2(T& t) {
typename T::template C<void> tcv = t;
typename T::template C<auto> u = tcv;
T::template C<auto>::f (tcv, u); // { dg-error "incomplete" }
T::template D<auto> (t); // { dg-error "yields a type" }
}
struct T2 {
template <typename T> struct C {
C(T2&);
static void f(T2&, C&);
};
template <typename T> static void D(T2&);
};
void f(T1& t1, T2& t2) {
foo1 (t2);
foo2 (t1);
}
// { dg-do compile { target c++11 } }
// { dg-options "-fconcepts" }
template<typename> void foo() {}
void bar()
{
foo<auto>(); // { dg-error "invalid" }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment