With the following code,
#define REINT(T, X) (union {__typeof__(X) x; T t;}){X}.t
int f2i(float x) {
return REINT(int, x);
}
float i2f(int x) {
return REINT(float, x);
}
float f2i2f(float x) {
return REINT(float, REINT(int, x));
}
Clang complains about f2i2f
that an "initializer element is not a compile-time constant". This seems odd because compound literals "have automatic storage duration associated with
the enclosing block" (6.5.2.5p5), and the elements in the initializer list for such objects don't have to be compile-time constants.
CodePudding user response:
In the comments under the question, it was mentioned that this is a known bug, and "it is quite an old bug still not fixed". So until it's fixed, you'll have to work around it.
The simplest code I could find that triggers the bug is
int x = 3.0;
struct { __typeof__((int){x}) y; };
The bug is triggered when:
- a compound literal with a non-constant initializer
- is used in the argument to
__typeof__
- in the declaration of a member variable in either a
struct
or aunion
When the REINT
macro is used in the f2i
and i2f
functions, it doesn't trigger the bug because argument X
is not a compound literal. X
in those functions is a variable with a primitive type.
But in the f2i2f
function, the argument X
passed to the outer invocation of REINT
contains a compound literal. And that compound literal is part of the argument to a __typeof__
that is used in the definition of the outer union
.
So the workaround is to avoid nesting the REINT
macro. For example, f2i2f
can be implemented as follows:
float f2i2f(float x) {
int temp = REINT(int, x);
return REINT(float, temp);
}