User account creation filtered due to spam.

Bug 36170

Summary: enum variable operation behaviour and -O2
Product: gcc Reporter: john spelis <john.spelis>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED INVALID    
Severity: normal CC: gcc-bugs, jason
Priority: P3    
Version: 4.3.0   
Target Milestone: ---   
Host: i686-pc-linux-gnu Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu Known to work:
Known to fail: Last reconfirmed:

Description john spelis 2008-05-07 15:01:33 UTC
The following program shows a case where
the 4.3.0 C++ compiler omits a check on an ENUM
variable when compiled with -O2 but keeps it when
-O is used ?

Targets where this occurs; at least x86, arm-*-linux-*


 optEnum = (Options::Id::Type) getopt_long( ... ) ;

 if( optEnum == -1 )    /* This test skipped with -O2 but not -O */
      break;

 switch( optEnum ) {
        :
 }

 The workaround for this "bug" is explicitly set
 an enum value of -1

  i.e.

      enum Type {
                eHelp = 'h',
                    ::
                Dummy = -1      /* fixes issue */
                }

 Some people say this is an interpretation of the C++ Spec
 but why does the program behaviour change so radically
 with/without the optimiser and without any warnings ?


 This behviour is reproducible with the attached program on
 an x86 build of 4.3.0

 E.g.

    ./configure --enable-languages=c,c++ --prefix=/tmp/gcc


    g++ -O -o m m.cxx
    ./m               -> program runs and exit's

    g++ -O2 -o m m.cxx
    ./m               -> program prints -1 forever


=====
m.cxx
=====

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>

typedef unsigned long uint32_t ;
typedef unsigned char uint8_t ;

#define ANSI_BOLD ""
#define ANSI_RED ""
#define ANSI_RESET ""
#define HAVE_GETOPT 1


class Background {
public:
    enum Type {
        eMandel = 0,
        eGrid,
        eFlat,
        eGouraud,
    };
};

class Options {
public:
    Options( void ) {
        memset( this, 0x00, sizeof(*this) );

        bailOut        = 4;
        maxIteration   = 240;
        size[0]        = 64;
        size[1]        = 32;
        surfSize[0]    = size[0];
        surfSize[1]    = size[1];
        offset[0]      = 0;
        offset[1]      = 0;
        coordX[0]      = -2;
        coordX[1]      =  2;
        coordY[0]      = -2;
        coordY[1]      =  2;
        bRandomColours = true;

        background     = Background::eMandel;

#if USE_HARDWARE
        bUseTCSET      = true;
#endif
    }

        bool                bAnimate;
        bool                bUseGUI;
        bool                bSetMode;
        bool                bListModes;
    bool                bDumpImage;
        bool                    bUseTCSET;
    bool                                bWantClears;
    bool                                bRandomColours;
    bool                                bFixedAspect;
    bool                                bFullScreen;
        bool                    bSingleBuffer;
        uint32_t            modeX, modeY;
        uint32_t            vidDevice;
        uint32_t                vidRotate;
    uint32_t                    bailOut;
    uint32_t                    maxIteration;
    uint32_t                    loopCount;
    uint32_t                    size[2];
    uint32_t                    surfSize[2];
    uint32_t                    offset[2];
    float                               coordX[2];
    float                               coordY[2];
    Background::Type    background;
    bool                bStall;
    uint32_t            benchmarkMode;
};

bool                gVerbose        = false;
bool                gVeryVerbose    = false;
bool                            gAbortNow               = false;


