This is the mail archive of the gcc-prs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

c++/8910: Incorrect code generation when returning class by value


>Number:         8910
>Category:       c++
>Synopsis:       Incorrect code generation when returning class by value
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          wrong-code
>Submitter-Id:   net
>Arrival-Date:   Wed Dec 11 19:16:00 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Lakhbir Gandhi
>Release:        gcc version 2.95.4 20010321 (Peerless-JBurk) derived from  gcc 2.95.3 with DaveK's modifications for VxWorksPPC.
>Organization:
>Environment:
Compiler#1: gcc 2.95.3 with DaveK's modifications for VxWorksPPC.
Compiler#2: cygwin 2.95.3-5
Host: PIII MS Windows 2000 666Mhz 768MB
Shell: Cmd
Compile command: c++<ppc> test.cpp -g -c -o test.o
Disassembly command: objdump<ppc> -d -r -S test.o 
>Description:
Hello,
 
I want to report a bug wherein if a method returns a class by value, incorrect code is generated.
It manifests itself when copy constructors are not available, in my case I had my copy constructor declared 'explicit' to prevent the compiler from generating expensive temporary objects.
 
 
Both the ppc & cygwin compilers produce the same result so I don't think DaveK's modifications have anything to do with it.
 
The test code is as follows: (copy-paste into test.cpp)
 
    class A  {
 

    };
 
class B  {
    public :
        
            B(int  init);
            B(A  init);
explicit  B(const B & init);
 
         operator A();
        
    };
 
    class C  {
    
        public :
         operator B();
        
    
    };
    
     C::operator B() {
        return B(12345);
    }
    
 
The class setup is described so:
 
class A is any class.
class B contains conversion constructor and operator for class A.
class B also has a conversion constructor from int.
(I have used int as an example, but all other datatypes intrisic and user-defined cause the same behaviour)
class C defines a conversion operator to class B.
The copy constructor for class B is declared explicit to prevent the compiler from generating expensive temporary B objects.
C's conversion operator returns a B object by value, not as a reference or pointer. 

The implementation of C::operator B() elects to return an object B which is initialized by the integer 12345.
Because class B has a conversion constructor from int, all we should see in the assembly code generated is a call to B::B(int).
 
However I get the following:
 

MiscTest.ppc.o:     file format elf32-powerpc
 
Disassembly of section .text:
 
00000000 <C::operator B(void)>:
        
    
    };
    
     C::operator B() {
   0: 94 21 ff c0  stwu r1,-64(r1)
   4: 7c 08 02 a6  mflr r0
   8: 93 61 00 2c  stw r27,44(r1)
   c: 93 81 00 30  stw r28,48(r1)
  10: 93 a1 00 34  stw r29,52(r1)
  14: 93 c1 00 38  stw r30,56(r1)
  18: 93 e1 00 3c  stw r31,60(r1)
  1c: 90 01 00 44  stw r0,68(r1)
  20: 7c 3f 0b 78  mr r31,r1
  24: 7c 7d 1b 78  mr r29,r3
  28: 7c 9c 23 78  mr r28,r4
        return B(12345);
  2c: 3b 7f 00 09  addi r27,r31,9
  30: 38 1f 00 18  addi r0,r31,24
  34: 7c 03 03 78  mr r3,r0
  38: 38 80 30 39  li r4,12345
  3c: 48 00 00 01  bl 3c <C::operator B(void)+0x3c>
   3c: R_PPC_REL24 B::B(int)
  40: 7c 60 1b 78  mr r0,r3
  44: 39 3f 00 18  addi r9,r31,24
  48: 7f 63 db 78  mr r3,r27
  4c: 7d 24 4b 78  mr r4,r9
  50: 4c c6 31 82  crclr 4*cr1+eq
  54: 48 00 00 01  bl 54 <C::operator B(void)+0x54>
   54: R_PPC_REL24 B::operator A(void)
  58: 88 1f 00 09  lbz r0,9(r31)
  5c: 39 20 00 00  li r9,0
  60: 99 3f 00 08  stb r9,8(r31)
  64: 7f a3 eb 78  mr r3,r29
  68: 38 9f 00 08  addi r4,r31,8
  6c: 48 00 00 01  bl 6c <C::operator B(void)+0x6c>
   6c: R_PPC_REL24 B::B(A)
  70: 7c 60 1b 78  mr r0,r3
  74: 48 00 00 0c  b 80 <C::operator B(void)+0x80>
  78: 48 00 00 08  b 80 <C::operator B(void)+0x80>
  7c: 48 00 00 04  b 80 <C::operator B(void)+0x80>
    }
  80: 7f a3 eb 78  mr r3,r29
  84: 81 61 00 00  lwz r11,0(r1)
  88: 80 0b 00 04  lwz r0,4(r11)
  8c: 7c 08 03 a6  mtlr r0
  90: 83 6b ff ec  lwz r27,-20(r11)
  94: 83 8b ff f0  lwz r28,-16(r11)
  98: 83 ab ff f4  lwz r29,-12(r11)
  9c: 83 cb ff f8  lwz r30,-8(r11)
  a0: 83 eb ff fc  lwz r31,-4(r11)
  a4: 7d 61 5b 78  mr r1,r11
  a8: 4e 80 00 20  blr

 
