gcc-patches@gcc.gnu.org
[Top] [All Lists]

Re: [PATCH] Fix PR c++/19989 (4.0/4.1 regression)

Subject: Re: [PATCH] Fix PR c++/19989 4.0/4.1 regression
From: Josh Conner
Date: Thu, 03 Nov 2005 09:34:57 -0800
Gabriel Dos Reis wrote:
> Josh Conner <jconner@xxxxxxxxx> writes:
> 
> | The attached patches fix PR c++/19989 on the 4.0 and 4.1 branches.
> | Without this fix, code of this form is rejected:
> | 
> |   template<int> struct A
> |   {
> |     static const int i = 0;
> |   };
> | 
> |   template<int N> struct B
> |   {
> |     int x[A<N>::i];
> |   };
> | 
> |   B<0> b;
> | 
> | It was rejected because template instantiation was being conservative in
> | not allowing zero-sized arrays, to avoid (correctly) something like this
> | from also being accepted:
> | 
> |   template<int M> void foobar (int (*) [M] = 0 );
> | 
> |   void fn (void)
> |   {
> |     foobar<0>();
> |   }
> | 
> | Fortunately, we can distinguish between these instances in this code by
> | looking at the complain variable -- when we're committed to applying a
> | template (as in the first case), tf_error will be set.
> 
> I'm nervous about this sort of extensions that change function
> overload set -- especially for *conforming* programs, where such
> constructs can happen in the preliminary stage of what is called
> SFINAE.  I would like to see more testcases that cover corner cases.

OK.  So, the problem domain we're concerned with is function template
instantiation that results in the declaration of an array of size zero.
 In all of these cases, substitution must fail in order to be
conformant.  If there are other cases to consider, please let me know.

The test case I included in my patch that covers this space is:

  TEST #1
  ~~~~~~~
  template<int M> void foobar (int (*) [M] = 0 );
  template<int M> void foobar ( );

  void fn (void)
  {
    foobar<0>();
    foobar<-1>();
  }

Which should compile without error only if the first pattern fails to
instantiate.

Trying to look at a unit-testing level, since the code's behavior is
dependent on the 'complain' variable, here's an example that mixes up
class and function template instantiations:

  TEST #2
  ~~~~~~~
  template<int T> struct cl {
    const static int value = T;
  };

  template<int I> void fn (char (*) [cl<I>::value] = 0 );

  void foo (void)
  {
    fn<0> ();  // { dg-error "no matching function" }
  }

This test behaves correctly with my patch.

Looking at a compliance-testing level, here is another example that
should fail to compile:

  TEST #3
  ~~~~~~~
  template<int I> int f1 (char[I]);
  template<class T, int I> int f2 (T[I]);

  int i = f1<0>(0);  // { dg-error "no matching function" }
  int j = f2<char, 0>(0);  // { dg-error "no matching function" }

However, gcc incorrectly succeeds, perhaps because it is performing the
type[size] --> type * conversion too early, as prohibited by 14.8.2.3:

  After this substitution is performed, the function parameter type
  adjustments described in 8.3.5 are performed. [Example: A parameter
  type of “void ()(const int, int[5])” becomes “void(*)(int,int*)”.

Finally, one other incompliance I noticed during my testing, but which
is not related to my patch, was this:

  TEST #4
  ~~~~~~~
  template<class T> int f(T[5]);
  int j = f<void>(0);

This code is pulled directly from an example in the standard, and it
incorrectly succeeds both before and after the proposed patch.

So, I propose to:

1) Add test #2 to my patch
2) Install my patch
3) File a bug report on tests #3 and #4

OK?

- Josh

<Prev in Thread] Current Thread [Next in Thread>