Bug 33012 - ICE on throwing copy of object returned by reference from method with traits-deduced return-type
Summary: ICE on throwing copy of object returned by reference from method with traits-...
Status: RESOLVED WORKSFORME
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.1.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-08-07 17:46 UTC by Raymond Russell
Modified: 2007-08-16 09:50 UTC (History)
2 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work: 4.1.2 4.2.1 4.3.0
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Raymond Russell 2007-08-07 17:46:32 UTC
Compiling a .cpp file with the following contents triggers an internal compiler
error:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

/*
 * The two Traits templates here are essentially std::iterator_traits 
 * stripped right down with just enough left to make the test-case work:
 */

template<typename _Type> struct Traits;
template<typename _Type>
struct Traits<_Type *> { typedef _Type& reference; };


/*
 * TraitedWrapper is essentially __gnu_cxx::__normal_iterator stripped
 * to the minimum required to make the test-case work:
 */

template<typename _Pointer>
class TraitedWrapper {
public:
	typedef	typename Traits<_Pointer>::reference	reference;


	TraitedWrapper(const _Pointer pointer) : pointer_(pointer) { }

	reference get() const	{ return *pointer_; }

private:
	_Pointer pointer_;
};


/*
 * SpecialWrapper is essentially a form of TraitedWrapper that is
 * specialised for the pointer case in the way that Traits is.
 */

template<typename _Type>	class SpecialWrapper;
template<typename _Type>
class SpecialWrapper<_Type *> {
public:
	SpecialWrapper(_Type *pointer) : pointer_(pointer) { }

	_Type get() const	{ return *pointer_; }

private:
	_Type *pointer_;
};




/*
 * inner() throws a copy of an object returned by reference from
 * a method whose return-type is sometimes deduced by some template
 * indirection.  It's templated to show what happens with different
 * combinations of return-type deduction and copy-constructor origin.
 */

template<template<typename> class _Wrapper, typename _Type>
void	inner()
{
	_Type orig;
	_Wrapper<_Type *> wrapper(&orig);

/*
 * No problem copy-constructing a stack-variable from the iterator:
 */
	_Type copy(wrapper.get());
	if( true )
/*
 * No problem throwing the stack-variable:
 */
		throw copy;
	else
/*
 * ICE can happen here, when directly throwing a copy,
 * depending on template parameters:
 */
		throw _Type(wrapper.get());
}


struct Generated { };

struct Manual {
	Manual() { }
	Manual(const Manual&) { }
};


void	outer()
{
	inner<SpecialWrapper, Manual>();
	inner<SpecialWrapper, Generated>();
	inner<TraitedWrapper, Manual>();

/*
 * ICE when the wrapper get-method has a traits-deduced return-type
 * and the class has a compiler-supplied copy-constructor:
 */
	inner<TraitedWrapper, Generated>();
}

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


Issued command-line:
    g++ -Wall -W -Wundef -Wpointer-arith -g -O0 -c -o /dev/null bug.cpp

Resulting output:
    bug.cpp: In function 'void inner() [with _Wrapper = TraitedWrapper, _Type = Generated]':
    bug.cpp:101:   instantiated from here
    bug.cpp:79: internal compiler error: in stabilize_call, at cp/tree.c:2248
    Please submit a full bug report,
    ...

Full output from running with "-v --save-temps" is as follows:
    g++ -v -save-temps -Wall -W -Wundef -Wpointer-arith -g -O0 -c -o /dev/null bug.cpp
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../gcc-4.1.1/configure --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-languages=c,c++
Thread model: posix
gcc version 4.1.1
 /usr/local/libexec/gcc/i686-pc-linux-gnu/4.1.1/cc1plus -E -quiet -v -D_GNU_SOURCE bug.cpp -mtune=pentiumpro -Wall -W -Wundef -Wpointer-arith -fworking-directory -O0 -fpch-preprocess -o bug.ii
ignoring nonexistent directory "NONE/include"
ignoring nonexistent directory "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/../../../../i686-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/../../../../include/c++/4.1.1
 /usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/../../../../include/c++/4.1.1/i686-pc-linux-gnu
 /usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/../../../../include/c++/4.1.1/backward
 /usr/local/include
 /usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include
 /usr/include
End of search list.
 /usr/local/libexec/gcc/i686-pc-linux-gnu/4.1.1/cc1plus -fpreprocessed bug.ii -quiet -dumpbase bug.cpp -mtune=pentiumpro -auxbase-strip /dev/null -g -O0 -Wall -W -Wundef -Wpointer-arith -version -o bug.s
GNU C++ version 4.1.1 (i686-pc-linux-gnu)
        compiled by GNU C version 4.1.1.
GGC heuristics: --param ggc-min-expand=63 --param ggc-min-heapsize=63424
Compiler executable checksum: 5c1ee95ea2451a4e1aafd30c10a207cb
bug.cpp: In function 'void inner() [with _Wrapper = TraitedWrapper, _Type = Generated]':
bug.cpp:101:   instantiated from here
bug.cpp:79: internal compiler error: in stabilize_call, at cp/tree.c:2248
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Comment 1 Raymond Russell 2007-08-07 17:59:23 UTC
I have been able to reproduce the same ICE in 3.4.2,

    gcc version 3.4.2 20040827 (prerelease) [FreeBSD]

but not in 2.95.4 or 4.1.2:

    gcc version 2.95.4 20020320 [FreeBSD]
    gcc version 4.1.2 (Ubuntu 4.1.2-0ubuntu4)


I originally found the ICE in some code that was throwing a copy of an object in a std::vector on the stack.  By playing around with the test code I posted, I found that it seems to trigger only when the following three conditions occur together:

* the copy is directly thrown, and not when the a copy is declared on the stack and then thrown;
* the method that provides the reference to be copied has a return-type deduced from a traits template;
* the class of the object being thrown does not provide a copy-constructor.

I've tried to illustrate in the full test case that, if any one of these conditions is false, then the ICE doesn't happen.


The following shorter test-case also triggers the error.  I know it includes a standard header, and I haven't provided pre-processed sources for this, but it's just for illustration purposes.

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#include <vector>

/*
 * inner() throws a copy of an object contained in a vector.
 * It's templated to show what happens with different _Types.
 */

template<typename _Type>
void	inner()
{
	typename std::vector<_Type> vector(1);
	throw _Type(*vector.begin());
}


struct Generated { };

struct Manual {
	Manual() { }
	Manual(const Manual&) { }
};


void	outer()
{
// No problems when the class has a hand-written copy-constructor:
	inner<Manual>();

// ICE when the class has a compiler-supplied copy-constructor:
	inner<Generated>();
}

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Comment 2 Paolo Carlini 2007-08-15 09:14:04 UTC
So the problem is already fixed in all the active branches. Thanks, anyway!
Comment 3 Raymond Russell 2007-08-16 09:50:19 UTC
Yes, it does not happen with recent releases.  I logged it because I couldn't find any hint of this problem having been seen and noted anywhere.  I just wanted to let you know about it in case the problem has simply been masked by recent code changes rather than specifically fixed (not that I'm suggesting it has ;-) I just don't know).  Thanks!