bool processArgs( int argc, char *const argv[], Options &opts )
{
#if HAVE_GETOPT
        class Options {
        public:
        class Id {
        public:
            enum Type {
                eHelp = 'h',
                eHelpL = 1,
                eSize,
                eCoords,
                eCoordSet,
                eClearFirst,
                eBail,
                eMaxIt,
                eColourMap,
                eAnimate,
                eSetMode,
                eLoop,
                eFullScreen,
                eListModes,
                eOffset,
                eAspect,
                eDemo,
                eNoSync,
                eVidDevice,
                eNoTCSET,
                eGUI,
                eDumpImage,
                eBackground,
                eRotate,
                eVerbose,
                eStall,
                eBench,
#if 0                                   /* set to '1' as workaround */
                eDummy = -1
#endif
            };
        };

        class Args {
        public:
            enum Type {
                eNone,
                eReq,
                eOpt,
            };
        };

                const char      *name;
                Options::Args::Type      args;
                Id::Type        id;
                const char      *help;
        };
        Options::Id::Type optEnum;
        int         optIndex;
        uint32_t        i;
        bool        bSuccess = true;

        static Options     options[] = {
                { "help",        Options::Args::eNone, Options::Id::eHelp,       "Show this help message" },
                { "size",        Options::Args::eReq,  Options::Id::eSize,       "Size of rendered image" },
                { "coords",      Options::Args::eReq,  Options::Id::eCoords,     "Co-ordinates of rendered image" },
                { "coordSet",    Options::Args::eReq,  Options::Id::eCoordSet,   "Select a predefined set of co-ordinates" },
                { "clearFirst",  Options::Args::eNone, Options::Id::eClearFirst, NULL },
                { "bail",        Options::Args::eReq,  Options::Id::eBail,       "Bailout value" },
                { "maxIt",       Options::Args::eReq,  Options::Id::eMaxIt,      "Maximum iteration count" },
                { "colourMap",   Options::Args::eReq,  Options::Id::eColourMap,  "Set the colour style" },
                { "animate",     Options::Args::eNone, Options::Id::eAnimate,    "Run in animation mode" },
                { "setMode",     Options::Args::eOpt,  Options::Id::eSetMode,    "Set the given video mode" },
                { "loop",        Options::Args::eOpt,  Options::Id::eLoop,       "Number of times to loop in animation mode" },
                { "fullScreen",  Options::Args::eNone, Options::Id::eFullScreen, "Buffer size matches video resolution even if render size is smaller" },
                { "listModes",   Options::Args::eNone, Options::Id::eListModes,  "List available video modes" },
                { "offset",      Options::Args::eOpt,  Options::Id::eOffset,     "Offset to render area if render size is smaller than video resolution" },
                { "aspect",      Options::Args::eOpt,  Options::Id::eAspect,     "Keep 1:1 aspect ratio or stretch to fill" },
                { "demo",        Options::Args::eNone, Options::Id::eDemo,       "Enable demo mode (480x272 animation)" },
                { "noSync",      Options::Args::eNone, Options::Id::eNoSync,     "Disable video sync by running single buffered" },
                { "vidDevice",   Options::Args::eReq,  Options::Id::eVidDevice,  "Use the given video device" },
                { "noTCSET",     Options::Args::eNone, Options::Id::eNoTCSET,    "Do not use the TCSET ioctl" },
                { "gui",         Options::Args::eNone, Options::Id::eGUI,        "Run in GUI mode" },
                { "dump",        Options::Args::eNone, Options::Id::eDumpImage,  "Dump the rendered image as ascii text" },
                { "back",        Options::Args::eReq,  Options::Id::eBackground, "Set the background style for animation mode" },
                { "rotate",      Options::Args::eReq,  Options::Id::eRotate,     "Rotate the video output by 90, 180, 270, FlipV, FlipH" },
                { "verbose",     Options::Args::eNone, Options::Id::eVerbose,    "Enable debugging output" },
                { "stall",       Options::Args::eNone, Options::Id::eStall,      "Stall on the first frame" },
                { "bench",       Options::Args::eOpt,  Options::Id::eBench,      "Benchmark mode" },
        };

asm("L:");

        while( 1 ) {
                optEnum = (Options::Id::Type) getopt_long( argc, argv, "h", NULL, &optIndex);
                if( optEnum == -1 )
                        break;

                switch( optEnum ) {
                    case Options::Id::eVerbose:
                gVerbose = true;
                gVeryVerbose = true;
            continue;

                    case Options::Id::eHelp:
                    case Options::Id::eHelpL:
                printf( "Mandelbrot options:\n" );
                bSuccess = false;

                    continue;

                        case Options::Id::eBail:
                                opts.bailOut = atoi( optarg );
                                printf("Setting bail out to %d\n", opts.bailOut);
                        continue;

                        case Options::Id::eMaxIt:
                                opts.maxIteration = atoi( optarg );
                                printf("Setting maximum iteration to %d\n", opts.maxIteration);
                        continue;

                        case Options::Id::eColourMap:
                                opts.bRandomColours = atoi( optarg );
                                printf("Setting colour map to type #%d\n", opts.bRandomColours);
                        continue;

                        case Options::Id::eCoordSet:
                                i = atoi(optarg);
                                switch( i ) {
                                        case 0:
                                                opts.coordX[0] = -2;                            opts.coordX[1] = 2;
                                                opts.coordY[0] = -2;                            opts.coordY[1] = 2;
                                                opts.bRandomColours = true;
                                        break;

                                        case 1:
                                                opts.coordX[0] = -0.55472656250f;       opts.coordX[1] =  0.016328125f - 0.55472656250f;
                                                opts.coordY[0] = -0.50505859375f;       opts.coordY[1] =  0.016328125f - 0.50505859375f;
                                                opts.bRandomColours = false;
                                        break;

                                        default:
                                                fprintf(stderr, ANSI_BOLD ANSI_RED "Invalidate co-ordinate set request: %d!" ANSI_RESET "\n", i);
                                }

                                printf( "Coords set to (%f, %f) -> (%f, %f)\n", opts.coordX[0], opts.coordY[0], opts.coordX[1], opts.coordY[1] );
                        continue;

                        case Options::Id::eSize:
                                sscanf( optarg, "%dx%d", &opts.size[0], &opts.size[1] );
                                printf( "Size set to %d x %d\n", opts.size[0], opts.size[1] );
                        continue;

                        case Options::Id::eOffset:
                                if( optarg ) {
                                        sscanf( optarg, "%d,%d", &opts.offset[0], &opts.offset[1] );
                                        printf( "Offset set to (%d, %d)\n", opts.offset[0], opts.offset[1] );
                                } else
                                        opts.offset[0] = opts.offset[1] = ~0U;
                        continue;

                        case Options::Id::eCoords:
                                sscanf( optarg, "%f,%f,%f,%f", &opts.coordX[0], &opts.coordY[0], &opts.coordX[1], &opts.coordY[1] );
                                printf( "Coords set to (%f, %f) -> (%f, %f)\n", opts.coordX[0], opts.coordY[0], opts.coordX[1], opts.coordY[1] );
                        continue;

                        case Options::Id::eClearFirst:
                                opts.bWantClears = true;
                        continue;

                        case Options::Id::eAnimate:
                                opts.bAnimate = true;
                        continue;

                        case Options::Id::eGUI:
                                opts.bUseGUI = true;
                        continue;

                        case Options::Id::eDumpImage:
                                opts.bDumpImage = true;
                        continue;

                        case Options::Id::eSetMode:
                                opts.bSetMode = true;

                                if( optarg ) {
                                        sscanf( optarg, "%dx%d", &opts.modeX, &opts.modeY );
                                        printf( "Mode size set to %d x %d\n", opts.modeX, opts.modeY );
                                }
                        continue;

                        case Options::Id::eVidDevice:
                                sscanf( optarg, "%d", &opts.vidDevice );
                                printf( "Video device set to %d\n", opts.vidDevice );
                        continue;

                        case Options::Id::eListModes:
                                opts.bListModes = true;
                        continue;

                        case Options::Id::eLoop:
                                if( optarg ) {
                                        sscanf( optarg, "%d", &opts.loopCount );
                                        printf( "Loop count set to %d\n", opts.loopCount );
                                        opts.loopCount--;
                                } else
                                        opts.loopCount = ~0;
                        continue;

                        case Options::Id::eFullScreen:
                                opts.bFullScreen = true;
                        continue;

                        case Options::Id::eAspect:
                                if( optarg ) {
                                        sscanf( optarg, "%d", &i );
                                        opts.bFixedAspect = i ? true : false;
                                        printf( "Fixed aspect set to %d\n", opts.bFixedAspect );
                                } else
                                        opts.bFixedAspect = true;
                        continue;

                        case Options::Id::eNoSync:
                                opts.bSingleBuffer = true;
                        continue;

                        case Options::Id::eNoTCSET:
                                opts.bUseTCSET = false;
                        continue;

                        case Options::Id::eDemo:
                if( gVerbose )  printf( "Running with demo options.\n" );

                                opts.bFixedAspect = true;
                                opts.bFullScreen  = true;
                                opts.bAnimate     = true;
                                opts.bSetMode     = true;
                                opts.loopCount    = 1;
                                opts.offset[0]    = ~0U;
                                opts.offset[1]    = ~0U;
                                opts.size[0]      = 272;
                                opts.size[1]      = 272;
                        continue;

                        case Options::Id::eBackground:
                                sscanf( optarg, "%d", &i );
                                opts.background = (Background::Type) i;
                                printf( "Background style set to %d\n", opts.background );
                        continue;

                        case Options::Id::eRotate:
                                sscanf( optarg, "%d", &opts.vidRotate );
                                printf( "Video rotation set to %d\n", opts.vidRotate );
                        continue;

                        case Options::Id::eStall:
                                opts.bStall = true;
                        continue;

                        case Options::Id::eBench:
                                if( optarg )
                    sscanf( optarg, "%d", &opts.benchmarkMode );
                else
                    opts.benchmarkMode = 1;
                printf( "Benchmark mode set to %d\n", opts.benchmarkMode );
                        continue;

                        default:
                        break;
                }

                fprintf(stderr, ANSI_BOLD ANSI_RED "Got unknown option id: %d!" ANSI_RESET "\n", optEnum);
                bSuccess = false;
        }

        return bSuccess;
#else
    fprintf(stderr, ANSI_BOLD ANSI_RED "No getopt. Ignoring command line arguments!" ANSI_RESET "\n");
    return true;
#endif
}


