[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Incorrect code generation when returning class by value
From: |
Lakhbir Gandhi |
Subject: |
Incorrect code generation when returning class by value |
Date: |
Mon, 9 Dec 2002 22:25:51 -0500 |
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.
The environment is
as follows:
Compiler#1:
gcc 2.95.3
with DaveK's modifications for VxWorksPPC.
Compiler#2: cygwin
2.95.3-5
Host: PIII MS
Windows 2000
Shell:
Cmd
Compile command:
c++<ppc> test.cpp -g -c -o test.o
Disassembly command:
objdump<ppc> -d -r -S test.o
Both 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:
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 setup is
described so:
class B contains
conversion constructor and operator for class A.
class B also has a
conversion constructor from int.
class C defines a
conversion operator to class B.
The copy constructor
for class B is declared explicit to prevent the compiler from generating
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
address@hidden
253-395-8890 x13.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Incorrect code generation when returning class by value,
Lakhbir Gandhi <=