On 1/5/19 7:48 AM, Eric Blake wrote: > I'm fine keeping the name MIN/MAX for the common use, but we'd need a > second pair, maybe named MIN_CONST/MAX_CONST, for use in contexts that > require a constant (there, both arguments are evaluated twice because it > is the naive implementation, but that is harmless because both arguments > are constant and the macro is then usable in places where the smart > MIN/MAX are not). I don't know if trying to use __builtin_constant_p in > the const version would also be worthwhile. In fact, if > __builtin_constant_p is powerful enough, perhaps we could use it to > force a single macro to expand to the naive version if both arguments > are constant and the smart version otherwise. I'll give that a shot.
Alas, even though __builtin_constant_p can let the compiler overlook SOME cases of non-constant code (as in __builtin_constant_p(0 && foo()) returning 1), it is not powerful enough to ignore the dead branch: $ cat foo.c #define MIN(a, b) \ (__builtin_constant_p(a) && __builtin_constant_p(b) ? \ (a) < (b) ? (a) : (b) : \ ({ \ __auto_type _a = (a) + 0; \ __auto_type _b = (b) + 0; \ _a < _b ? _a : _b; \ })) char x[MIN(1, 2)]; int main(int argc, char **argv) { return MIN(argc, 0); } $ gcc -o foo -Wall foo.c foo.c:4:6: error: braced-group within expression allowed only inside a function ({ \ ^ foo.c:10:8: note: in expansion of macro ‘MIN’ char x[MIN(1, 2)]; ^~~ If anyone can come up with a workaround for single-macro usage, be my guest. Otherwise, I'm going with the two-macro solution, with MIN/MAX for common use, and MIN_CONST/MAX_CONST for constant-context use. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org
signature.asc
Description: OpenPGP digital signature