Opened 3 years ago

Last modified 3 years ago

#91 new defect

Assignment to bool, not a boolean context

Reported by: Thierry Delisle Owned by:
Priority: minor Component: cfa-cc
Version: 1.0 Keywords:


Assignment to bool and condition evaluation behave differently :

#include <stdbool.h>

struct fred {};
bool ?!=?(const fred & this, zero_t) { return true; }

void foo() {
	fred f;
	if(f) {}
	bool test = f;

Change History (5)

comment:1 Changed 3 years ago by a3moss

I think maybe the way to handle this is with another "default" function in builtins.c (much like the ones that implement ++ and -- in terms of +=), something like the following:

forall(dtype T | { int ?!=?(const T&, zero_t); })
void ?{}(_Bool& b, const T& x) { b = (x != 0); }

forall(dtype T | { int ?!=?(const T&, zero_t); })
_Bool ?=?(_Bool& b, const T& x) { return b = (x != 0); }

comment:2 Changed 3 years ago by a3moss

Thierry says we also want a couple more operators:

forall(dtype T | { int ?!=?(const T&, zero_t); })
int !?(const T& x) { return !(x != 0); }

forall(dtype T | { int ?!=?(const T&, zero_t); })
int ?==?(const T& x, zero_t ) { return !(x != 0); }
Last edited 3 years ago by a3moss (previous) (diff)

comment:3 Changed 3 years ago by a3moss

An unintended consequence of this is that by adding this constructor, _Bool becomes a "managed type" (and transitively, any struct including bool becomes managed as well). The only thing this seems to break in the test suite is the initialization of kernelTLS in libcfa/concurrency/kernel.c (easily fixed with an @= initializer), but the implications of bool being "managed" seem wrong.


  1. Status quo; do nothing, reject this enhancement request
  2. Merge the suggested change above, accept _Bool as a managed type
  3. Change the definition of managed type somehow to exclude this case (not sure if that's possible)
  4. If we ever put in user-defined implicit conversions, implement the above something like this:
    forall(dtype T | { int ?!=? ( const T&, zero_t ); } )
    void ?{safe} ( _Bool& b, const T& x ) { b = (x != 0); }

comment:4 Changed 3 years ago by Rob Schluntz

With respect to option 3, I already ignore intrinsic and autogenerated constructors in the definition of managed types. It would be easy to expand the definition to also ignore builtins. The trick is that with the current setup, if a type is not managed I don't even try to implicitly construct it, so you wouldn't get the desired behavior from the new constructors.

It might be possible to do something in between. For example, builtins constructors change a type to managed, but that managed status does not propagate to other types. I don't love the way this complicated the definition though.

comment:5 Changed 3 years ago by a3moss

I don't love that complication either.

I lean toward option 4, with a suggested mitigation in the meantime of bool test = f != 0; (for the original code snippet).

Note: See TracTickets for help on using tickets.