Bug 42576 - GCC miscompiles switch statement (omits case label/block)
Summary: GCC miscompiles switch statement (omits case label/block)
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.4.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-01-01 19:16 UTC by Karel Gardas
Modified: 2010-01-01 20:34 UTC (History)
1 user (show)

See Also:
Host: i386-pc-solaris2.11
Target: i386-pc-solaris2.11
Build: i386-pc-solaris2.11
Known to work:
Known to fail:
Last reconfirmed:


Attachments
MICO's head preprocessed typecode.cc file (139.76 KB, application/octet-stream)
2010-01-01 19:20 UTC, Karel Gardas
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Karel Gardas 2010-01-01 19:16:28 UTC
Hello,
first of all, I've tried hard to judge if MICO[1] code is wrong or GCC is wrong in this case, but I still think GCC is wrong here, hence reporting this. I'm not able to simplify testcase for this, but we're using following idiom:

#include <iostream>
#include <cassert>

using namespace std;

#define TK_RECURSIVE ((int)0xffffffff)

class TypeCode {
public:
    int tckind;

    TypeCode(int v)
        : tckind(v)
    {}
};

int
main(int argc, char* argv[])
{
    TypeCode* tc = NULL;
    if (argc > 5) {
        tc = new TypeCode(TK_RECURSIVE);
    }
    else {
        tc = new TypeCode(argc);
    }
    switch (tc->tckind) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        cout << "number supplied" << endl;
        break;
    case TK_RECURSIVE:
        cout << "TK_RECURSIVE is working!" << endl;
        break;
    default:
        cout << "C++ Compiler BUG!" << endl;
        assert(0);
    }
    return 0;
}


i.e. quite long switch statement of `int' where (int)0xffffffff is used as a case label this everything done in object (C++ class). Some case blocks are also rather large (several C++ code lines) Please note: the code above just shows an idiom, but is not able to duplicate my issue. First problem seems to be shown by GCC complaining with a warning like:

typecode.cc: In member function ‘CORBA::Boolean CORBA::TypeCode::equal(CORBA::TypeCode*, CORBA::Boolean, CORBA::Boolean) const’:
typecode.cc:750: warning: case label value is less than minimum value for type
typecode.cc: In member function ‘CORBA::Boolean CORBA::TypeCode::equaltype(CORBA::TypeCode*, std::set<std::pair<CORBA::TypeCode*, CORBA::TypeCode*>, std::less<std::pair<CORBA::TypeCode*, CORBA::TypeCode*> >, std::allocator<std::pair<CORBA::TypeCode*, CORBA::TypeCode*> > >*)’:
typecode.cc:827: warning: case label value is less than minimum value for type
typecode.cc: In member function ‘CORBA::Boolean CORBA::TypeCode::decode(CORBA::DataDecoder&, std::map<long unsigned int, std::pair<long unsigned int, CORBA::TypeCode*>, std::less<long unsigned int>, std::allocator<std::pair<const long unsigned int, std::pair<long unsigned int, CORBA::TypeCode*> > > >*, CORBA::ULong)’:
typecode.cc:1672: warning: case label value is less than minimum value for type
typecode.cc: In member function ‘void CORBA::TypeCode::encode(CORBA::DataEncoder&, std::map<const CORBA::TypeCode*, long unsigned int, std::less<const CORBA::TypeCode*>, std::allocator<std::pair<const CORBA::TypeCode* const, long unsigned int> > >*) const’:
typecode.cc:1913: warning: case label value is less than minimum value for type

so GCC does not like our code that much, although I think it's completely legal (the same code is well compilable by GCC up to 4.3.x version, Sun C++ up to 5.10 and Intel C++, the issue starts with GCC 4.4.x).
The second problem seems to be that GCC completely omits generating code for this as it thinks bad case label block. This results in a switch statement code being corrupted and application not working well. Concretely I'm seeing asserts done in default switch block.
I've tested simple workaround which is moving problematic case block in front of the switch block into simple `if' statement and this works well. Fully preprocessed source code is attached for your reference, you can find appropriate lines following warnings above inside it.
Thanks for looking into it!
Karel
[1]: www.mico.org
Comment 1 Karel Gardas 2010-01-01 19:20:46 UTC
Created attachment 19438 [details]
MICO's head preprocessed typecode.cc file
Comment 2 Andrew Pinski 2010-01-01 19:21:37 UTC
If tckind is really an enum, then the behavior of gcc is correct.
Comment 3 Andrew Pinski 2010-01-01 19:23:45 UTC
And it is. ((int)0xffffffff) is ouside the range of the enum is gcc's behavior is correct.
Comment 4 Richard Biener 2010-01-01 19:43:08 UTC
new TypeCode(TK_RECURSIVE); is undefined and TK_RECURSIVE will
be truncated to fit the enum.  That might be the issue that actually
breaks this.
Comment 5 Karel Gardas 2010-01-01 20:34:58 UTC
yes, tckind is enum. Thanks for pointing out that this is MICO code issue. If you also could be so kind and cite some C++/C language specification point which GCC follows here and which all older GCC releases "overlooked" (or does not implement support for) as does Sun's C++ and Intel C++ that would be great. I find somehow silly that while using GCC 4.4.x (1) I'm able to assign arbitrary value to enum type variable w/o any warning, (2) I'm able to use arbitrary int for comparison with enum and (3) if I set enum variable value to arbitrary integer I'm able to use this arbitrary integer in `if/else' comparison successfully so the assignment nor comparison is not truncated to enum value IMHO, yet still it does omit my arbitrary integer from switch/case. Isn't this kind of strange? Thanks!