At offset 3c above, the correct call to B::B(int) is generated.
But at offset 54, there is a call to B::operator A !!!!! 
To add insult to injury, this returned A is used to call B::B(A) at offset 6c !
This causes C::operator B() to return the B object created above, which is initialized by an A instead of an int which was the intent.
 
This is incorrect behavior on two accounts:
1) ISO/IEC 14882:1998 in section 12.3.4 specifies that "At most one user-defined conversion (constructor or conversion function) is implictely applied to a single value", and here we see two such conversions, from B to A and then back to B.
2) The B object created by B::B(A) at offset 6c is returned instead of the the B object created by B::B(int) at offset 3c.
 
I have examined the rtl and it contains the incorrect return semantic described above, so rtl to asm conversion is not the issue.
Either the bug is in gcc/cp/parse.y or tree generation is incorrect or the resolution of candidate functions is incorrect or has the wrong data or the code in gcc/cp/typeck.c between line 7449 and line 7453 in function c_expand_return does not implement  the correct semantics. Please be aware this is just a conjecture.
 


Now if I do not declare B::B(B&) explicit, the correct code gets generated at offset 30 as shown below.
 
 
MiscTest.ppc.o:     file format elf32-powerpc
 
Disassembly of section .text:
 
00000000 <C::operator B(void)>:
        
    
    };
    
     C::operator B() {
   0: 94 21 ff e0  stwu r1,-32(r1)
   4: 7c 08 02 a6  mflr r0
   8: 93 81 00 10  stw r28,16(r1)
   c: 93 a1 00 14  stw r29,20(r1)
  10: 93 c1 00 18  stw r30,24(r1)
  14: 93 e1 00 1c  stw r31,28(r1)
  18: 90 01 00 24  stw r0,36(r1)
  1c: 7c 3f 0b 78  mr r31,r1
  20: 7c 7d 1b 78  mr r29,r3
  24: 7c 9c 23 78  mr r28,r4
        return B(12345);
  28: 7f a3 eb 78  mr r3,r29
  2c: 38 80 30 39  li r4,12345
  30: 48 00 00 01  bl 30 <C::operator B(void)+0x30>
   30: R_PPC_REL24 B::B(int)
  34: 7c 60 1b 78  mr r0,r3
  38: 48 00 00 0c  b 44 <C::operator B(void)+0x44>
  3c: 48 00 00 08  b 44 <C::operator B(void)+0x44>
  40: 48 00 00 04  b 44 <C::operator B(void)+0x44>
    }
  44: 7f a3 eb 78  mr r3,r29
  48: 81 61 00 00  lwz r11,0(r1)
  4c: 80 0b 00 04  lwz r0,4(r11)
  50: 7c 08 03 a6  mtlr r0
  54: 83 8b ff f0  lwz r28,-16(r11)
  58: 83 ab ff f4  lwz r29,-12(r11)
  5c: 83 cb ff f8  lwz r30,-8(r11)
  60: 83 eb ff fc  lwz r31,-4(r11)
  64: 7d 61 5b 78  mr r1,r11
  68: 4e 80 00 20  blr

This code should have been generated for the explicit copy constructor case because as you can see there is no mention of B::B(B&)  here!
I think it is a definite bug.
 
I have tried commenting out the conversion operator B::operator A() and the conversion constructor B::B(A) one at a time, the compiler then generates the error messages shown below.
 
Change#1:
//        B::B(A  init);

result#1:
 
MiscTest.cpp: In method `C::operator B()':
MiscTest.cpp:29: no matching function for call to `B::B (B)'
MiscTest.cpp:11: candidates are: B::B(int)

 
change#2:
//         B::operator A();

resullt#2:
MiscTest.cpp: In method `C::operator B()':
MiscTest.cpp:29: no matching function for call to `B::B (B)'
MiscTest.cpp:11: candidates are: B::B(int)
MiscTest.cpp:14:                 B::B(A)

I am a newbie to gcc innards, so I may be way off the mark. Sorry I don't have more details yet, I just ran into this problem last friday.
 
VisualC++ however does not display this behaviour and generates correct code.

Regards, 

Lakhbir Gandhi 
Consulting Engineer 
Peerless Systems Imaging Products (PSIP)
>How-To-Repeat:

>Fix:

>Release-Note:
>Audit-Trail:
>Unformatted:


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]