Example of usage:
void closefrom (int lowfd);
int main()
{
// expected warning
closefrom(-1);
return 0;
}
Specifically: I should implement diagnostics (compiler warning) for function calls. Function located in glibc:
void closefrom (int lowfd);
If lowfd
is negative compiler should issue a warning.
Here is some information about closefrom
:
https://sourceware.org/pipermail/libc-alpha/2021-August/129718.html
Maybe attribute of the function will somehow help in this?
CodePudding user response:
You can do it like this, but don’t:
void foo(int x) {}
#define foo(x) foo(((int [(x) 1]){0}, (x)))
int main(void)
{
foo(-1);
return 0;
}
The macro attempts to create a compound literal consisting of an array with (x) 1
elements. If x
is negative, (x) 1
will be negative or zero, and the compiler will complain about an improper size for the array. (This may require using compiler switches to disable a zero-length array extension.) If x
is zero or positive, the compound literal will be discarded by the comma operator, and foo
will be called with argument x
. (When a macro name is used in its own replacement, it is not replaced again, so the function foo
will be called.)
Note that overflow in (x) 1
is possible. You could add a check against INT_MAX
to deal with that.
This requires that x
be some compile-time expression, which is implied in your question about how to check at compile time.
With Clang or GCC, you can combine a standard _Static_assert
with a non-standard statement expression:
#define foo(x) ({ _Static_assert((x) >= 0, "Argument to foo must be nonnegative."); foo(x); })
If foo
is always void
, you can simply use a _Static_assert
with the do … while
idiom to give it statement form when a semicolon is appended:
#define foo(x) do { _Static_assert((x) >= 0, "Argument to foo must be nonnegative."); foo(x); } while (0)
If x
can be something other than an int
, such as a floating-point type, you might want to work on the conditions a bit to deal with issues that arise in the tests and conversions.
CodePudding user response:
want to issue warning only if compiler is able to calculate the value (by optimizations, or if the value is constant). Otherwise just use function without warnin
In short, with GNU extensions:
void foo (int lowfd);
#if defined(__GNUC__) && defined(__OPTIMIZE__)
#define curb(expr, msg) \
__extension__({ \
if (__builtin_constant_p(expr)) { \
if (!(expr)) { \
__attribute__((__noinline__, \
__warning__(msg))) void warnit() {__asm__("");}; warnit(); \
} \
} \
})
#else
#define curb(expr, msg) (void)0
#endif
#define foo(x) (curb(x >= 0, "x is lower than 0"), foo(x))
int main()
{
// expected warning
foo(-1);
return 0;
}
I have this https://gitlab.com/Kamcuk/kamillibc/-/blob/master/libs/curb/src/curb.h#L46 in my tree about the idea of issuing a warning or error if the expression is known at compile time, and if it isn't, failing at runtime or not. The && defined(__OPTIMIZE__)
seems not to be needed in this case.