3

I want to use gcc to do some compile-time checking on function inputs if the compiler knows that they are constants.

I have a solution that very almost works, and as far as I can see, it should work.

Note: __builtin_constant_p(expression) is supposed to returns whether an expression is known to be a constant at compile time.

Assuming we want to check whether port<2 when calling uart(port), the following code should work:

#include <stdio.h>

void _uart(int port) {
 printf("port is %d", port);
}

#define uart(port) \
 static_assert(__builtin_constant_p(port)? port<2: 1, "parameter port must be < 2"); \
 _uart(port)

int main(void) {
 int x=1;
 uart(x);
}

This works when calling uart(). Unfortunately, it doesn't quite work for non-constant x. For some reason static_assert can't handle the case where x is not a constant, even though in theory __builtin_constant_p() won't even pass it a constant. The error message I get is:

c:\>gcc a.cpp -std=c++0x -Os
a.cpp: In function 'int main()':
a.cpp:13: error: 'x' cannot appear in a constant-expression

Any ideas?

Berwyn
  • 151
  • 7
  • 1
    The "for some reason" is that the formal grammar for "constant expression" does not have a rule for the `?` operator that says "If the left-hand side is provably `false` at compile time, then the second parameter is not required to be a constant expression." The grammar for "constant expression" says "All components (even the ones that end up not being used when evaluated) must be constant expressions." That's why the error message says "cannot appear in a constant-expression" as opposed to "cannot appear in the evaluated part of a constant-expression." – Raymond Chen Feb 25 '12 at 16:47

2 Answers2

3

Your code works with g++ (GCC) 4.8.2.

- but not with optimization, as you correctly noted.

If only we could use

static_assert(__builtin_choose_expr(__builtin_constant_p(port), \
                          port<2, 1), "parameter port must be < 2")

- but unfortunately the __builtin_choose_expr construct is currently only available for C.

However, there is a C++ patch which sadly didn't make it into the release yet.

Armali
  • 18,255
  • 14
  • 57
  • 171
  • 1
    Hmmm ... you're right it complied but it didn't actually do what I wanted because I forgot to add the compiler optimization parameter: I have now added "-Os" which reproduces the problem nicely. – Berwyn Mar 13 '14 at 20:19
2

You can try the trick used in the Linux kernel:

What is ":-!!" in C code?

The (somewhat horrible) Linux kernel macro is less strict about what kinds of expressions are allowed in the parameter.

Community
  • 1
  • 1
Igor ostrovsky
  • 7,282
  • 2
  • 29
  • 28