public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Possible bug in gcc 4.4.7
@ 2014-09-17 16:17 Andy Falanga (afalanga)
  2014-09-17 17:00 ` Jonathan Wakely
  0 siblings, 1 reply; 10+ messages in thread
From: Andy Falanga (afalanga) @ 2014-09-17 16:17 UTC (permalink / raw)
  To: gcc-help

Hello,

Below is a driver program which I was using to test my approach for using enumerations as flags.  I have a couple of enumerations I'm using in C++ which are bitwise flags.  The language spec, so I have learned, states that when you bitwise for enumeration values together the result is no longer an enumeration value but simply an int.  As I thought of this, this makes sense and is a wise decision for the definition.

To work around this, I've overloaded the binary operators that I'm using in the code.  The driver program shows the case in which I'm using them.  When I compile with no optimizations, the program executes as it should.  When the driver program is compiled using -O2 optimizations, which our production code is, the function Test() runs the for loop twice for each bit in the Flag parameter.  I've stepped through with gdb and the result is *not* correct.  For example,

62              for(int i = 0; f & (one | two | four | eight); ++i)
(gdb) 
64                      if(f & one)
(gdb) p/x f
$3 = 0xf
(gdb) s
66                              std::cout << "Found one" << std::endl;
(gdb) 
Found one
67                              f &= ~one;
(gdb) p/x f
$4 = 0xf
(gdb) n
62              for(int i = 0; f & (one | two | four | eight); ++i)
(gdb) p/x f
$5 = 0xe
(gdb) n
64                      if(f & one)
(gdb) 
66                              std::cout << "Found one" << std::endl;
(gdb) p/x f
$6 = 0xe

As you can see, the second time the "if(f & one)" clause is executed, the value of f is 0xe (bit 0 is off), yet the result of the bitwise and is true.  The second time f &= ~one is executed the result is still 0xe but the next time it runs through the conditional, it passes as expected.

The output from this program, when optimized, is:
Found one
Found one
Found two
Found two
Found four
Found four
Found eight
Found eight
Found four
Found four
UInt32 version
Found eight
Found eight

which is not correct.  The output is correct when the code is not optimized.  I would like to know if it is generally agreed that this is a bug in 4.4.7, or, frankly, if I've done something incorrect in the code.  I happen to have 4.8 installed on my system and this driver program (the code is below), works as expected with or without optimizations.

Thanks
Andy

#include <iostream>
#include <type_traits>

typedef unsigned int UInt32;

enum Flag {
	one = 0x1,
	two = 0x2, 
	four = 0x4,
	eight = 0x8
};

template <typename T, typename S>
struct PodToEnum {
	S s;
	operator T() { return static_cast<T>(s); }
	PodToEnum(S t) : s(t) {
		if(!std::is_integral<S>::value) {
			std::cout << "Can't convert types that aren't integers" << std::endl;
			throw "up";
		}
	}
};

template <>
struct PodToEnum<Flag, UInt32>  {
	int I;
	operator Flag() { return static_cast<Flag>(I); };
	PodToEnum(int i) : I(i) {
		std::cout << "UInt32 version" << std::endl;
		if(i != 1 && i != 2 && i != 4 && i != 8) {
			throw "up";
		}
	}
};

Flag operator|(Flag f1, Flag f2) {
	return static_cast<Flag>(int(f1) | int(f2));
}

Flag operator~(Flag f) {
	return static_cast<Flag>(~(static_cast<unsigned int>(f)));
}

Flag operator &=(Flag& f1, Flag f2) {
	return static_cast<Flag>(reinterpret_cast<unsigned int&>(f1) &= static_cast<unsigned int>(f2));
}

void Test(Flag f) {
	for(int i = 0; f & (one | two | four | eight); ++i)
	{
		if(f & one)
		{
			std::cout << "Found one" << std::endl;
			f &= ~one;
		}
		else if(f & two)
		{
			std::cout << "Found two" << std::endl;
			f &= ~two;
		}
		else if(f & four)
		{
			std::cout << "Found four" << std::endl;
			f &= ~four;
		}
		else
		{
			std::cout << "Found eight" << std::endl;
			f &= ~eight;
		}
	}
}

int main() {
	Flag f = (one | two | four | eight);
	Test(f);

	Test(static_cast<Flag>(4));
	Test(PodToEnum<Flag, UInt32>(8));
	return 0;
}

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-09-18 20:40 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-17 16:17 Possible bug in gcc 4.4.7 Andy Falanga (afalanga)
2014-09-17 17:00 ` Jonathan Wakely
2014-09-17 17:15   ` Andy Falanga (afalanga)
2014-09-17 18:05     ` Andrew Haley
2014-09-17 20:34       ` Andy Falanga (afalanga)
2014-09-18  0:12         ` Jonathan Wakely
2014-09-18 14:25           ` Andy Falanga (afalanga)
2014-09-18 17:42             ` Jonathan Wakely
2014-09-18 20:40               ` Andy Falanga (afalanga)
2014-09-17 23:57     ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).