gebjon
gebjon

Reputation: 131

gcc unexpected C static_assert error: expression in static assertion is not constant

I have some C code which builds OK with gcc-11 and earlier but not gcc-12 and later. This illustrates the problem (this isn't the actual code I'm working on):

#include <stdint.h>
#include <assert.h>

// forward testfunc declaration
void testfunc(int testvar);

int main()
{
  static_assert(((uintptr_t)testfunc != 0), "error!!");
}

// testfunc definition
void testfunc(int testvar) {}

see also: https://godbolt.org/z/vMf31zoaT

With gcc-12, if I move the testfunc() definition before main(), then it builds OK. But with testfunc() after main(), I get the build error: error: expression in static assertion is not constant

I don't understand why I get this error as the function address is constant. This occurs several times in the existing code I'm working on. I could fix it by modifying the code, but I'd prefer not to as it would mean a lot of changes. Any ideas how to fix this? Just to be clear: the code above illustrates the problem. The actual code I'm working on uses static_assert in a macro to detect if a const function pointer is set to NULL in error, but it gets the same error with gcc-12.

Upvotes: 3

Views: 143

Answers (1)

John Bollinger
John Bollinger

Reputation: 181849

I don't understand why I get this error as the function address is constant.

Yes, the function address is constant, in the sense that C defines it as an address constant, one of the forms of constant expression. (C17 6.6/9)

But C places a stronger requirement on the expression in a static assertion: it must be an integer constant expression, and even though your expression has integer type, it does not qualify. These are the requirements:

An integer constant expression shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, _Alignof expressions, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof or _Alignof operator.

(C17 6.6/6)

Pointers are not among the operands the spec allows in integer constant expressions, neither in general nor as operands in cast (sub)expressions, except that they probably may appear in sizeof and _Alignof (sub)expressions.

Any ideas how to fix this?

Option 1: Remove the static assertions in question. If your program contains (direct) calls to undefined functions, or if it attempts to take the address of an undefined function, then you will know it because of link errors. On the other hand, until linking, your C implementation does not know whether there are any such calls, so even if it accepted static assertions such as those in your example, they would not tell you anything useful.

Option 2: Convert the static assertions to ordinary assertions. The expression in an ordinary assertion does not even have to be a constant expression, much less an integer constant expression. Of course, these are not evaluated until runtime, and depending on how you build the program, they may be suppressed so that they are not evaluated at all.

Option 3: Stick with Gcc 11, since that apparently accepts the static assertions you have (which it is within its rights to do). This is probably not a viable long-term strategy, but it can keep your builds working until you finish implementing option 1 or 2.

I looked for a command-line option in Gcc 12 that would provide the old behavior for such assertions, but if there is one, it eluded me.

Upvotes: 5

Related Questions