-
-
Notifications
You must be signed in to change notification settings - Fork 607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Issue 18295 - scope class
check too conservative under -dip1000
#7771
Conversation
scope class
check too conservative under -dip1000
test/compilable/test18295.d
Outdated
|
||
scope class C { int i; } // Notice the use of `scope` here | ||
|
||
C increment(C c) // Should not emit error here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is a function there is no inferrence, and if the scope
parameter is not return
, it cannot be returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, all scope class
means is enforcing the usage of
scope var = new Clazz
, it has no implications on the scope checks besides that.
In particular you still need to annotate parameters as return scope
. Remember, scope is a storage class, not a type qualifier, so it doesn't simply carry to every usage of that type.
I'm inclined to say that forcing a particular storage on users of a class is a weird use-case and unprecedented for other storage options (GC, RC). Maybe we should deprecate scope class C {}
declarations in the long-run? Not sure why this mechanism was introduced? To catch unwanted GC allocations?
test/compilable/test18295.d
Outdated
|
||
scope class C { int i; } // Notice the use of `scope` here | ||
|
||
C increment(C c) // Should not emit error here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it should error, you need return scope
on the parameter for this to pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added return scope
to the parameter
test/compilable/test18295.d
Outdated
void main() | ||
{ | ||
scope C c = new C(); | ||
c.increment(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should error here, cannot pass scope to non-scope parameter c
.
bug.d(10): Error: scope variable `c` assigned to non-scope parameter `c` calling bug.increment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added return scope
to the parameter, there should be no error.
// https://issues.dlang.org/show_bug.cgi?id=18295 | ||
|
||
// See test/fail_compilation/test18295.d for the non-`-dip1000` version` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without @safe:
there are no scope checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added @safe
attributes
test/fail_compilation/test18295.d
Outdated
void main() | ||
{ | ||
scope C c = new C(); | ||
c.increment(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That simply won't catch the escaping of a scope variable, checks are only enabled with -dip1000
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not the point of this test. The point is to test the current behavior for which there currently is no test. See https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d#L800...801 If you believe that is an error, please file a bug in bugzilla and submit a fix in a separate PR.
FYI: https://dlang.org/deprecate.html#scope%20for%20allocating%20classes%20on%20the%20stack |
The de-deprecation has been approved. See dlang/dlang.org#2027
When scope class A { }
void main()
{
A a = new A(); // Error: variable main.a reference to scope class must be scope
} |
Jenkins failure is unrelated and should be gone soon (-> dlang/ci#132) |
I find it to be rather useful as a way of enforcing that all instances of the class are stack allocated. It's consistent with constraints such as |
Well, final allows you to restrict any compatibility-relevant usage. /+
dub.sdl:
dependency "automem" version="~>0.0.10"
+/
import automem, std.typecons : scoped;
scope class C {}
void main()
{
auto c1 = scoped!C();
auto c2 = RefCounted!C();
} If there was a clear need for local only classes, that restriction might be warranted, I just don't see any. |
test/fail_compilation/test18295.d
Outdated
|
||
scope class C { int i; } // Notice the use of `scope` here | ||
|
||
C increment(C c) // Not compiling under -dip1000, so this should emit an error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment seems to be wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right or wrong, that's the way it currently works. All this test is doing is adding coverage to the existing implementation. The compilable/test18295.d
file is the test for the new functionality in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test has been merged in a separate PR (#7791), so we can get off this tangent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks OKish. Though I don't think anyone wants to define those half-implemented scope class
es and their interaction with DIP1000 while we're working on @safe
manual memory management and the whole topic is still in flux.
|
||
// See test/fail_compilation/test18295.d for the non-`-dip1000` version` | ||
|
||
scope class C { int i; } // Notice the use of `scope` here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scope class
is irrelevant for this test, please remove the misleading comment.
Only the fact that c
is a scoped class reference matters for the return scope check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not irrelevant, and in fact is the whole point of this PR. Prior to this PR, due to the scope class
attribution, an error would be emitted at the function declaration C increment(scope return C c) @safe
, which is too conservative. After this PR, there is no error.
test/compilable/test18295.d
Outdated
|
||
scope class C { int i; } // Notice the use of `scope` here | ||
|
||
C increment(return scope C c) @safe // Should not emit error here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we'd want to add this -dip1000
test as well.
scope class C { int i; }
C increment(return ref C c) @safe // check implicit scope from class type
{
c.i++;
return c;
}
void main() @safe
{
scope C c = new C();
c.increment();
}
Doesn't work though cause scope class
isn't a real class reference.
bug.d(3): Error: variable bug.increment.c globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I suggest merging this PR and filing a bug for that example.
That's a good question for the folks at Sociomantic who have clearly found a use for it in Ocean. @mathias-lang-sociomantic? |
(answering @mathias-lang-sociomantic summons) @JinShil it is a legacy of D1 which doesn't have struct constructors/destructors, which means In the long term there is nothing preventing deprecation of scope classes and switching to structs instead, but that is both non-trivial and somewhat low priority (there are more important problems with D2 migration that are still unresolved). Important to note that we only care about actual |
So be it. Then I leave it to @WalterBright and @andralex to decide the fate of the |
@WalterBright has made his view known at dlang/dlang.org#2027 (comment)
Therefore, instead of fixing this issue (Issue 18295), I'll move ahead deprecating |
See issue for the details. This PR also adds coverage for previously uncovered case.
FYI: This is in direct support of dlang/dlang.org#2027