Jump to page: 1 2
Thread overview
Please, can the langauge stop inferring scope and return for @trusted/@system?
May 19, 2022
Dukc
May 19, 2022
Dukc
May 19, 2022
Tejas
May 19, 2022
Dukc
May 19, 2022
bauss
May 19, 2022
Dukc
May 19, 2022
Dukc
May 19, 2022
Dennis
May 19, 2022
Dukc
May 19, 2022
Dennis
May 19, 2022
Dukc
May 19, 2022
Dennis
May 19, 2022
Dukc
May 19, 2022
Dukc
May 19, 2022
Dennis
May 19, 2022
Dukc
May 19, 2022
Dennis
May 23, 2022
Dukc
May 19, 2022
Dennis
May 19, 2022
Dukc
May 19, 2022

First thing first, I'm talking about code with -preview=dip1000. Make sure that is on if you test these.

There are times when you want to treat data in a scoped struct as non-scoped. Example:

struct MyType
{ // Struct designed so that this will never point to local data
  private @system int* _content;
  // This might.
  int* otherPtr;
  @trusted this(return ref int i)
  { _content = new int(i);
    otherPtr = &i;
  }
  // Note, not marked RETURN scope. Should return an unscoped pointer.
  @trusted scope content(){return _content;}
}

@safe void main()
{ int* outer;
  if(true)
  { int inner;
    // Inferred as scope, which is intended
    auto myVar = MyType(inner);
    // Should be allowed
    outer = myVar.content;
  }
}

This pattern is perfectly @safe and makes sense. One problem though - it does not compile. Auto-inference being on, the compiler goes on to infer that MyType.content is return scope.

In this case, it would be easy to avoid this by simply disabling auto-inference by giving the function an explicit type: @trusted pure nothrow @nogc scope int* content(). This only works in non-templated functions and types though. We sometimes need to achieve the same inside a template too. We can do that:

@trusted scope content()
{ auto tmp = _content;
  return tmp;
}

This works. The compiler does not really track lifetimes of the variables inside @trusted or @system functions. But it still tries to be smart if directly returning a pointer from the struct.

Frankly, this violates the principle of least astonishment pretty badly. Can't we just have a simple rule: if the function is explicitly marked @trusted or @system, NO scope or return attributes are inferred whatsoever?

May 19, 2022

On Thursday, 19 May 2022 at 07:13:05 UTC, Dukc wrote:

>

[snip]

Bugzilla entry created: https://issues.dlang.org/show_bug.cgi?id=23124

May 19, 2022

On Thursday, 19 May 2022 at 07:13:05 UTC, Dukc wrote:

>

First thing first, I'm talking about code with -preview=dip1000. Make sure that is on if you test these.

[...]

The code compiled for me with -preview=dip1000 in run.dlang.io though...

And when I added a destructor that freed _content, and I added a writeln(*outer); below the if block, the program also segfaulted

May 19, 2022

On Thursday, 19 May 2022 at 07:31:56 UTC, Tejas wrote:

>

On Thursday, 19 May 2022 at 07:13:05 UTC, Dukc wrote:

>

First thing first, I'm talking about code with -preview=dip1000. Make sure that is on if you test these.

[...]

The code compiled for me with -preview=dip1000 in run.dlang.io though...

And when I added a destructor that freed _content, and I added a writeln(*outer); below the if block, the program also segfaulted

Hmm, it seems to run with the default compiler, but fail to compile with nightly.

May 19, 2022

On Thursday, 19 May 2022 at 07:39:03 UTC, Dukc wrote:

>

On Thursday, 19 May 2022 at 07:31:56 UTC, Tejas wrote:

>

On Thursday, 19 May 2022 at 07:13:05 UTC, Dukc wrote:

>

First thing first, I'm talking about code with -preview=dip1000. Make sure that is on if you test these.

[...]

The code compiled for me with -preview=dip1000 in run.dlang.io though...

And when I added a destructor that freed _content, and I added a writeln(*outer); below the if block, the program also segfaulted

Hmm, it seems to run with the default compiler, but fail to compile with nightly.

Probably shouldn't rely on nightly anyway, considering it's not fully tested, it could contain buggy/partial pull requests.

May 19, 2022

On Thursday, 19 May 2022 at 07:46:15 UTC, bauss wrote:

>

Probably shouldn't rely on nightly anyway, considering it's not fully tested, it could contain buggy/partial pull requests.

I'm not sure quite what version the Symmetry-patched DMD I tested with was based on. It said "2.100.0" but if it is the stable 2.100.0 or something with nightly additions on top of it, I frankly don't know.

Anyway I hope this addition won't make it to the next stable.

May 19, 2022

On Thursday, 19 May 2022 at 08:30:58 UTC, Dukc wrote:

>

I'm not sure quite what version the Symmetry-patched DMD I tested with was based on. It said "2.100.0" but if it is the stable 2.100.0 or something with nightly additions on top of it, I frankly don't know.

Anyway I hope this addition won't make it to the next stable.

run.dlang.io still runs 2.099.something.

May 19, 2022

On Thursday, 19 May 2022 at 08:30:58 UTC, Dukc wrote:

>

Anyway I hope this addition won't make it to the next stable.

The reason run.dlang.io / dmd 2.099 allows it is that it failed to propagate lifetimes of return ref parameters through constructors, so it doesn't consider myVar scope. It would give an error about assigning i to the otherPtr member, but you marked the constructor @trusted. See:

https://issues.dlang.org/show_bug.cgi?id=22801

May 19, 2022

On Thursday, 19 May 2022 at 08:52:46 UTC, Dennis wrote:

>

The reason run.dlang.io / dmd 2.099 allows it is that it failed to propagate lifetimes of return ref parameters through constructors, so it doesn't consider myVar scope. It would give an error about assigning i to the otherPtr member, but you marked the constructor @trusted. See:

https://issues.dlang.org/show_bug.cgi?id=22801

Thanks. So it was a bug hiding another bug (or just controversial design - you decide).

May 19, 2022

On Thursday, 19 May 2022 at 07:13:05 UTC, Dukc wrote:

>

Frankly, this violates the principle of least astonishment pretty badly. Can't we just have a simple rule: if the function is explicitly marked @trusted or @system, NO scope or return attributes are inferred whatsoever?

There used to be different rules for lifetime errors in all of these:

  • explicit @system functions
  • @system by default functions (yes, they were special)
  • inferred functions
  • @safe functions
  • @trusted functions

It was really complex and confusing, and I've worked on simplifying it such that all lifetime errors are safety violations like any other. The only exception is directly returning a dangling pointer to a stack variable, which is just an error even in @system code (issue 19873). I don't want to go back to more special cases, especially with the dip1000 by default transition which is complex enough as is.

I also don't agree with the "principle of least astonishment" violation. Consider this slice example:

struct Slice(T)
{
    size_t length;
    private @system T* _ptr;

    // `@safe` read-only access to _ptr
    T* ptr() @trusted { return length == 0 ? null : _ptr; }
}

I expect the compiler to infer return scope for ptr() here.

« First   ‹ Prev
1 2