Fix the remaining PR c++/24666 blockers (arrays decay to pointers too early)

gcc/cp/ChangeLog:

	PR c++/11858
	PR c++/24663
	PR c++/24664
	* decl.c (grokdeclarator): Don't decay array parameter type to
	a pointer type if it's dependent.
	(grokparms): Invoke strip_top_quals instead of directly invoking
	cp_build_qualified_type.
	* pt.c (decay_dependent_array_parm_type): New static function.
	(type_unification_real): Call decay_dependent_array_parm_type
	to decay a dependent array parameter type to its corresponding
	pointer type before unification.
	(more_specialized_fn): Likewise.
	(get_bindings): Likewise.
	* tree.c (cp_build_qualified_type): Trivial typofix in
	documentation.

gcc/testsuite/ChangeLog:

	PR c++/11858
	PR c++/24663
	PR c++/24664
	* g++.dg/template/pr11858.C: New test.
	* g++.dg/template/pr24663.C: New test.
	* g++.dg/template/unify12.C: New test.
	* g++.dg/template/unify13.C: New test.
	* g++.dg/template/unify14.C: New test.
	* g++.dg/template/unify15.C: New test.
	* g++.dg/template/unify16.C: New test.
	* g++.dg/template/unify17.C: New test.

From-SVN: r232547
This commit is contained in:
Patrick Palka 2016-01-19 00:19:16 +00:00
parent 49f8a19186
commit 17c15cb932
13 changed files with 254 additions and 5 deletions

View File

@ -1,3 +1,21 @@
2016-01-18 Patrick Palka <ppalka@gcc.gnu.org>
PR c++/11858
PR c++/24663
PR c++/24664
* decl.c (grokdeclarator): Don't decay array parameter type to
a pointer type if it's dependent.
(grokparms): Invoke strip_top_quals instead of directly invoking
cp_build_qualified_type.
* pt.c (decay_dependent_array_parm_type): New static function.
(type_unification_real): Call decay_dependent_array_parm_type
to decay a dependent array parameter type to its corresponding
pointer type before unification.
(more_specialized_fn): Likewise.
(get_bindings): Likewise.
* tree.c (cp_build_qualified_type): Trivial typofix in
documentation.
2016-01-18 Jason Merrill <jason@redhat.com>
* cp-gimplify.c (cp_fold) [CONSTRUCTOR]: Don't clobber the input.

View File

