Bug 11750 - class scope using-declaration lookup not implemented
Summary: class scope using-declaration lookup not implemented
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.3
: P2 normal
Target Milestone: 4.8.0
Assignee: fabien
URL:
Keywords: wrong-code
: 28748 29136 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-07-31 17:44 UTC by jfischer_5809
Modified: 2012-11-14 20:20 UTC (History)
7 users (show)

See Also:
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


Attachments

Note You need to log in before you can comment on or make changes to this bug.
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.