Bug List: (This bug is not in your last search results)   Show last search results      Search page      Enter new bug
Bug#: 21008
Product:  
Component:  
Status: RESOLVED
Resolution: FIXED
Assigned To: Jason Merrill <jason@gcc.gnu.org>
Host:
Reported against  
Priority:  
Severity:  
Target Milestone:  
 
 
Target:
Reporter: Liviu Nicoara <nicoara@roguewave.com>
Add CC:
CC:
Remove selected CCs
Build:
URL:
Summary:
Keywords:
Known to work:
Known to fail:

Attachment Description Type Created Size Actions
Create a New Attachment (proposed patch, testcase, etc.) View All

Bug 21008 depends on: Show dependency tree
Show dependency graph
Bug 21008 blocks:

Additional Comments:






View Bug Activity   |   Format For Printing   |   Clone This Bug


Description:   Last confirmed: 2009-11-13 05:55 Opened: 2005-04-13 21:50
$ uname -srm
Linux 2.6.11.4 i686

$ g++ -v
Reading specs from /opt/compilers/gcc-3.4.3/lib/gcc/i686-pc-linux-gnu/3.4.3/specs
Configured with: ../gcc-3.4.3/configure --prefix=/opt/compilers/gcc-3.4.3
--enable-shared --enable-threads --enable-languages=c,c++
Thread model: posix
gcc version 3.4.3


Copy and paste at prompt:

$ cat > t.cpp << EOF

struct A
{
protected:
    int foo_;
};


template <class T>
struct B : public A
{
};

template <class T>
struct C : protected B<T>
{
    int foo () {
        return A::foo_;
    }
};
 
EOF

Compilation of the above with:

$ g++ -c t.cpp

results in:

t.cpp: In member function `int C<T>::foo()':
t.cpp:4: error: object missing in reference to `A::foo_'
t.cpp:17: error: from this location

Thanks,
Liviu

------- Comment #1 From Andrew Pinski 2005-04-13 22:04 -------
Ok, I don't know if this is valid code (I think it is invalid as foo_ is
qualified and not dependent, even 
though ICC and Comeau does not reject this):
struct A { int foo_; };
template <class T> struct B : public A {};
template<> struct B<int> {};
template <class T>
struct C : B<T>
{
    int foo () {
        return A::foo_;
    }
};


Take the above code and add:
C<int> a;
void f(void) {a.foo();}

ICC only rejects the code at  instantiation time which seems wrong.

Someone else will have to comment to make sure that I got my analysis right.

The way to "fix" the if the code is invalid is to do B<T>::A::_foo or
this->_foo.

------- Comment #2 From Wolfgang Bangerth 2005-04-15 05:29 -------
A::foo_ is not template-dependent, so it is looked up and bound at the time 
of template definition, not at instantiation time. Because template-dependent 
base classes are not visible at the time, the access is assumed to be from 
the outside, not within the class hierarchy through this->, and the error, 
though surprising, is correct. 
 
W. 

------- Comment #3 From Martin Sebor 2005-04-19 15:39 -------
I discussed this with Mike Miller of EDG. His response to my query on the issue
(copied with his permission) is below.

