Bug 11750

Summary: class scope using-declaration lookup not implemented
Product: gcc Reporter: jfischer_5809
Component: c++Assignee: fabien
Status: RESOLVED FIXED    
Severity: normal CC: alexey.starovoytov, andrew.stubbs, aschepler, balakrishnan.erode, fabien, fang, gcc-bugs, rigaje
Priority: P2 Keywords: wrong-code
Version: 3.3   
Target Milestone: 4.8.0   
Host: i686-pc-linux-gnu Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu Known to work:
Known to fail: 4.3.0 Last reconfirmed: 2011-11-21 20:22:49

Description jfischer_5809 2003-07-31 17:44:50 UTC
Paragraph 10.3/2 in the C++ standard [ISO/IEC 14882:1998] provides the following
code example:

<quote>

struct A {
    virtual void f();
};
struct B : virtual A {
    virtual void f();
};

struct C : B , virtual A {
    using A::f; 
};
void foo() {
    C c; 
    c.f();      // calls B::f, the final overrider
    c.C::f();   // calls A::f because of the using-declaration
}

</quote>

When a similar program is compiled using G++ 3.3, the method call 'c.f()' in
function foo() incorrectly invokes A::f and not B::f as specified in the standard.

<example>
<code main.cpp>
#include <iostream>

struct A {
    virtual void f() { std::cout << "A::f()\n"; }
};
struct B : virtual A {
    virtual void f() { std::cout << "B::f()\n"; }
};
struct C : B, virtual A {
    using A::f;
};

int main()
{
    C c;
    c.f();      // ERROR - Incorrectly invokes A::f
    c.C::f();   // OK - Invokes A::f
}
</code>

<build>
$ g++ main.cpp

$ ldd a.out
        libstdc++.so.5 =>
/usr/local/gcc/3.3/lib/gcc-lib/i686-pc-linux-gnu/3.3/libstdc++.so.5 (0x40017000)
        libm.so.6 => /lib/tls/libm.so.6 (0x400e4000)
        libgcc_s.so.1 =>
/usr/local/gcc/3.3/lib/gcc-lib/i686-pc-linux-gnu/3.3/libgcc_s.so.1 (0x40106000)
        libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
</build>

<output>
$ ./a.out
A::f()
A::f()
</output>

