Eric Sosman said:
Because, rather than following the advice I give several times a
week to copy-and-paste actual code rather than paraphrasing it by
re-typing it, I paraphrased the actual code by re-typing it and
got it wrong in a way that destroyed the point I was trying to make.
Here's the actual code:
#include<assert.h>
int main(void) {
(assert)(0);
return 0;
}
And here are the error messages from the compiler:
c.c: In function 'main':
c.c:3: error: 'assert' undeclared (first use in this function)
c.c:3: error: (Each undeclared identifier is reported only once
c.c:3: error: for each function it appears in.)
Interestingly, the diagnostic is not required. Quoth the
Standard: "If the macro definition is suppressed in order to access
an actual function, the behavior is undefined," and "undefined"
includes the possibility that no diagnostic appears, that the code
compiles, and that any oddities happen at run-time. [snip]
I'm not sure if you're meaning to make a subtle point or if
you've just overlooked something. If the identifier 'assert' is
not declared (or defined as an enumeration constant), then in
fact a diagnostic must be issued. The Standard is quite clear
about this, in 5.1.1.3p1, when it says a diagnostic must be
produced whenever there is
a violation of any syntax rule or constraint, even if
the behavior is also explicitly specified as undefined
or implementation-defined.
If 'assert' hasn't been declared (or defined as an enumeration
constant), then it doesn't match the syntax for primary-expression,
which requires a diagnostic, even if there is undefined behavior.
The subtlety is whether <assert.h> is allowed to declare 'assert'
as a regular identifier (or define it as an enumeration constant).
My impression is that it is not. For example, consider
enum blah { assert = 0 };
#include <assert.h>
int main(){ return assert; }
I believe this program is supposed to be strictly conforming.
Another possibility: could 'assert' be defined as an object-like
macro rather than a function-like macro? Again my impression is
that it cannot. Another program:
struct { int assert; } x = 0;
#include <assert.h>
int main(){ return x.assert; }
Here again I believe this program is supposed to be strictly
conforming. More specifically, for both programs I'm not
aware of any restriction that has been violated.
The weak point of the above comments is that the Standard never
says specifically (at least not as far as I'm aware) that the
definition for 'assert' must be as a function-like macro and not as
an object-like macro (assuming NDEBUG is not defined). However,
all the evidence I'm aware of makes the 'must be a function-like
macro' choice appear to be the more reasonable one.