@ -10898,8 +10898,13 @@ grokdeclarator (const cp_declarator *declarator,
if (TREE_CODE (type) == ARRAY_TYPE)
{
/* Transfer const-ness of array into that of type pointed to. */
type = build_pointer_type (TREE_TYPE (type));
/* Withhold decaying a dependent array type so that that during
instantiation we can detect type deduction failure cases such as
creating an array of void, creating a zero-size array, etc. */
if (dependent_type_p (type))
;
else
type = build_pointer_type (TREE_TYPE (type));
type_quals = TYPE_UNQUALIFIED;
array_parameter_p = true;
}
@ -11696,7 +11701,8 @@ grokparms (tree parmlist, tree *parms)
/* Top-level qualifiers on the parameters are
ignored for function types. */
type = cp_build_qualified_type (type, 0);
type = strip_top_quals (type);
if (TREE_CODE (type) == METHOD_TYPE)
{
error ("parameter %qD invalidly declared method type", decl);

View File

@ -17729,6 +17729,23 @@ fn_type_unification (tree fn,
return r;
}
/* TYPE is the type of a function parameter. If TYPE is a (dependent)
ARRAY_TYPE, return the corresponding POINTER_TYPE to which it decays.
Otherwise return TYPE. (We shouldn't see non-dependent ARRAY_TYPE
parameters because they get decayed as soon as they are declared.) */
static tree
decay_dependent_array_parm_type (tree type)
{
if (TREE_CODE (type) == ARRAY_TYPE)
{
gcc_assert (uses_template_parms (type));
return type_decays_to (type);
}
return type;
}
/* Adjust types before performing type deduction, as described in
[temp.deduct.call] and [temp.deduct.conv]. The rules in these two
sections are symmetric. PARM is the type of a function parameter
@ -18167,6 +18184,8 @@ type_unification_real (tree tparms,
arg = args[ia];
++ia;
parm = decay_dependent_array_parm_type (parm);
if (unify_one_argument (tparms, targs, parm, arg, subr, strict,
explain_p))
return 1;
@ -20169,6 +20188,9 @@ more_specialized_fn (tree pat1, tree pat2, int len)
len = 0;
}
arg1 = decay_dependent_array_parm_type (arg1);
arg2 = decay_dependent_array_parm_type (arg2);
if (TREE_CODE (arg1) == REFERENCE_TYPE)
{
ref1 = TYPE_REF_IS_RVALUE (arg1) + 1;
@ -20454,7 +20476,10 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
for (arg = decl_arg_types, ix = 0;
arg != NULL_TREE && arg != void_list_node;
arg = TREE_CHAIN (arg), ++ix)
args[ix] = TREE_VALUE (arg);
{
args[ix] = TREE_VALUE (arg);
args[ix] = decay_dependent_array_parm_type (args[ix]);
}
if (fn_type_unification (fn, explicit_args, targs,
args, ix,

View File

@ -1012,7 +1012,7 @@ c_build_qualified_type (tree type, int type_quals, tree /* orig_qual_type */,
arrays correctly. In particular, if TYPE is an array of T's, and
TYPE_QUALS is non-empty, returns an array of qualified T's.
FLAGS determines how to deal with ill-formed qualifications. If
COMPLAIN determines how to deal with ill-formed qualifications. If
tf_ignore_bad_quals is set, then bad qualifications are dropped
(this is permitted if TYPE was introduced via a typedef or template
type parameter). If bad qualifications are dropped and tf_warning

View File

@ -1,3 +1,17 @@
2016-01-18 Patrick Palka <ppalka@gcc.gnu.org>
PR c++/11858
PR c++/24663
PR c++/24664
* g++.dg/template/pr11858.C: New test.
* g++.dg/template/pr24663.C: New test.
* g++.dg/template/unify12.C: New test.
* g++.dg/template/unify13.C: New test.
* g++.dg/template/unify14.C: New test.
* g++.dg/template/unify15.C: New test.
* g++.dg/template/unify16.C: New test.
* g++.dg/template/unify17.C: New test.
2016-01-18 David Malcolm <dmalcolm@redhat.com>
PR testsuite/69181

View File

@ -0,0 +1,5 @@
// PR c++/11858
template <typename T> struct S { static typename T::x f (); }; // { dg-error "" }
template <class T> int f (int [sizeof(T::f())]);
int const i = f<S<int> >(0); // { dg-error "no matching function" }

View File

@ -0,0 +1,22 @@
// PR c++/24663
template<int I> int f1 (char[I]);
template<int I> int f1 (char p1 = I);
int i = f1<0>(0);
template<typename T, int I> int f2 (T[I]); // { dg-error "" }
int j = f2<int, 0>(0); // { dg-error "no matching function" }
int k = f2<void, 1>(0); // { dg-error "no matching function" }
int o[5];
int l = f2<int[5], 1>(&o);
template<int I> int f3 (char [][I]);
template<int I> int f3 (char p1 = I);
int x1 = f3<1>(0); // { dg-error "is ambiguous" }
int x2 = f3<1>();
template<typename T, int I> int f4 (T [][I]); // { dg-error "" }
int y1 = f4<void, 1>(0); // { dg-error "no matching function" }
int y2 = f4<int (void), 1>(0); // { dg-error "no matching function" }
int y3 = f4<int&, 1>(0); // { dg-error "no matching function" }

View File

@ -0,0 +1,46 @@
// { dg-do run }
#include <cassert>
template<typename T, int I> int foo (T [I][I]) { return 0; }
template int foo (char [][6]);
template <typename T>
int foo (T *)
{
return -1;
}
template <typename T>
int foo (T [3][3])
{
return 1;
}
template <int I>
int foo (bool [I][I])
{
return 2;
}
template <>
int foo (bool [3][2])
{
return 3;
}
char x[3];
bool y[4];
bool z[3][2];
int a = foo (&x);
int b = foo (&y);
int c = foo (z);
int
main ()
{
assert (a == 1);
assert (b == 2);
assert (c == 3);
}

View File

@ -0,0 +1,26 @@
// { dg-do run }
#include <cassert>
template<typename T, int I> int foo (T [I][I]) { return 0; }
template<typename T>
int foo (T [3][2])
{
return 1;
}
template <>
int foo (bool [3][2])
{
return 2;
}
bool z[3][2];
int a = foo (z);
int
main ()
{
assert (a == 2);
}

View File

@ -0,0 +1,5 @@
template <typename T, int X>
void bar (T [X]) { }
template <typename T, int X>
void bar (const T [X]) { }

View File

@ -0,0 +1,15 @@
// { dg-do run }
#include <cassert>
template <typename T, int N>
int bar (T (&) [N]) { return 0; }
template <typename T, int N>
int bar (const T (&) [N]) { return 1; }
int
main ()
{
const int s[2] = { 0 };
assert (bar (s) == 1);
}

View File

@ -0,0 +1,56 @@
// { dg-do run }
#include <cassert>
template <typename T>
struct Foo
{
static int foo (T) { return 0; }
};
template <typename T, int I>
struct Foo<T[I]>
{
static int foo (T[I]) { return 1; }
};
template <int I>
struct Foo<char[I]>
{
static int foo (char[I]) { return 2; }
};
template <typename T>
struct Foo<T[5]>
{
static int foo (T[5]) { return 3; }
};
template <>
struct Foo<char[5]>
{
static int foo (char[5]) { return 4; }
};
template <>
struct Foo<const char[5]>
{
static int foo (const char[5]) { return 5; }
};
int a = Foo<const char[5]>::foo (0);
int b = Foo<char[5]>::foo (0);
int c = Foo<bool[5]>::foo (0);
int d = Foo<char[4]>::foo (0);
int e = Foo<bool[4]>::foo (0);
int f = Foo<char[]>::foo (0);
int
main (void)
{
assert (a == 5);
assert (b == 4);
assert (c == 3);
assert (d == 2);
assert (e == 1);
assert (f == 0);
}

View File

@ -0,0 +1,11 @@
void foo (int *);
template <typename T>
void bar (void (T[5])); // { dg-error "array of 'void'" }
void
baz (void)
{
bar (foo); // { dg-bogus "" }
bar<void> (0); // { dg-error "no matching function" }
}