1 day ago
On Thursday, 11 September 2025 at 03:47:02 UTC, Richard (Rikki) Andrew Cattermole wrote:
> It did go through the DIP process.

Blast, you're right. I've even seen the DIP Development post for it before, too! I didn't read into it at the time. I could've probably identified this problem and raised it ahead of time.
1 day ago

On Wednesday, 10 September 2025 at 12:29:24 UTC, IchorDev wrote:

>

If anyone has any ideas, please let me know.

The trick that's used in druntime is putting the part that still needs to be checked for attributes inside an if (false) block, for example:

https://github.com/dlang/dmd/blob/c81714b9bc7626e1d235fb2d6279dc73d47c9174/druntime/src/core/lifetime.d#L1981

private T moveImpl(T)(return scope ref T source)
{
    // Properly infer safety from moveEmplaceImpl as the implementation below
    // might void-initialize pointers in result and hence needs to be @trusted
    if (false) moveEmplaceImpl(source, source);

    return trustedMoveImpl(source);
}

Other example:

https://github.com/dlang/dmd/blob/c81714b9bc7626e1d235fb2d6279dc73d47c9174/druntime/src/core/internal/newaa.d#L692

1 day ago

On Thursday, 11 September 2025 at 11:47:40 UTC, Dennis wrote:

>

On Wednesday, 10 September 2025 at 12:29:24 UTC, IchorDev wrote:

>

If anyone has any ideas, please let me know.

The trick that's used in druntime is putting the part that still needs to be checked for attributes inside an if (false) block, for example:

https://github.com/dlang/dmd/blob/c81714b9bc7626e1d235fb2d6279dc73d47c9174/druntime/src/core/lifetime.d#L1981

You can also use static if and a no-op @system function:

@system pure nothrow @nogc
pragma(inline, true)
void inferSystem() {}

T* example(T)()
{
    import std.traits: isSafe;

    static if (!isSafe!(() { new T(); })
        inferSystem();

    void[] memory = new void[](T.sizeof);
    return (() @trusted => new (memory) T())();
}
19 hours ago

On Thursday, 11 September 2025 at 11:47:40 UTC, Dennis wrote:

>

The trick that's used in druntime is putting the part that still needs to be checked for attributes inside an if (false) block, for example:

private T moveImpl(T)(return scope ref T source)
{
    // Properly infer safety from moveEmplaceImpl as the implementation below
    // might void-initialize pointers in result and hence needs to be @trusted
    if (false) moveEmplaceImpl(source, source);

    return trustedMoveImpl(source);
}

Well, that would work. Thank you for pointing it out. It's probably better to do it like this to avoid the potential for an unconditional cache miss (depending on how smart the compiler feels today):

private T moveImpl(T)(return scope ref T source){
	if(true) return trustedMoveImpl(source);
	moveEmplaceImpl(source, source);
	assert(0);
}

It would still be nice to have a proper, intuitive way of doing this though. Hacks are great and all, but they are still hacks. One time I got my code to call into Swift code by writing inline assembly to match Swift's calling convention; but that was a hack, and I'm still excited that LDC has recently gained some degree of native Swift interoperability.

19 hours ago

On Thursday, 11 September 2025 at 17:16:35 UTC, Paul Backus wrote:

>
void inferSystem() @system pure nothrow @nogc {}

T* example(T)() {
    static if (!isSafe!(() { new T(); })
        inferSystem();
    return (() @trusted => new (new void[](T.sizeof)) T())();
}

Unfortunately that would give you an incredibly unhelpful error message.

18 hours ago

On Thursday, 11 September 2025 at 08:06:17 UTC, IchorDev wrote:

>

But that's the thing: all I want is to construct objects into freshly-allocated, uninitialised memory; so my desired use-case has a safe interface and can therefore be marked @trusted. However the constructor is a wildcard, so I want to leave that part to attribute inference.
Do you think it'd be worth submitting an enhancement issue to add something simple like this?

new @trusted (buffer) S(500); //we trust that the buffer is safe to use, but not S's constructor.

No, for 2 reasons:

  1. @trusted is a function attribute that says the function has a safe interface. Placement new does not have a safe interface, above it depends on how buffer is used outside of it and what S is. (Yes people often resort to using a trusted function literal without a safe interface, but it's still wrong, and the language shouldn't endorse that).

  2. There are various other expressions in the language where you'd need something similar. Phobos uses introspection instead to detect whether to trust an expression or not.

>

The weird placement new syntax means that this looks a bit goofy, but it's better than the feature being essentially dead-on-arrival for the one thing I'd ever want it for.

It's no different than some other unsafe expressions that Phobos sometimes needs to trust.

1 2
Next ›   Last »