cgcclanguage-lawyernull-pointerc23

Why isn't the keyword false an integer constant expression in gcc C23?


Latest gcc 13.x (trunk) gives a compiler error (gcc -std=c23) for this code:

int* p = false;

error: incompatible types when initializing type 'int *' using type '_Bool'

How can this be correct?


C23 6.2.5 §8-9 (Types - the definition of integer types):

The type bool and the unsigned integer types that correspond to the standard signed integer types are the standard unsigned integer types.

The standard signed integer types and standard unsigned integer types are collectively called the standard integer types;

C23 6.6 §8 (Constant expressions - the definition of an integer constant expression):

An integer constant expression shall have integer type...

C23 6.3.2.3 (Pointers - the definition of null pointer constant)

An integer constant expression with the value 0, such an expression cast to type void *, or the predefined constant nullptr is called a null pointer constant

C23 6.5.16.1 (Simple assignment):

Constraints
/--/

  • the left operand is an atomic, qualified, or unqualified pointer, and the right operand is a null pointer constant

Conclusion:

Did I misunderstand anything in the standard or is this a gcc bug? clang gives a warning but still produces an executable. I don't really see how any of the above has changed in C23 either.

Including stdbool.h and compiling under gcc -std=c17 -pedantic-errors makes it compile cleanly as expected.


Solution

  • In addition to the paragraphs quoted in the question, there is paragraph 6.4.4.5/3:

    The keywords false and true are constants of type bool with a value of 0 for false and 1 for true.

    and 6.6/7:

    An identifier that is:
    [...]
    — a predefined constant;
    [...]
    is a named constant

    That makes false a named constant, which is relevant because a fuller quotation of 6.6/8 is

    An integer constant expression shall have integer type and shall only have operands that are integer constants, named and compound literal constants of integer type [...]

    (emphasis added).

    Regardless, then, of GCC implementation details surrounding the constant false, when taken as an expression, false meets C23's criteria for an integer constant expression. Its value is specified to be 0. It is therefore a valid null pointer constant.

    GCC's behavior here is contrary to the language spec.


    I don't really see how any of the above has changed in C23 either.

    None of the points you were referring to changed in C23, but what did change is the type of false and true. In C17, these had type int. In C23, they have type bool (a.k.a. _Bool). As you observe, however, bool is an integer type, so GCC not allowing that as the type of a null pointer constant is non-conforming.

    I note that GCC 8.5 does not accept _Bool as a valid type for a null pointer constant, either. Given this source:

    void *test = (_Bool)0;
    
    int main(void) {
    }
    

    , it fails with the same error you observed:

    npctest.c:1:14: error: incompatible types when initializing type ‘void *’ using type ‘_Bool’

    Thus, your observation appears to be a manifestation of a larger, relatively longstanding issue that is not specific to C23.

    This issue is mentioned in the GCC bug tracker in comments on a related issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112556.