Bug 13967

Summary: A warning could be emitted if a template parameter of a member template is begin shadowed by another member of the class
Product: gcc Reporter: gianni
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: enhancement CC: fang, gcc-bugs, gcc-bugs, gianni, giovannibajo, igodard, jwakely.gcc, martindorey, pinskia
Priority: P2 Keywords: diagnostic
Version: 3.4.0   
Target Milestone: ---   
Host: Target:
Build: Known to work: 3.2.3
Known to fail: 3.4.0 4.0.0 Last reconfirmed: 2005-09-18 02:03:18

Description gianni 2004-02-01 23:34:01 UTC
The code below, compiles fine on MSVC++ 7.1 and Comeau.
It seems that the fix for Bug 13808 is not complete as the 
scoping of template parameters is not taken into account 
before identifies in the anclosing class's template.


gccbug_13808.cpp: In member function `C<T, A> X::Func()':
gccbug_13808.cpp:10: error: `X::C' is not a template

struct X
{
    struct C { int x; }; //uncomment to make this work.
    struct Z { int x; }; //uncomment to make this work.

    template<typename T,  typename A, template<typename,typename> class C>
    C<T, A> Func()
    {
        return C<T, A>(); // sees X::C not template parameter
    }

    template< typename Z > Z Zunc()
    {
        return Z(); // works ok
    }

};
Comment 1 gianni 2004-02-01 23:43:45 UTC
Cut-n-pasted too many comments ... the example should look like this.

struct X
{
    struct C { int x; };
    struct Z { int x; };

    template<typename T,  typename A, template<typename,typename> class C>
    C<T, A> Func()
    {
        return C<T, A>(); // sees X::C not template parameter
    }

    template< typename Z > Z Zunc()
    {
        return Z(); // works ok
    }

};
Comment 2 gianni 2004-02-02 00:11:14 UTC
I lied :
> ... compiles fine on MSVC++ 7.1 and Comeau.

The truth is:
It compiles fine on Comeau it triggers an internal compiler error on MSVC++v7.1.

(when I was testing 13808 I had a (mistaken) memory of it compiling fine).

Nonetheless - it's still a boog.

I also thought that the struct Z code in my first example is meaningless so I
tried this and it proves to be that the second example is also looking up
symbols incorrectly.

struct X
{
    struct C { int x; };
    class Z { Z(int){} };

    template<typename T,  typename A, template<typename,typename> class C>
    C<T, A> Func()
    {
        return C<T, A>();
    }

    template< typename Z > Z Zunc()
    {
        return Z(); // this should be template parameter Z
    }

    template< typename Z > void Zinc()
    {
//        X::Z(); // this should not work
    }

    void tst()
    {
        Zunc<int>();

        Zinc<int>();
    }

};

Comeau still likes this example - MSVC++7.1 still crashes and burns on this.
Comment 3 Giovanni Bajo 2004-02-02 00:42:26 UTC
Yes, it's a regression too. The final testcase which should be accepted is the 
following:

-------------------------------------------------------------------
struct X
{
  struct C { int x; };
  struct Z { Z(float); };

  template<typename T,  typename A, template<typename,typename> class C>
    C<T, A> Func()
  {
    return C<T, A>(); // sees X::C not template parameter
  }

  template< typename Z > Z Zunc()
  {
    return Z(); // works ok
  }

  void foo(void)
  {
    Zunc<int>();
  }
};
-------------------------------------------------------------------
pr13967.cpp: In member function `C<T, A> X::Func()':
pr13967.cpp:9: error: `X::C' is not a template
pr13967.cpp: In member function `Z X::Zunc() [with Z = int]':
pr13967.cpp:19:   instantiated from here
pr13967.cpp:14: error: no matching function for call to `X::Z::Z()'
pr13967.cpp:4: note: candidates are: X::Z::Z(const X::Z&)
pr13967.cpp:4: note:                 X::Z::Z(float)

