Search code examples
ccastingimplicit-conversionstdbool

Is failure to implicitly convert a pointer to _Bool a compiler deficiency?


Answers to this question state that scalars can be converted to _Bool and that the resulting integer value of the _Bool will be 0 or 1.

The accepted answer to this question points out that pointers are scalars.

Is a failure to implicitly convert a pointer to a _Bool, therefore, a compiler bug?

E.g.:

$ cat ./main.c 
// main.c

#include <stdbool.h>

int main( int argc, char* argv )
{
  int  i;
  int* p   = &i;
  bool foo = (bool)p;
  bool bar = p;

  return 0;
}

Failing compiler (one of one):

$ /path/to/mips_fp_le-gcc --version
2.95.3
$ /path/to/mips_fp_le-gcc ./main.c 
./main.c: In function `main':
./main.c:10: incompatible types in initialization

Passing compiler (one of many):

$ gcc --version
gcc (GCC) 8.3.1 20190223 (Red Hat 8.3.1-2)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcc ./main.c 
$ 

Note that only the implicit conversion, and not the cast (explicit conversion), is flagged as an error with the problem compiler.
Also, note that according to a comment to this question, the noted problem compiler is old - from 2001 - this may be relevant to whether this is a genuine compiler bug. (Reasons beyond my control prevent a version upgrade of the noted problem cross-compiler)


Solution

  • Yes, this is a compiler bug. While C has no implicit conversions in either direction between integer types and pointer types, nor implicit conversions between pointer types except in special cases like to/from pointer-to-void or from pointer-to-unqualified to pointer-to-qualified, it does define an implicit conversion to _Bool. (Traditionally many compilers supported such implicit conversions in other places, but doing so was harmful and was not part of the C language.)

    The language about implicit conversion is under 6.5.16.1 Simple assignment:

    One of the following shall hold:

    • the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;
    • the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;
    • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
    • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
    • the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
    • the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.

    In other places in the standard where implicit conversion appears, it's specified "as if by assignment", referring to the above. For example, in 6.5.2.2 Function calls:

    If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, ...

    Note that your question is actually about initialization, which is not assignment in C but something different. However, 6.7.9 Initialization ¶11 covers it:

    The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.