Mike Miller wrote:
...
> There were a couple of different examples in that thread, 
> so just to avoid confusion, here's the one I'll refer to:
> 
>     struct A {
>       int foo_;
>     };
>     template <typename T> struct B: public A { };
>     template <typename T> struct C: B<T> {
>       int foo() {
>         return A::foo_;  // #1
>       }
>     };
> 
> The question is how the reference on line #1 is treated. Wolfgang's 
> analysis isn't quite right.  While it's true that "A" is non-dependent 
> and thus is bound to ::A at template definition time, that is 
> irrelevant.  When C<int>::foo() (for instance) is instantiated, it turns 
> out that the reference to ::A::foo_ is, in fact, a non-static member of 
> a base class (9.3.1p3), so the reference is transformed into 
> (*this).::A::foo_ and there is no error.  This is not a violation of 
> 14.6.2p3 -- there's no lookup in a dependent base class involved, as 
> Wolfgang's comments assume, and the description "the access is assumed 
> to be from the outside, not within the class hierarchy through this->" 
> doesn't accurately describe how 9.3.1p3 works.
> 
> In fact, though, this just sort of happens to work because A is both 
> visible in the definition context and a base class of the instantiated 
> template.  If you add an explicit specialization
> 
>     template<> struct B<int> { };
> 
> as suggested in Andrew's comment, so A is not a base class, or if you 
> change the program so that A is not visible in the definition context 
> (by making it a member of a namespace, for instance), we do report an 
> error in the instantiated C<int>::foo().  (There's no requirement to 
> report errors in uninstantiated templates, of course, contrary to 
> Andrew's observation.)
> 
> This is sort of contrary to the "spirit" of two-stage lookup, though -- 
> Wolfgang's expectation is not unreasonable, I think, even though the 
> details of his reasoning are incorrect.  I'm probably going to open a 
> core issue on this, especially in light of the differences between 
> implementations.

------- Comment #4 From Martin Sebor 2005-04-19 15:41 -------
Here's a followup email from Mike with some calarifying comments:

Mike Miller wrote:
> Martin Sebor wrote:
> 
>> Thanks a lot for the detailed analysis! I wonder if your reasoning
>> would be the same given a slightly different test case (one that's
>> closer to the original in comment #1):
>>
>>>
>>>     struct A {
>>
>>
>>       protected:     // <<< ADDED <<<
>>
>>>       int foo_;
>>>     };
>>>     template <typename T> struct B: public A { };
>>>     template <typename T> struct C: B<T> {
>>>       int foo() {
>>>         return A::foo_;  // #1
>>>       }
>>>     };
> 
> 
> No, I don't think that changes things.  Again, the situation is the 
> same: whether A is the global class or the injected-class-name doesn't 
> affect whether C<int> (or whatever) has access to A::foo_.  (There are 
> cases where it does matter, but this isn't one of them.  Those typically 
> involve private or protected inheritance, where the access from 
> "outside" is greater than the inherited access.)
> 
> The general principle is that non-dependent names are looked up and 
> bound in the definition context (14.6.3), but that's really the only 
> semantic effect.  In cases like this one, it's as if "A" were replaced 
> by "::A".  If the result of using "::A" is well-formed, then the version 
> with just "A" is, too.
> 
>> But if an implementation is permitted to diagnose access violations
>> at definition time wouldn't the gcc compilation error be justified?
> 
> 
> I think the general rule is that you should only issue a diagnostic if 
> you can tell that no well-formed instantiation is possible (14.6p7).  In 
> these cases, at least some specializations will have well-formed 
> instantiations, so no diagnostic is permitted.

------- Comment #5 From Wolfgang Bangerth 2005-04-19 18:25 -------
Martin & Mike, 
I'm happy to reopen this PR. I understand your analysis, and in fact thought 
about it when I wrote my comment. Independently of whether it may be strictly 
mandated by the standard, I do have to admit that I find it confusing to see 
the semantics of something change at the time of instantiation, even though 
it was already bound at template definition time. I do think that this is 
a further complication of the already not quite so intuitive two-stage 
name lookup rules. 
 
But I guess that's immaterial. We're not into intuitive things, but into 
the letter of the law. Some people in this country already claim that  
lawyers stray too far from the letter of the law anyway, so we won't give 
them more reason to complain. 
 
Incidentally, two question: 
a) your reference to 9.3.1p3 must have been to something else. In TC1,  
   9.3.1 is on const and volatile member functions. 
 
b) how does your interpretation affect the validity of the following program: 
------------------ 
struct A { 
    int foo_; 
}; 
typedef int A::* pAi; 
 
template <typename T> struct B: public A { }; 
template <typename T> struct C: B<T> { 
     pAi foo() { 
      return &A::foo_; 
    } 
}; 
----------------- 
If A::foo_ refers to the member variable *of the present object*, then  
taking its address returns an int*, not an "int A::*" object, right? However, 
I can't seem to find a compiler that would reject the code. 
 
