Bug 18265 – `scope` storage class w/ -dip1000 and `scope` type modifier behavior inconsistent

Status
RESOLVED
Resolution
INVALID
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2018-01-19T14:02:15Z
Last change time
2018-01-20T12:17:40Z
Keywords
diagnostic
Assigned to
No Owner
Creator
Mike Franklin

Comments

Comment #0 by slavo5150 — 2018-01-19T14:02:15Z
The following code uses `scope` as a type modifier and is compiled WITHOUT -dip1000 --- import std.stdio; scope class A { this() { writeln("A.this()"); } ~this() { writeln("A.~this()"); } void method() { writeln("A.method()"); } } A fun() // onlineapp.d(10): Error: functions cannot return scope onlineapp.A { writeln("entering fun()"); auto a = new A; writeln("leaving fun()"); return a; // a.~this() called here } void main(string[] args) { auto a = fun(); // a.~this() has already been called, so the // call to a.method() is undefined behavior a.method(); } --- Run online at https://run.dlang.io/is/s9oozy The compiler emits the following error: onlineapp.d(10): Error: functions cannot return scope onlineapp.A Now consider the following using `scope` as a storage class. --- import std.stdio; class A { this() { writeln("A.this()"); } ~this() { writeln("A.~this()"); } void method() { writeln("A.method()"); } } A fun() { writeln("entering fun()"); scope a = new A; writeln("leaving fun()"); return a; //onlineapp.d(10): Error: functions cannot return scope onlineapp.A // a.~this() called here } void main(string[] args) { auto a = fun(); // a.~this() has already been called, so the // call to a.method() is undefined behavior a.method(); } --- Run online at https://run.dlang.io/is/AUwGEb Compiling WITH -dip1000 results in the following error: onlineapp.d(10): Error: functions cannot return scope onlineapp.A These are essentially two ways of implementing the same program, yet the compiler emits different errors at different locations. The error messages should, arguable, be the same and be at the same location.
Comment #1 by slavo5150 — 2018-01-19T14:06:48Z
GRRR!!! Copied the wrong error. Please disregard the first comment. Instead see the following. The following code uses `scope` as a type modifier and is compiled WITHOUT -dip1000 --- import std.stdio; scope class A { this() { writeln("A.this()"); } ~this() { writeln("A.~this()"); } void method() { writeln("A.method()"); } } A fun() // onlineapp.d(10): Error: functions cannot return scope onlineapp.A { writeln("entering fun()"); auto a = new A; writeln("leaving fun()"); return a; // a.~this() called here } void main(string[] args) { auto a = fun(); // a.~this() has already been called, so the // call to a.method() is undefined behavior a.method(); } --- Run online at https://run.dlang.io/is/s9oozy The compiler emits the following error: onlineapp.d(10): Error: functions cannot return scope onlineapp.A Now consider the following using `scope` as a storage class. --- import std.stdio; class A { this() { writeln("A.this()"); } ~this() { writeln("A.~this()"); } void method() { writeln("A.method()"); } } A fun() { writeln("entering fun()"); scope a = new A; writeln("leaving fun()"); return a; // onlineapp.d(16): Error: scope variable a may not be returned // a.~this() called here } void main(string[] args) { auto a = fun(); // a.~this() has already been called, so the // call to a.method() is undefined behavior a.method(); } --- Run online at https://run.dlang.io/is/AUwGEb Compiling WITH -dip1000 results in the following error: onlineapp.d(16): Error: scope variable a may not be returned These are essentially two ways of implementing the same program, yet the compiler emits different errors at different locations. The error messages should, at least be at the same location.
Comment #2 by chilli — 2018-01-19T23:31:25Z
For all the following, add stdout.flush(); to A's destructor. IIRC, the scope _attribute_ in Your 1. program version declares a class, that shall be allocated on the stack. It's deprecated, and by it's nature, an already destroyed object of that type can't be returned from a function, detected by the compiler - knowing that A is a scope class - in line 10 already. https://dlang.org/spec/class.html#auto Your 2. program version is more interesting: First, change scope to auto, compile without -dip1000, and the program prints as expected: entering fun() A.this() leaving fun() A.method() A.~this() Back to Your 'original' 2. program version (scope a), still without -dip1000, You have an undefined behavior program as per Your comments, undetected by the compiler, it prints and then segfaults: entering fun() A.this() leaving fun() A.~this() Thus the difference auto<->scope here is that scope forces A's destructor when a's lifetime ends, as per Your comment line. Now with -dip1000 enabled, additional checks are applied and compiling already fails, but the error occurs in line 16. An A may be returned by fun(), but not one assigned to a scope variable. Thus IMO everything is fine here as per language rules and DIP1000, except that acc. to DIP1000, the additional checks should kick in only for @safe attributed functions. I suggest to change the issue text accordingly.
Comment #3 by slavo5150 — 2018-01-20T12:17:40Z
Closing as invalid for now until I sort this out further.