Comment 4 Gabriel Dos Reis 2004-02-02 01:02:22 UTC
Subject: Re:  template template argument identifier lookup fails scoping rules

"gianni at mariani dot ws" <gcc-bugzilla@gcc.gnu.org> writes:

| I lied :
| > ... compiles fine on MSVC++ 7.1 and Comeau.
| 
| The truth is:
| It compiles fine on Comeau it triggers an internal compiler error on MSVC++v7.1.
| 
| (when I was testing 13808 I had a (mistaken) memory of it compiling fine).
| 
| Nonetheless - it's still a boog.

Where? in como or in GCC?  Member functions defined in a class
definition get rewritten as if they were defined outside of the class.
And it is clear that when you rewrite the function outside of the
class definition (which is what GCC does), then you find X::C, not the
template parameter.

-- Gaby
Comment 5 gianni 2004-02-02 01:18:01 UTC
 Gabriel Dos Reis writes:
|| Nonetheless - it's still a boog.
|
|Where? in como or in GCC?

.. I believe it's GCC that gets it wrong.


| ..  Member functions defined in a class
| definition get rewritten as if they were defined outside of the class.
| And it is clear that when you rewrite the function outside of the
| class definition (which is what GCC does), then you find X::C, not the
| template parameter.

But when it gets expanded, there should be no "X::C" symbol in the template
whatsoever as this is should be substituted with the template parameter.  Did I
miss somthing ?


Comment 6 Gabriel Dos Reis 2004-02-02 01:31:57 UTC
Subject: Re:  [3.3?/3.4/3.5 regression] template template argument identifier lookup fails scoping rules

"gianni at mariani dot ws" <gcc-bugzilla@gcc.gnu.org> writes:

|  Gabriel Dos Reis writes:
| || Nonetheless - it's still a boog.
| |
| |Where? in como or in GCC?
| 
| .. I believe it's GCC that gets it wrong.

If there is a bug in GCC, I think it is only about the wording of the
diagnostic, not the fact of rejecting the code.   

| | ..  Member functions defined in a class
| | definition get rewritten as if they were defined outside of the class.
| | And it is clear that when you rewrite the function outside of the
| | class definition (which is what GCC does), then you find X::C, not the
| | template parameter.
| 
| But when it gets expanded, there should be no "X::C" symbol in the template
| whatsoever as this is should be substituted with the template parameter.  Did I
| miss somthing ?

I'm not talking about the instantiation.  I'm talking about the
definition. E.g. when you write

   struct X
   {
     struct C { int x; };

     template<typename T,  typename A, template<typename,typename> class C>
       C<T, A> Func()
     {
       return C<T, A>();
     }
   };

It gets rewritten as

  struct X
  {
     struct C;
     template<class T, class A, template<class, class> class C>
     C<T, A> Func();
  };

  struct A::C { int x; };

  template<class T, class A, template<class, class> class C>
  C<T, A> X::Func()
  {
    return C<T, A>();   // #1
  }

and at line #1, the standard says that X::C should be found.

-- Gaby
Comment 7 gianni 2004-02-02 01:49:10 UTC
Gabriel Dos Reis writes:
| ... and at line #1, the standard says that X::C should be found.

I don't get what you're trying to say.

Fact: If X::C does not exist then the function compiles correctly in gcc 3.4.

So I'm confused as to what you mean "should be found".  Can you cite the standard ?


Comment 8 Gabriel Dos Reis 2004-02-02 02:18:40 UTC
Subject: Re:  [3.3?/3.4/3.5 regression] template template argument identifier lookup fails scoping rules

"gianni at mariani dot ws" <gcc-bugzilla@gcc.gnu.org> writes:

| ------- Additional Comments From gianni at mariani dot ws  2004-02-02 01:49 -------
| Gabriel Dos Reis writes:
| | ... and at line #1, the standard says that X::C should be found.
| 
| I don't get what you're trying to say.

Exactly which part confuses you?

| Fact: If X::C does not exist then the function compiles correctly in
| gcc 3.4. 

Yes, that is correct.