Thanks 
  Wolfgang 
 
 

------- Comment #6 From William M. (Mike) Milller 2005-04-20 20:14 -------
Responses to Wolfgang's two questions:

a) You're right; I was looking at the current WP rather than the 2003 
Standard.  Sorry.  It's 9.3.1p2 in the 2003 Standard (the change from troff to 
LaTeX resulted in some paragraphs being numbered differently, and I didn't 
notice that this was one of those cases).

b) No, unary & applied to a qualified-id that names a non-static member is 
always a pointer to member (5.3.1p2-3), regardless of whether the qualifier is 
an injected-class-name or an ordinary class-name.

------- Comment #7 From Mark Mitchell 2005-07-06 17:03 -------
Postponed until 4.0.2.

------- Comment #8 From Andrew Pinski 2005-10-17 14:50 -------
Confirmed, and .....

------- Comment #9 From Andrew Pinski 2005-10-17 14:51 -------
And removing target milestone and suspending since the DR report is still
active:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#515

------- Comment #10 From Mark Mitchell 2006-05-25 02:35 -------
Will not be fixed in 4.1.1; adjust target milestone to 4.1.2.

------- Comment #11 From Andrew Pinski 2007-12-29 00:38 -------
This was voted in WP in 2005:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#515

------- Comment #12 From Joseph S. Myers 2008-07-04 16:51 -------
Closing 4.1 branch.

------- Comment #13 From Joseph S. Myers 2009-03-31 18:44 -------
Closing 4.2 branch.

------- Comment #14 From Richard Guenther 2009-08-04 12:26 -------
GCC 4.3.4 is being released, adjusting target milestone.

------- Comment #15 From Jason Merrill 2009-11-13 14:41 -------
Subject: Bug 21008

Author: jason
Date: Fri Nov 13 14:40:22 2009
New Revision: 154150

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=154150
Log:
        PR c++/21008, DR 515
        * semantics.c (finish_non_static_data_member): Don't check
        derivation in a template.

Added:
    trunk/gcc/testsuite/g++.dg/template/inherit4.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/semantics.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/g++.dg/lookup/scoped8.C

------- Comment #16 From Jason Merrill 2009-11-13 15:37 -------
Subject: Bug 21008

Author: jason
Date: Fri Nov 13 15:37:29 2009
New Revision: 154153

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=154153
Log:
        PR c++/21008, DR 515
        * semantics.c (finish_non_static_data_member): Don't check
        derivation in a template.

Added:
    branches/gcc-4_3-branch/gcc/testsuite/g++.dg/template/inherit4.C
Modified:
    branches/gcc-4_3-branch/gcc/cp/ChangeLog
    branches/gcc-4_3-branch/gcc/cp/semantics.c
    branches/gcc-4_3-branch/gcc/testsuite/ChangeLog
    branches/gcc-4_3-branch/gcc/testsuite/g++.dg/lookup/scoped8.C

------- Comment #17 From Jason Merrill 2009-11-13 18:03 -------
Subject: Bug 21008

Author: jason
Date: Fri Nov 13 18:03:31 2009
New Revision: 154158

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=154158
Log:
        PR c++/21008, DR 515
        * semantics.c (finish_non_static_data_member): Don't check
        derivation in a template.

Added:
    branches/gcc-4_4-branch/gcc/testsuite/g++.dg/template/inherit4.C
Modified:
    branches/gcc-4_4-branch/gcc/cp/ChangeLog
    branches/gcc-4_4-branch/gcc/cp/semantics.c
    branches/gcc-4_4-branch/gcc/testsuite/ChangeLog
    branches/gcc-4_4-branch/gcc/testsuite/g++.dg/lookup/scoped8.C

------- Comment #18 From Jason Merrill 2009-11-13 18:03 -------
Fixed.

Bug List: (This bug is not in your last search results)   Show last search results      Search page      Enter new bug