</example>
Comment 1 Andrew Pinski 2003-08-01 19:10:33 UTC
I can confirm this on the mainline (20030801).
ICC 6.0 produces the correct ouput.
Note 2.95.3 produces:
B::f()
B::f()
While 3.0.4 produces:
A::f()
A::f()
Comment 2 Davi Arnaut 2004-08-05 23:18:04 UTC
A way to workaround this is to put C into the heap. Is anyone going to fix this ?
Comment 3 Giovanni Bajo 2004-08-08 16:33:55 UTC
(In reply to comment #2)

> Is anyone going to fix this ?

I doubt it, at least any time soon. This is not a regression, and our semantic 
of the using declarations should be reworked (right now, they match old ARM-
style access declarations).

If you feel strong about this, you can either try to look into the problem 
yourself, or hire someone to do the work.
Comment 4 Andrew Pinski 2006-08-16 04:45:59 UTC
*** Bug 28748 has been marked as a duplicate of this bug. ***
Comment 5 Andrew Pinski 2006-09-19 09:41:56 UTC
*** Bug 29136 has been marked as a duplicate of this bug. ***
Comment 6 Balakrishnan B 2011-01-12 16:57:07 UTC
(In reply to comment #0)
> Paragraph 10.3/2 in the C++ standard [ISO/IEC 14882:1998] provides the
> following
> code example:
> 
> <quote>
> 
> struct A {
>     virtual void f();
> };
> struct B : virtual A {
>     virtual void f();
> };
> 
> struct C : B , virtual A {
>     using A::f; 
> };
> void foo() {
>     C c; 
>     c.f();      // calls B::f, the final overrider
>     c.C::f();   // calls A::f because of the using-declaration
> }
> 
> </quote>
> 
> When a similar program is compiled using G++ 3.3, the method call 'c.f()' in
> function foo() incorrectly invokes A::f and not B::f as specified in the
> standard.
> 
> <example>
> <code main.cpp>
> #include <iostream>
> 
> struct A {
>     virtual void f() { std::cout << "A::f()\n"; }
> };
> struct B : virtual A {
>     virtual void f() { std::cout << "B::f()\n"; }
> };
> struct C : B, virtual A {
>     using A::f;
> };
> 
> int main()
> {
>     C c;
>     c.f();      // ERROR - Incorrectly invokes A::f
>     c.C::f();   // OK - Invokes A::f
> }
> </code>
> 
> <build>
> $ g++ main.cpp
> 
> $ ldd a.out
>         libstdc++.so.5 =>
> /usr/local/gcc/3.3/lib/gcc-lib/i686-pc-linux-gnu/3.3/libstdc++.so.5
> (0x40017000)
>         libm.so.6 => /lib/tls/libm.so.6 (0x400e4000)
>         libgcc_s.so.1 =>
> /usr/local/gcc/3.3/lib/gcc-lib/i686-pc-linux-gnu/3.3/libgcc_s.so.1 (0x40106000)
>         libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
>         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
> </build>
> 
> <output>
> $ ./a.out
> A::f()
> A::f()
> </output>
> 
> </example>

Im using g++ 4.4.5
With the same example with my main function as below,
int main()
{
      C c;
      c.f() // Calls A::f
      C* pc = &c;
      pc->f() // Calls B::f
}

With the same object when accessed directly produces different results and when accessed using a pointer of same type produces a different result. Even if gcc violates standard, there has to be some proper explanation.
Comment 7 Jonathan Wakely 2011-01-12 17:10:17 UTC
(In reply to comment #6)
> 
> With the same object when accessed directly produces different results and when
> accessed using a pointer of same type produces a different result. Even if gcc
> violates standard, there has to be some proper explanation.

The explanation is "it's a bug"
Comment 8 Andrew Schepler 2011-01-12 17:16:29 UTC
(In reply to comment #6)
> > struct A {
> >     virtual void f();
> > };
> > struct B : virtual A {
> >     virtual void f();
> > };
> > 
> > struct C : B , virtual A {
> >     using A::f; 
> > };

> Im using g++ 4.4.5
> With the same example with my main function as below,
> int main()
> {
>       C c;
>       c.f() // Calls A::f
>       C* pc = &c;
>       pc->f() // Calls B::f
> }
> 
> With the same object when accessed directly produces different results and when
> accessed using a pointer of same type produces a different result. Even if gcc
> violates standard, there has to be some proper explanation.

The reason is that when f is invoked via a pointer or reference, g++ uses the vtable lookup to call the correct final override.  But when the object in the member access is not a pointer or reference (it is a non-reference identifier as here, or qualified id, or class member), g++ can usually optimize away the virtual call and just call the correct member function.  In this case the logic for calling the correct member function for that optimization is incorrect, but virtual calls still work correctly.
Comment 9 fabien 2012-11-14 20:12:56 UTC
Author: fabien
Date: Wed Nov 14 20:12:47 2012
New Revision: 193504

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=193504
Log:
gcc/testsuite/ChangeLog

2012-11-14  Fabien ChĂȘne  <fabien@gcc.gnu.org>

	PR c++/11750
	* g++.dg/inherit/vitual9.C: New.

gcc/cp/ChangeLog

2012-11-14  Fabien ChĂȘne  <fabien@gcc.gnu.org>

	PR c++/11750
	* call.c (build_new_method_call_1): Check that the instance type
	and the function context are the same before setting the flag
	LOOKUP_NONVIRTUAL.

Added:
    trunk/gcc/testsuite/g++.dg/inherit/virtual9.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
    trunk/gcc/testsuite/ChangeLog
Comment 10 fabien 2012-11-14 20:20:21 UTC
Fixed in 4.8.
Comment 11 Andrew Pinski 2021-08-02 00:15:23 UTC
*** Bug 55385 has been marked as a duplicate of this bug. ***