int main( int argc, char *argv[] )
{
        bool    bSuccess = true;
        const char      *env;
        class Options opts ;

        if( !processArgs(argc, argv, opts) ) {
                fprintf( stderr, ANSI_BOLD ANSI_RED "Failed to process command line arguments!" ANSI_RESET "\n" );
                bSuccess = false;
        }

 return(0) ;
}
Comment 1 Andrew Pinski 2008-05-07 17:23:45 UTC
And C++ standard says if the value is out of range of the enum, the behavior is undefined so this is not a bug.
Comment 2 john spelis 2008-05-07 18:38:56 UTC
Subject: Re:  enum variable operation behaviour and -O2


Thanks for ending that issue.
Best Regards


On 7 May 2008, pinskia at gcc dot gnu dot org wrote:

> 
> 
> ------- Comment #1 from pinskia at gcc dot gnu dot org  2008-05-07 17:23 -------
> And C++ standard says if the value is out of range of the enum, the behavior is
> undefined so this is not a bug.
> 
> 
> -- 
> 
> pinskia at gcc dot gnu dot org changed:
> 
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>              Status|UNCONFIRMED                 |RESOLVED
>          Resolution|                            |INVALID
> 
> 
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36170
> 
> ------- You are receiving this mail because: -------
> You reported the bug, or are watching the reporter.
> 

Comment 3 Jason Merrill 2010-05-04 04:49:33 UTC
In G++ 4.6 the surprising optimization will only be performed with -fstrict-enums.