diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9325bb0bf3c..87b4cca8468 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2016-01-18 Patrick Palka + + 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 * cp-gimplify.c (cp_fold) [CONSTRUCTOR]: Don't clobber the input. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index df95133f253..187390d2359 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 403c5ac0bea..866b4b1add8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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, diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index d4cf3102a03..e2123ac5179 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index da5bfa931f1..9245b50b567 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,17 @@ +2016-01-18 Patrick Palka + + 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 PR testsuite/69181 diff --git a/gcc/testsuite/g++.dg/template/pr11858.C b/gcc/testsuite/g++.dg/template/pr11858.C new file mode 100644 index 00000000000..dc0d6881393 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/pr11858.C @@ -0,0 +1,5 @@ +// PR c++/11858 + +template struct S { static typename T::x f (); }; // { dg-error "" } +template int f (int [sizeof(T::f())]); +int const i = f >(0); // { dg-error "no matching function" } diff --git a/gcc/testsuite/g++.dg/template/pr24663.C b/gcc/testsuite/g++.dg/template/pr24663.C new file mode 100644 index 00000000000..2dc68c2ed24 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/pr24663.C @@ -0,0 +1,22 @@ +// PR c++/24663 + +template int f1 (char[I]); +template int f1 (char p1 = I); +int i = f1<0>(0); + +template int f2 (T[I]); // { dg-error "" } +int j = f2(0); // { dg-error "no matching function" } +int k = f2(0); // { dg-error "no matching function" } + +int o[5]; +int l = f2(&o); + +template int f3 (char [][I]); +template int f3 (char p1 = I); +int x1 = f3<1>(0); // { dg-error "is ambiguous" } +int x2 = f3<1>(); + +template int f4 (T [][I]); // { dg-error "" } +int y1 = f4(0); // { dg-error "no matching function" } +int y2 = f4(0); // { dg-error "no matching function" } +int y3 = f4(0); // { dg-error "no matching function" } diff --git a/gcc/testsuite/g++.dg/template/unify12.C b/gcc/testsuite/g++.dg/template/unify12.C new file mode 100644 index 00000000000..6e624e41d6a --- /dev/null +++ b/gcc/testsuite/g++.dg/template/unify12.C @@ -0,0 +1,46 @@ +// { dg-do run } +#include + +template int foo (T [I][I]) { return 0; } + +template int foo (char [][6]); + +template +int foo (T *) +{ + return -1; +} + +template +int foo (T [3][3]) +{ + return 1; +} + +template +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); +} diff --git a/gcc/testsuite/g++.dg/template/unify13.C b/gcc/testsuite/g++.dg/template/unify13.C new file mode 100644 index 00000000000..56a46df7ee3 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/unify13.C @@ -0,0 +1,26 @@ +// { dg-do run } +#include + +template int foo (T [I][I]) { return 0; } + +template +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); +} diff --git a/gcc/testsuite/g++.dg/template/unify14.C b/gcc/testsuite/g++.dg/template/unify14.C new file mode 100644 index 00000000000..7fda8fd381a --- /dev/null +++ b/gcc/testsuite/g++.dg/template/unify14.C @@ -0,0 +1,5 @@ +template +void bar (T [X]) { } + +template +void bar (const T [X]) { } diff --git a/gcc/testsuite/g++.dg/template/unify15.C b/gcc/testsuite/g++.dg/template/unify15.C new file mode 100644 index 00000000000..fe4848b998f --- /dev/null +++ b/gcc/testsuite/g++.dg/template/unify15.C @@ -0,0 +1,15 @@ +// { dg-do run } +#include + +template +int bar (T (&) [N]) { return 0; } + +template +int bar (const T (&) [N]) { return 1; } + +int +main () +{ + const int s[2] = { 0 }; + assert (bar (s) == 1); +} diff --git a/gcc/testsuite/g++.dg/template/unify16.C b/gcc/testsuite/g++.dg/template/unify16.C new file mode 100644 index 00000000000..7b5a2aa4692 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/unify16.C @@ -0,0 +1,56 @@ +// { dg-do run } +#include + +template +struct Foo +{ + static int foo (T) { return 0; } +}; + +template +struct Foo +{ + static int foo (T[I]) { return 1; } +}; + +template +struct Foo +{ + static int foo (char[I]) { return 2; } +}; + +template +struct Foo +{ + static int foo (T[5]) { return 3; } +}; + +template <> +struct Foo +{ + static int foo (char[5]) { return 4; } +}; + +template <> +struct Foo +{ + static int foo (const char[5]) { return 5; } +}; + +int a = Foo::foo (0); +int b = Foo::foo (0); +int c = Foo::foo (0); +int d = Foo::foo (0); +int e = Foo::foo (0); +int f = Foo::foo (0); + +int +main (void) +{ + assert (a == 5); + assert (b == 4); + assert (c == 3); + assert (d == 2); + assert (e == 1); + assert (f == 0); +} diff --git a/gcc/testsuite/g++.dg/template/unify17.C b/gcc/testsuite/g++.dg/template/unify17.C new file mode 100644 index 00000000000..2da8553aad8 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/unify17.C @@ -0,0 +1,11 @@ +void foo (int *); + +template +void bar (void (T[5])); // { dg-error "array of 'void'" } + +void +baz (void) +{ + bar (foo); // { dg-bogus "" } + bar (0); // { dg-error "no matching function" } +}