Types in D2 that have a non-scalar representation, this involves:
- Dynamic arrays { size_t length, void *ptr }
- Delegates { void *object, void *funcptr }
- Associative arrays { void *ptr }
Are silently allowed to pass through the front-end in checkToBoolean checks as valid boolean values.
This means that type-strict backends (GDC, LDC) must do it's own special lowering to ensure that the correct value is extracted and proper scalar -> bool conversion is done.
This also means that dmd, gdc, and ldc may be each doing something different when it comes to the following operations.
---
if (arr) { ... } // Could be (arr.ptr != null) or (arr.ptr || arr.length)
if (dg) { ... } // Could be (dg.funcptr != null) or (dg.object || dg.funcptr)
if (aa) { ... } // arr.ptr != null
---
So I propose that the front-end should instead do this lowering so the behaviour is 'precisely defined' and not up for interpretation of the backend implementer.
Comment #1 by bugzilla — 2015-04-30T22:57:17Z
I don't think this is an enhancement - it's a bug fix. All the compilers must do the same thing.
Comment #2 by yebblies — 2015-05-01T01:15:46Z
The way to make this precisely defined is to put it in the spec and test suite, not to move the lowering into the frontend. Lowering early is not without downsides.
Comment #3 by ibuclaw — 2015-05-04T10:29:52Z
(In reply to yebblies from comment #2)
> The way to make this precisely defined is to put it in the spec and test
> suite, not to move the lowering into the frontend. Lowering early is not
> without downsides.
In some cases, yes. But in this instance, I don't think so.
After we've verified condition->toBoolean() the only other time semantic analysis is done on the condition is for optimizations. And I seriously doubt that we are likely going to get any meaningful constant literal optimized out from any of these types.
Comment #4 by yebblies — 2015-05-04T11:37:31Z
(In reply to Iain Buclaw from comment #3)
> In some cases, yes. But in this instance, I don't think so.
>
> After we've verified condition->toBoolean() the only other time semantic
> analysis is done on the condition is for optimizations. And I seriously
> doubt that we are likely going to get any meaningful constant literal
> optimized out from any of these types.
One example is error messages - I would much rather see
if (dg)
than
if ((auto tmp = dg, tmp.funcptr != null && tmp.ptr != null))
Lowering to
if (cast(bool)dg)
would be acceptable, but the lowering would still be in the backend. Maybe this is done late enough that it wouldn't affect error messages anyway?
This in particular what really irks me.
---
int test()
{
int[int] aa = [1:2];
int[] array = [1,2];
aa.remove(1);
array.length = 0;
if (__ctfe)
assert(!aa);
else
assert(aa);
if (__ctfe)
assert(!array);
else
assert(array);
return 1;
}
---
We have a split brain between what CTFE evaluates as true vs. runtime!
Comment #7 by robert.schadek — 2024-12-13T18:42:40Z