| So I'm confused as to what you mean "should be found".  Can you cite
| the standard ? 

What I meant is this:

  struct X {
      int C;

      template<class> void func(); 
  }; 


  template<class C>
    void X::func()
    {
       C c;     // ERROR: C is not a type.
    }

In the definition of X::func(), lookup for C will find X::C instead of
the template parameter.  In the example you gave, X::C is a
non-template, so it will cause an error -- because the function gets
rewritten out of the class definition..  

-- Gaby
Comment 9 gianni 2004-02-02 03:00:51 UTC
Gabriel Dos Reis writes:
|
|| So I'm confused as to what you mean "should be found".  Can you cite
|| the standard ? 
|
| What I meant is this:
|
|  struct X {
|      int C;
|
|      template<class> void func(); 
|  }; 
|
|
|  template<class C>
|    void X::func()
|    {
|       C c;     // ERROR: C is not a type.
|    }
|
| In the definition of X::func(), lookup for C will find X::C instead of
| the template parameter. 

Yes - but is this the behaviour as specified in the standard ?  At first glance,
it seems like the gcc behaviour is probably wrong.


Comment 10 Gabriel Dos Reis 2004-02-02 17:32:49 UTC
Subject: Re:  New: template template argument identifier lookup fails scoping rules

"gianni at mariani dot ws" <gcc-bugzilla@gcc.gnu.org> writes:

| The code below, compiles fine on MSVC++ 7.1 and Comeau.
| It seems that the fix for Bug 13808 is not complete as the 
| scoping of template parameters is not taken into account 
| before identifies in the anclosing class's template.

Well, I don't think GCC is in error.  When you define a function (or a
class) in a class, it gets rewritten as if it where defined outside of
the class (which is why we get the reevaluation rule I pointed you to
in a different PR).  Now, when you reevaluate the member template
outside of the class, name lookup is required to find X::C -- see 
14.6.1/5 and 14.6.1/7

-- Gaby
Comment 11 Gabriel Dos Reis 2004-02-02 17:40:08 UTC
Subject: Re:  [3.3?/3.4/3.5 regression] template template argument identifier lookup fails scoping rules

"gianni at mariani dot ws" <gcc-bugzilla@gcc.gnu.org> writes:

| Gabriel Dos Reis writes:
| |
| || So I'm confused as to what you mean "should be found".  Can you cite
| || the standard ? 
| |
| | What I meant is this:
| |
| |  struct X {
| |      int C;
| |
| |      template<class> void func(); 
| |  }; 
| |
| |
| |  template<class C>
| |    void X::func()
| |    {
| |       C c;     // ERROR: C is not a type.
| |    }
| |
| | In the definition of X::func(), lookup for C will find X::C instead of
| | the template parameter. 
| 
| Yes - but is this the behaviour as specified in the standard ? 

I just checked with the Core group and John Spicer recalled that the
committee madethe general decision that a class-member hides a
template-parameter. See the implementation of that decision in
14.6.1/5 and 14.6.1/7.  

| At first glance, it seems like the gcc behaviour is probably wrong.

But, GCC behaviour is Right :-)

The fundamental issue is that template-parameters can be renamed and
you don't want to depend on that.  Consider

   template<class T>
      struct X {  
         struct B { };
  
         void f();
      };

   template<class B>
      void  X<B>::f()
      { 
         B* p = 0;      // 'B' is X<>::B, not the template parameter
      }

-- Gaby
Comment 12 Giovanni Bajo 2004-02-02 18:11:39 UTC
As Gaby said, this is invalid per [temp.local]/5 and [temp.local]/7. The 
diagnostic looks satisfatory to me, so I'm closing this as invalid.
Comment 13 gianni 2004-02-02 18:21:28 UTC
Gabriel Dos Reis writes:
| I just checked with the Core group and John Spicer recalled that the
| committee madethe general decision that a class-member hides a
| template-parameter. See the implementation of that decision in
| 14.6.1/5 and 14.6.1/7.

