This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
optimization/7560: copy construction (return value optimization?)
- From: spencer at aol dot net
- To: gcc-gnats at gcc dot gnu dot org
- Date: 9 Aug 2002 16:52:31 -0000
- Subject: optimization/7560: copy construction (return value optimization?)
- Reply-to: spencer at aol dot net
>Number: 7560
>Category: optimization
>Synopsis: copy construction (return value optimization?)
>Confidential: no
>Severity: critical
>Priority: medium
>Responsible: unassigned
>State: open
>Class: wrong-code
>Submitter-Id: net
>Arrival-Date: Fri Aug 09 09:56:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator: Brad Spencer
>Release: gcc-3.1 and gcc-3.1.1
>Organization:
>Environment:
sparc64-sun-solaris2.8
>Description:
I'm using both gcc-3.1 [cross and native] and gcc-3.1.1 [cross] for the sparc64-sun-solaris2.8 target. This bug only shows up when build 64-bit sparc targets AFAIK.
starbug:/starbug/spencer$ /opt/gcc-3.1.1-cross/sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ -v
Reading specs from /opt/gcc-3.1.1-cross/sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1.1/specs
Configured with: ../../gcc-3.1.1/configure --with-dwarf2 --enable-languages=c,c++ --enable-threads=single --disable-shared --prefix=/opt/gcc-3.1.1-cross/sparc64-sun-solaris2.8 --target=sparc64-sun-solaris2.8 -v --with-headers=/starbug/spencer/devel/gcc-cross/sparc64-sun-solaris2.8/target-stuff/include/ --with-lib=/opt/gcc-3.1.1-cross/sparc64-sun-solaris2.8/sparc64-sun-solaris2.8/lib --with-gnu-as --with-gnu-ld --disable-multilib
Thread model: single
gcc version 3.1.1
starbug:/starbug/spencer$ /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ -v
Reading specs from /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/specs
Configured with: ../gcc-3.1/configure --with-dwarf2 --enable-languages=c,c++ --enable-threads=single --disable-shared --prefix=/opt/gcc-3.1-cross-sparc64-sun-solaris2.8 --target=sparc64-sun-solaris2.8 -v --with-headers=/starbug/spencer/devel/gcc-cross/target-stuff/include/ --with-lib=/starbug/spencer/devel/gcc-cross/target-stuff/lib --with-gnu-as --with-gnu-ld --disable-multilib
Thread model: single
gcc version 3.1
netra-1:~$ /opt/gcc-3.1/bin/g++ -v
Reading specs from /opt/gcc-3.1/lib/gcc-lib/sparc-sun-solaris2.8/3.1/specs
Configured with: ../gcc-3.1/configure --with-dwarf2 --enable-languages=c,c++ --enable-threads=single --disable-shared --with-gnu-as --with-gnu-ld --with-as=/opt/bin/as --with-ld=/opt/bin/ld --prefix=/opt/gcc-3.1
Thread model: single
gcc version 3.1
When running the following code compiled with any of these three compilers with optimizations on, the output is incorrect (see comments). What I suspect is happening is that the m_container member of Container::iterator is being treated as if it was only 32-bit during some optimization.
Here is the code sample:
+++BEGIN
//*****************************************************************************
// Shows bug when compiled with gcc-3.1 or gcc-3.1.1 at -O2 or higher for
// sparc64-sun-solaris2.8.
//
// When compiled with -O or no optimizations, gives correct output:
// /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++
// -Wall -o optfoo optfoo.cc -O
// *** begin: [0xffffffff7ffff9bf, 0, 0] end: [0xabcd, 123456, 1]
// Not equal
//
// But when build with -O2 or higher, gives incorrect output:
// /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++
// -Wall -o optfoo optfoo.cc -O2
// *** begin: [0xffffffff7ffff9cf, 0, 0] end: [0xabcd, 0, 0]
// equal
//
// Removing the const qualifier from the two const members of iterator also
// avoids the bug, even on -O6:
// /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++
// -Wall -o optfoo optfoo.cc -O2 -DFOO_NO_CONST_MEMBERS
// *** begin: [0xffffffff7ffff9cf, 0, 0] end: [0xabcd, 123456, 1]
// Not equal
#include <iostream>
#include <iterator>
#include <string>
// If FOO_NO_CONST_MEMBERS is set, then skip the const on the iterator members
#if FOO_NO_CONST_MEMBERS
# define DEBUG_CONST
#else
# define DEBUG_CONST const
#endif
//=============================================================================
using std::cout;
using std::endl;
class Container
{
public:
class iterator
{
// Not allowed
void operator=(const iterator &);
public:
// creates as 'end'
iterator()
: m_container((Container *)0xABCD), m_all(true), m_idx(123456)
{}
bool operator!=(const iterator &rhs) const
{
return m_idx != rhs.m_idx;
}
// Return the packet itself
const Container *getContainer() const { return m_container; }
unsigned int getIdx() const { return m_idx; }
bool getAll() const { return m_all; }
protected:
friend class Container;
iterator(const Container *p,unsigned int i)
: m_container(p), m_all(false), m_idx(i) {}
explicit iterator(const Container *p)
: m_container(p), m_all(true), m_idx(0) {}
bool isValid() const {
return m_container!=NULL;
}
private:
const Container * DEBUG_CONST m_container;
DEBUG_CONST bool m_all;
unsigned int m_idx;
};
iterator get() const { return iterator(this, 1); }
iterator begin() const { return iterator(this, 0); }
iterator end() const { return iterator(); }
};
template<typename directly_supported_type,
typename attribute_tag>
class DirectSupportIterator
: public Container::iterator,
public std::iterator<std::forward_iterator_tag, directly_supported_type>
{
private:
// :: --------------------------------------------------------------------
// :: Type Information
typedef Container::iterator BaseClass;
public:
// The value we dereference into
typedef directly_supported_type value_type;
public:
// :: --------------------------------------------------------------------
// :: Construction
// Copy construct from base class
DirectSupportIterator(const BaseClass &it)
: BaseClass(it)
{}
// Make "end" version
DirectSupportIterator()
: BaseClass()
{}
// Default copy and assignemnt
};
typedef int SomeType;
typedef DirectSupportIterator<std::string, SomeType> IteratorType;
class Wrapper
{
Container p;
public:
IteratorType begin() const { return p.begin(); }
static IteratorType end() { return IteratorType(); }
};
int
main()
{
std::ios::sync_with_stdio(false);
Wrapper w;
IteratorType begin = w.begin();
const IteratorType end = Wrapper::end();
cout << "*** begin: ["
<< begin.getContainer() << ", " << begin.getIdx()
<< ", " << begin.getAll() << "] end: ["
<< end.getContainer() << ", " << end.getIdx()
<< ", " << end.getAll() << ']' << std::endl;
// Avoid logging if this field is not present
if(begin != end) {
cout << "Not equal" << endl;
} else {
cout << "equal" << endl;
}
return 0;
}
+++END
[ - - - ]
Here it is being built by gcc-3.1.1 (a cross compiler):
starbug:/starbug/spencer$ /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ -Wall -o optfoo optfoo.cc -O2 -v
Reading specs from /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/specs
Configured with: ../gcc-3.1/configure --with-dwarf2 --enable-languages=c,c++ --enable-threads=single --disable-shared --prefix=/opt/gcc-3.1-cross-sparc64-sun-solaris2.8 --target=sparc64-sun-solaris2.8 -v --with-headers=/starbug/spencer/devel/gcc-cross/target-stuff/include/ --with-lib=/starbug/spencer/devel/gcc-cross/target-stuff/lib --with-gnu-as --with-gnu-ld --disable-multilib
Thread model: single
gcc version 3.1
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/cc1plus -v -D__GNUC__=3 -D__GNUC_MINOR__=1 -D__GNUC_PATCHLEVEL__=0 -Dsparc -Dsun -Dunix -D__svr4__ -D__SVR4 -D__PRAGMA_REDEFINE_EXTNAME -D__sparc__ -D__sun__ -D__unix__ -D__svr4__ -D__SVR4 -D__PRAGMA_REDEFINE_EXTNAME -D__sparc -D__sun -D__unix -Asystem=unix -Asystem=svr4 -D__OPTIMIZE__ -D__STDC_HOSTED__=1 -D_XOPEN_SOURCE=500 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D__EXTENSIONS__ -D__SIZE_TYPE__=long unsigned int -D__PTRDIFF_TYPE__=long int -D__WCHAR_TYPE__=int -D__WINT_TYPE__=int -D__arch64__ -Acpu=sparc64 -Amachine=sparcv9 -D__sparcv9 optfoo.cc -D__GNUG__=3 -D__DEPRECATED -D__EXCEPTIONS -D__GXX_ABI_VERSION=100 -quiet -dumpbase optfoo.cc -O2 -Wall -version -o /var/tmp//ccWZmCh0.s
GNU CPP version 3.1 (cpplib) (sparc ELF)
GNU C++ version 3.1 (sparc64-sun-solaris2.8)
compiled by GNU C version 3.1.
ignoring nonexistent directory "/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/sparc64-sun-solaris2.8/include"
#include "..." search starts here:
#include <...> search starts here:
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/include/g++-v3
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/include/g++-v3/sparc64-sun-solaris2.8
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/include/g++-v3/backward
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/include
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/include
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/sparc64-sun-solaris2.8/sys-include
End of search list.
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/../../../../sparc64-sun-solaris2.8/bin/as -V -Qy -s -64 -Av9 -o /var/tmp//cc1scFwK.o /var/tmp//ccWZmCh0.s
GNU assembler version 2.11.2 (sparc64-sun-solaris2.8) using BFD version 2.11.2
/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/collect2 -V -Y P,/usr/lib/sparcv9 -Qy -o optfoo /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crt1.o /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crti.o /usr/lib/sparcv9/values-Xa.o /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crtbegin.o -L/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1 -L/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/../../../../sparc64-sun-solaris2.8/lib /var/tmp//cc1scFwK.o -lstdc++ -lm -lgcc -lc -lgcc -lc /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crtend.o /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crtn.o
GNU ld version 2.11.2 (with BFD 2.11.2)
Supported emulations:
elf64_sparc
elf32_sparc
[ - - - ]
The expected output is of the form (the first pointer value is understandably different):
netra-1:~$ /starbug/spencer/optfoo
*** begin: [0xffffffff7ffff9cf, 0, 0] end: [0xabcd, 123456, 1]
Not equal
Here is a -O2 compiled version being run on a sparc64-sun-solaris2.8 box:
netra-1:~$ /starbug/spencer/optfoo
*** begin: [0xffffffff7ffff9cf, 0, 0] end: [0xabcd, 0, 0]
equal
The begin object is usually right during the failure, but the end object is always incorrect. As is suggested by the code comments, turning off -O2 or removing the two const qualifiers on Container::iterator's members avoids this bug.
I suspect that this is the "return value optimization" acting up. I could not find a compiler option to turn off just this optimization.
>How-To-Repeat:
See description.
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted: