Home > Software engineering >  constexpr_assert on embedded (--fno-exceptions)
constexpr_assert on embedded (--fno-exceptions)

Time:06-30

Is it possible to implement a thing such as "constexpr assert" on bare metal? I would normally use a throw statement as it is mentioned here for example. But the compiler rejects the code because of --fno-exceptions even though throw is used only in a constant evaluated context.

My implementation:

inline constexpr void constexpr_assert(bool condition)
{
        if (std::is_constant_evaluated())
        {
            if (!condition)
            {
                throw; //  error: exception handling disabled, use '-fexceptions' to enable
            }
        }
        else
        {
            assert(condition);
        }
}

Potential usage:

class EventMask
{
    uint32_t mask;

public:
    static constexpr auto MAX_ID = 31;

    constexpr EventMask(unsigned int event_id)
        : mask(static_cast<uint32_t>(1u) << event_id)
    {
        constexpr_assert(event_id <= MAX_ID);
    }
};


int main(int argc, char** argv)
{
    EventMask s_ev(55); // this should fail on compilation time
    EventMask d_ev(argc); // this could fail in the runtime 
}

My compiler is (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1

CodePudding user response:

Since you know you're being constant evaluated, all you need to trigger a failure is to do something that's not valid to do during constant evaluation.

The easiest of these is to invoke a non-constexpr function:

void on_error(char const* msg) {
   // some code here... or not
}

Which you can then:

if (std::is_constant_evaluated())
{
    if (!condition)
    {
        on_error("this is bad because of some reason that hopefully fits in a literal");
    }
}

Obviously not the greatest solution, but at least you would get an error right here. gcc for instance gives a compile error like:

<source>:8:21: error: call to non-'constexpr' function 'void on_error(const char*)'
    8 |             on_error("bad!");
      |             ~~~~~~~~^~~~~~~~

Though I guess in this context, the string literal would come from the caller, and so it'd still show up in the call stack. Maybe then on_error() should just take no parameters.

  • Related