0

main.cpp :

#include "timer.hpp"

int main() {
    TCC_TIMER<0> speed_timer;
    TC_TIMER<3, TIMER_16BIT> update_timer;

    speed_timer = TCC_TIMER<0>::Instance();
    update_timer = TC_TIMER<3, TIMER_16BIT>::Instance();

    for(;;);
}

timer.hpp :

#ifndef TIMER_HPP
#define TIMER_HPP

class TIMER_GENERAL {
    protected:
        TIMER_GENERAL() : initialized(false) {};
        ~TIMER_GENERAL() {};

        inline void Init(int number) {
            timer_number = number;
            initialized = true;
        }

        inline bool Initialized(void) {
            return initialized;
        }

        bool initialized;
        int timer_number;
};

class TIMER_16BIT : public TIMER_GENERAL {
    protected:
};

template <class T>   
class TIMER_TC : public T {
    protected:
};

class TIMER_TCC : public TIMER_GENERAL {
    public:
};

template <int number, class T>
class TC_TIMER : public TIMER_TC<T> {
    public:
        static TC_TIMER<number, T>& Instance(void) {
            static TC_TIMER<number, T> timer;
            if(!timer.initialized) {
                timer.Init(number);
            }
            return timer;
        }
};

template <int number>
class TCC_TIMER : public TIMER_TCC {
    public:
        static TCC_TIMER<number>& Instance(void) {
            static TCC_TIMER<number> timer;
            if(!timer.initialized) {
                timer.Init(number);
            }
            return timer;
        }
};

#endif  /* TIMER_HPP */

When I compile this code with g++ 7.5.0:

g++ -O3 -Wall -std=c++17 main.cpp

I get a warning in the TCC_TIMER class:

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]:  
if(!timer.initialized) {  

In TC_TIMER however, I do exactly the same and get no warning.

If I deliberately introduce an error by inserting:

timer = timer + 1;

just before the line with the warning, I get the error:

no match for 'operator+' (operand types are 'TCC_TIMER<0>' and 'int')  

which indicates that the compiler knows that timer has the type TCC_TIMER<0>.

Also, when I explicitly cast timer to TCC_TIMER<0>:

if(!static_cast<TCC_TIMER<0>>(timer).initialized) {

the compiler is happy and the warning disappears.

If I use a function instead:

if(!timer.Initialized()) {

everything is ok too.

Can anyone explain why I get this warning in the TCC_TIMER class and not in the TC_TIMER class?

Can anyone explain why I do get this warning while the timer type seems to be ok?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
eijkel
  • 1
  • 1
  • 1
    Odd that it errors about a type-punned pointer, when there are no pointers shown in this code. Must be a compiler bug. – Remy Lebeau May 19 '20 at 23:15
  • A recent clang does not emit any warnings on that code – Marshall Clow May 19 '20 at 23:22
  • Does the warning go away if you omit the redundant ``s in the `TCC_TIMER` class template definition? – Davis Herring May 20 '20 at 00:21
  • No, the warning does not go away. – eijkel May 20 '20 at 13:14
  • @RemyLebeau: Perhaps the people who wrote different parts of gcc were unclear about what actions by intermediate code should have defined behavior, so one part of the compilation process transformed the code into a form that its authors thought was defined behavior because there was no reason downstream parts shouldn't be able to handle it, but the authors of the downstream part made it deliberately blind to behaviors they didn't want programmers to use. – supercat May 22 '20 at 17:27

0 Answers0