OK - It seems like Comeau got this one wrong ... Cool.
Comment 14 gianni 2004-02-02 19:17:44 UTC
Giving this problem some more thought - I'm thinking that there should be some
kind of diagnostic if a template parameter is hidden, at least a warning.  The
template parameter is useless (at least next to useless) if it's hidden and so
this is probably not what the coder expected.

I'm obviously not the only one who has been or is surprised by this behaviour.

Comment 15 Giovanni Bajo 2004-02-02 19:33:19 UTC
Ok, we can try something.
Comment 16 Michael Mellor 2004-02-02 20:44:08 UTC
Gabriel Dos Reis writes:
|Well, I don't think GCC is in error.  When you define a function (or a
|class) in a class, it gets rewritten as if it where defined outside of
|the class (which is why we get the reevaluation rule I pointed you to
|in a different PR).  Now, when you reevaluate the member template
|outside of the class, name lookup is required to find X::C -- see 
|14.6.1/5 and 14.6.1/7

14.6.1/5 and 14.6.1/7 refer to "In the definition of a member of a class 
template..." and "In the definition of a class template or in the definition 
of a member of such a template..." respectively. The example does not have a 
class template, it is a member-template.

So AFAICS GCC is wrong.

Comment 17 Gabriel Dos Reis 2004-02-02 21:08:51 UTC
Subject: Re:  [3.3?/3.4/3.5 regression] template template argument identifier lookup fails scoping rules

"gianni at mariani dot ws" <gcc-bugzilla@gcc.gnu.org> writes:

| Giving this problem some more thought - I'm thinking that there
| should be some kind of diagnostic if a template parameter is hidden,
| at least a warning.

