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?
Permalink
Reply