return scope ref outlives the scope of the argument

Jonathan M Davis newsgroup.d at jmdavisprog.com
Tue Jun 25 16:02:27 UTC 2019


On Tuesday, June 25, 2019 6:32:35 AM MDT Eugene Wissner via Digitalmars-d-
learn wrote:
> On Tuesday, 25 June 2019 at 12:04:27 UTC, Jonathan M Davis wrote:
> > On Tuesday, June 25, 2019 1:32:58 AM MDT Eugene Wissner via
> >
> > Digitalmars-d- learn wrote:
> >> struct Container
> >> {
> >> }
> >>
> >> static struct Inserter
> >> {
> >>
> >>      private Container* container;
> >>
> >>      private this(return scope ref Container container)
> >>
> >> @trusted
> >>
> >>      {
> >>
> >>          this.container = &container;
> >>
> >>      }
> >>
> >> }
> >>
> >> auto func()()
> >> {
> >>
> >>      Container container;
> >>      return Inserter(container);
> >>
> >> }
> >>
> >> void main()
> >> {
> >>
> >>      static assert(!is(typeof(func!())));
> >>
> >> }
> >>
> >> The code above compiles with dmd 2.085, but not 2.086 (with
> >> -preview=dip1000). What am I doing wrong?
> >
> > Okay. I clearly looked over what you posted too quickly and
> > assumed that the subject was the error that you were actually
> > getting. The @trusted there is what's making the static
> > asertion fail.
> >
> > Inserter is able to compile with -dip1000 (or
> > -preview=dip1000), because you marked it as @trusted, which
> > throws away the scope checks. If you mark it @safe, it won't
> > compile. Without -dip1000, I wouldn't have expected anything to
> > be caught, but trying it on run.dlang.io, it looks like the
> > return probably makes it fail, which I find surprising, since I
> > didn't think that return had any effect without -dip25, but I
> > haven't done much with return on parameters.
> >
> > You'd have an easier time figuring out what's going on if you'd
> > just not make func a template rather than use the static
> > assertion, because then you'd see the compiler errors.
> >
> > In any case, by using @trusted, you're getting around the scope
> > compiler checks, which is why Inserter is able to compile with
> > -dip1000. Without -dip1000, I'm not experience enough with
> > return parameters to know what the compiler will or won't
> > catch, but the code is an @safety probelm regardless. It does
> > look like the behavior changed with 2.086 even without -dip1000
> > being used, which probably has something to do with how the
> > compiler was changed for DIP 1000, though it probably wasn't on
> > purpose, since in theory, the behavior shouldn't have changed
> > without -dip1000, but I don't know.
> >
> > - Jonathan M Davis
>
> Yes, reduced code could be a bit better.
>
> @trusted doesn't throw scope checks away (and it wouldn't make
> any sense since I don't see another way to make the code above
> safe). Try:
>
> struct Container
> {
> }
>
> private Container* stuff(return scope ref Container container)
> @trusted
> {
>      return &container;
> }
>
> auto func()
> {
>      Container container;
>      return stuff(container);
> }
>
> It fails with -dip1000 and works without (as expected).
>
> "return scope ref" parameter in the constructor means, that the
> constructed object has the same scope as the scope of the
> argument.
>
> I just want to know whether the behaviour of 2.085 or 2.086 is
> correct and if it is an "improvement" in 2.086, what I'm doing
> wrong.

scope is only checked in @safe code. If you use @trusted, it's not checked.
At that point, it's up to you to make sure that no references escape, and
taking the address of the scope variable and storing it is definitely
escaping a reference to it. As I understand it, what you're trying to do is
not something that works with scope. scope objects can be passed around, but
they can't be stored like this. Unfortunately, the primary source of
documentation for DIP 1000 is the DIP itself, and it was "superceded,"
meaning that the actual implementation does not match what's in the DIP, and
I don't know how it differs. Unfortunately, for the most part, with DIP
1000, you just have to see what works, but I am very sure that using
@trusted or @system means that the scope checks are off, and if you have to
use @trusted to make something work with scope, then what you're trying to
do doesn't work with scope.

I can say however that if you can get the compiler to let you return a
reference to a local variable like you're doing here with only @safe code
(so, no @trusted), then it's a definitely a compiler bug.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list