Sure, giving a warning controled by -Wshadow is a good idea 
(I've been thinking about that this morning while walking to work :-).

| The template parameter is useless (at least next to useless) if it's
| hidden and so this is probably not what the coder expected. 

Please remember that a template-parameter can be renammed at will.
In particular, there is no obligation that the template-parameter name
used in the declaration be the same as the one used in the definition.
And the definition can appear very far down in the program (or in
another translation unit.  You don't want the members be "leaked" by
whatever names are used in those definitions.

| I'm obviously not the only one who has been or is surprised by this
| behaviour. 

Well, we're talking about templates, right? :-)

-- Gaby
Comment 18 Gabriel Dos Reis 2004-02-02 21:13:03 UTC
Subject: Re:  A warning could be emitted if a template parameter of a member template is begin shadowed by another member of the class

"gcc-bugs at michaelmellor dot com" <gcc-bugzilla@gcc.gnu.org> writes:

| ------- Additional Comments From gcc-bugs at michaelmellor dot com  2004-02-02 20:44 -------
| Gabriel Dos Reis writes:
| |Well, I don't think GCC is in error.  When you define a function (or a
| |class) in a class, it gets rewritten as if it where defined outside of
| |the class (which is why we get the reevaluation rule I pointed you to
| |in a different PR).  Now, when you reevaluate the member template
| |outside of the class, name lookup is required to find X::C -- see 
| |14.6.1/5 and 14.6.1/7
| 
| 14.6.1/5 and 14.6.1/7 refer to "In the definition of a member of a class 
| template..." and "In the definition of a class template or in the definition 
| of a member of such a template..." respectively. The example does not have a 
| class template, it is a member-template.

That is the answer from the Core Group.
As I said, the decision of having class members hide template parameters
was an explicit decision made by the committee.  Parameters of member
templates are no different.

| So AFAICS GCC is wrong.

No, GCC is not wrong.  I just checked with the Core group and John
Spicer said yes, the program is ill-formed.  

-- Gaby
Comment 19 gianni 2004-02-07 08:25:02 UTC
Given this from William M. Miller - should we now reconsider reverting the
summary to the original one ?


Cut-n-paste from microsoft.public.vc.language ...
............................

That Bugzilla thread ends with an incorrect assertion about what the
"correct" behavior is.  It reports that John Spicer agreed that the
sample was ill-formed, but he later recanted that position -- he had
been looking at the wrong example in the voluminous discussion on
the reflector, and when he looked at the example in question, he said
it was well-formed.

Although Gaby has now agreed, I think, that the EDG (Comeau) compiler
has it right, I wouldn't consider the question resolved.  There's
been no vote to establish consensus among the core working group, and
at least three major compilers currently get a different answer from
the EDG compiler.  Furthermore, I believe Gaby's acceptance of the
EDG resolution is contingent on making the construct ill-formed, so
it won't matter which way the resolution goes.  I'm sure this will
be discussed at next month's Standard Committee meeting, and Microsoft
is expected to be represented there.  I hope that we'll be able to
come to consensus on the outcome then, but we'll have to wait and see.

-- William M. Miller
   The MathWorks, Inc.

..........................

Comment 20 Andrew Pinski 2004-02-07 08:29:44 UTC
Suspending until the time comes to reconsider this bug as there is no consensus.
Comment 21 Giovanni Bajo 2004-02-07 09:05:56 UTC
As a reference, the quote comes from: http://tinyurl.com/3bf5z
Comment 22 Gabriel Dos Reis 2004-02-07 13:11:26 UTC
Subject: Re:  A warning could be emitted if a template parameter of a member template is begin shadowed by another member of the class

"gianni at mariani dot ws" <gcc-bugzilla@gcc.gnu.org> writes:

| Given this from William M. Miller - should we now reconsider reverting the
| summary to the original one ?
| 
| 
| Cut-n-paste from microsoft.public.vc.language ...
| ............................
| 
| That Bugzilla thread ends with an incorrect assertion about what the
| "correct" behavior is.  It reports that John Spicer agreed that the
| sample was ill-formed, but he later recanted that position -- he had
| been looking at the wrong example in the voluminous discussion on
| the reflector, and when he looked at the example in question, he said
| it was well-formed.
| 
| Although Gaby has now agreed, I think, that the EDG (Comeau) compiler
| has it right, I wouldn't consider the question resolved.  There's
| been no vote to establish consensus among the core working group, and
| at least three major compilers currently get a different answer from
| the EDG compiler.  Furthermore, I believe Gaby's acceptance of the
| EDG resolution is contingent on making the construct ill-formed, so
| it won't matter which way the resolution goes.  I'm sure this will
| be discussed at next month's Standard Committee meeting, and Microsoft
| is expected to be represented there.  I hope that we'll be able to
| come to consensus on the outcome then, but we'll have to wait and see.
| 
| -- William M. Miller
|    The MathWorks, Inc.

Sorry for not having updated the info here.  I've been meaning to do
that but I was kept occupied by other things.  
Yes, Mike's report is an accurate executive summary of the discussion
going on the C++ Core Group reflection (there are other ramifications
but I doubt they would much change the big picture as painted by Mike).
The least that can be said is that the standard description of name
lookup in member function definition is not complete and the syntax of
out-of-class definition of member template is deceiving in that it 
does not reflect the scope stack (in Mike's description, I've agreed
on, the scope stack would need to be resuffled at some point before we
start name lookup; and the added constraint Mike alluded to is to
rejected "invalid" template-parameters renaming).  There was no vote
to establish consensus, so suspending this PR is the right thing to do. 

-- Gaby
Comment 23 Giovanni Bajo 2004-02-14 01:12:20 UTC
Also notice this: http://tinyurl.com/2k2d7. Daveed Vandevoorde raised the issue 
with the C++ community.
Comment 24 Giovanni Bajo 2004-03-31 09:38:03 UTC
*** Bug 14785 has been marked as a duplicate of this bug. ***
Comment 25 Wolfgang Bangerth 2005-11-08 05:23:47 UTC
*** Bug 24657 has been marked as a duplicate of this bug. ***
Comment 26 Jason Merrill 2009-03-03 22:01:08 UTC

*** This bug has been marked as a duplicate of 36019 ***