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
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 } };
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.
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) 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 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 ? 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 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 ? 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 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. 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 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 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. 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. 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. Ok, we can try something. 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. 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 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 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. .......................... Suspending until the time comes to reconsider this bug as there is no consensus. As a reference, the quote comes from: http://tinyurl.com/3bf5z 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 Also notice this: http://tinyurl.com/2k2d7. Daveed Vandevoorde raised the issue with the C++ community. *** Bug 14785 has been marked as a duplicate of this bug. *** *** Bug 24657 has been marked as a duplicate of this bug. *** *** This bug has been marked as a duplicate of 36019 *** |