Thread overview
Should I worry about this hashOf warning ?
1 day ago
axricard
1 day ago
axricard
1 day ago

When trying to use Nullable with a struct containing an overlapping pointer:

import std;

struct S
{
    union
    {
    	long foo;
       	int[] bar;
    }
}

void main()
{
    Nullable!S s;
}

I get this warning:

/dlang/dmd/linux/bin64/../../src/phobos/std/typecons.d(3820): Deprecation: `@safe` function `toHash` calling `hashOf`
           return _isNull ? 0 : .hashOf(_value.payload);
                                       ^
/dlang/dmd/linux/bin64/../../src/druntime/import/core/internal/hash.d-mixin-551(664):        and accessing overlapped field `S.bar` with pointers makes it fail to infer `@safe`

The spec is states that a @safe functions "cannot access union fields that have pointers or references overlapping with other types", and this toHash in std.typecons is @safe.

So I wonder, why is it just a warning and not a compile error (the code compiles and runs normally) ? Is there any risk at ignoring this warning ?

And if there is a risk, is there a workaround or do I have to drop the Nullable struct ?

1 day ago
On Wednesday, June 25, 2025 9:38:55 AM Mountain Daylight Time axricard via Digitalmars-d-learn wrote:
> When trying to use Nullable with a struct containing an overlapping pointer:
>
> ```D
> import std;
>
> struct S
> {
>      union
>      {
>       long foo;
>           int[] bar;
>      }
> }
>
> void main()
> {
>      Nullable!S s;
> }
> ```
>
> I get this warning:
>
>   ```
> /dlang/dmd/linux/bin64/../../src/phobos/std/typecons.d(3820):
> Deprecation: `@safe` function `toHash` calling `hashOf`
>              return _isNull ? 0 : .hashOf(_value.payload);
>                                          ^
> /dlang/dmd/linux/bin64/../../src/druntime/import/core/internal/hash.d-mixin-551(664):        and accessing overlapped field `S.bar` with pointers makes it fail to infer `@safe`
> ```
>
> The [spec](https://dlang.org/spec/function.html#safe-functions) is states that a @safe functions "cannot access union fields that have pointers or references overlapping with other types", and this toHash in std.typecons is @safe.
>
> So I wonder, why is it just a warning and not a compile error (the code compiles and runs normally) ? Is there any risk at ignoring this warning ?
>
> And if there is a risk, is there a workaround or do I have to drop the Nullable struct ?

Strictly speaking, it's not a warning. It's a deprecation message. I'd have to dig through the changelog to see where this particular decprecation is mentioned to know exactly what's going on with it, but almost certainly what happened is that the code was treated as @safe previously when it shouldn't have been. Someone then figured out that it wasn't actually memory safe, so it needs to be treated as @system, but making that change to the compiler would break code. So, instead of simply fixing the issue and making it @system, it was first made a deprecation message in order to get folks to fix their code. And then later, the compiler will be change do treat it as @system, breaking any code marked with @safe which hadn't been fixed yet.

In this case, the bug is in Nullable's toString in that it's calling hashOf and marked as @safe when using hashOf in this situation isn't @safe. And since Nullable is templated, this issue is only visible when Nullable is instantiated with a type like the one you have here, so Nullable's toHash needs to be fixed to infer @safe instead of being explicitly marked with it. I've opened a bug report for the issue:

But looking into this deeper, it looks like Nullable's toHash is just plain broken with any type whose toHash isn't @safe const nothrow (or some variation on that which can be called from code which is @safe const nothrow). Nullable's toHash is actually giving the wrong hash with code in such a situation, because it's bypassing the contained type's toHash. I'm pretty sure that this was done to try to make Nullable's toHash work with types whose hash isn't const, @safe, and nothrow, but it introduced incorrect behavior when what really needed to happen was make toHash infer its attributes and then make the code that required those attributes but couldn't infer them break, since that code is broken anyway. I've reported the issue:

https://github.com/dlang/phobos/issues/10809

As for your situation, if Nullable's toHash were correct, then your Nullable!S would be @system, so then you'd need to just either live with the deprecation message or fix your type to have a toHash which wasn't @system.

And what you really want here is to provide a toHash and opEquals which use whichever field is the valid one rather than using the entire union. That way, your code can be @safe. I don't recall at the moment whether your code as-is is hashing the entire union or just the first member, but it's highly unlikely that it's working in a way that you actually want regardless of @safe.

And in case you didn't know, with types in general, if you provide toHash, you need to provide an opEquals which is consistent with it (otherwise values which are considered equal might end up with different hashes, which is a bug), and if you provide an opEquals, you either can't use toHash with that type anywhere, or you need to provide a toHash which is consistent with your opEquals.

However, since Nullable's toHash is not currently correct, to get correct behavior, you not only need to provide an opEquals and toHash, but you need the toHash to be marked as @safe (or @trusted), const, and nothrow; otherwise, Nullable's toHash will use its broken workaround.

What will happen if you continue to use your code as-is without providing a toHash is that it will give the same hash as when you use hashOf directly on S and give you that deprecation message, but once the deprecation message becomes an error, Nullable's toHash will start using the typeid workaround that it currently has, which will cause the value of toHash to then be incorrect. Of course, if you're not actually using toHash anywhere, that's not necessarily a big deal, but your opEquals is still probably broken, and you'll have to live with the deprecation message if you don't provide a toHash which will work with Nullable's toHash.

So, if you want correct behavior (and no deprecation message), then you'll need to define an opEquals and toHash which do the correct thing for your type, _and_ you'll need its toHash to be @safe, const, and nothrow to work around the bug in Nullable's toHash. Once Nullable's toHash is fixed, the attribute issue will go away though, and you should then be able to not have those attributes on your toHash if you don't want to.

- Jonathan M Davis




1 day ago
On Thursday, 26 June 2025 at 03:55:03 UTC, Jonathan M Davis wrote:
> [...]

Thanks for these wonderful explanations ! A const @safe nothrow toHash indeed solved this.