Bug 23124 – [dip1000] scope inference leads to implementatio-defined semantics for @trusted and @system.

Status
REOPENED
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2022-05-19T07:18:32Z
Last change time
2024-12-13T19:22:56Z
Assigned to
No Owner
Creator
Ate Eskola
Moved to GitHub: dmd#20107 →

Comments

Comment #0 by Ajieskola — 2022-05-19T07:18:32Z
This should compile, but does not. ---------- struct MyType { private @system int* _content; // This type is designed so that _content will never point to local data. @trusted pure this(return ref int i){_content = new int(i);} // Note, not marked RETURN scope. Should return an unscoped pointer. @trusted pure 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; } } ---------- More through explaination: https://forum.dlang.org/thread/[email protected]
Comment #1 by bugzilla — 2022-08-26T17:44:03Z
The error is: test.d(17): Error: scope variable `myVar` assigned to `outer` with longer lifetime which is a correct error message. `outer` lives longer than the scope of `inner`, so it is an error to set `outer` to pointing at `inner`. If you need it to compile, remove `@safe` from main(). It's a feature of D to do scope inference. Whether the use of a scope pointer is checked or not is dependent on whether the function using the scope pointer is @safe or not. This is working as designed.
Comment #2 by Ajieskola — 2022-09-17T14:01:33Z
I did change my mind in the topic a bit. I said previously, that no `scope` inference should be done for a `@trusted` or `@system` function. Now I think that it's okay, good even, to infer, but if the inference changes the attributes it should be an error. Why? Consider a hypothetical future spec-compliant D compiler. The language spec does not say where the inference must stop, so our future compiler infers `scope` only if the argument is directly returned. If it encounters any other expression than a plain symbol name, it stops inference there. Now we have a function ------ import std.random : dice; auto either(int* a, int* b) @trusted { return dice(1,1) ? a : b; } ------ What happens? DMD infers arguments a and b as `scope`, BUT our future compiler does not. What is a perfectly safe function with DMDFE just became a terrible footgun in another spec-abiding compiler! So, if we don't want to disable inference in these cases, there are two options: 1: If inference detects need for adding `scope` or `return` to a `@system` or `@trusted` function, it must error. 2: The spec must unambiguously specify where `scope` and `return scope` should be inferred and where it should not. I think the first option is simpler, but I'm happy with either one.
Comment #3 by Ajieskola — 2022-09-17T14:20:51Z
Example in my last comment was wrong. Posting a corrected one: ---------------- struct MyType { private int* wontEverPointToLocal; int* mayPointToLocalIfScope; // Safe in the future compiler because // not callable with scope MyType. // Dangerous in DMD because it infers // scope for this reference. @trusted fun(bool cond){return cond? wontEverPointToLocal: mayPointToLocalIfScope;} } ----------------
Comment #4 by Ajieskola — 2022-09-17T15:14:50Z
(In reply to Ate Eskola from comment #3) > Example in my last comment was wrong. Posting a corrected one: > > ---------------- > struct MyType > { private int* wontEverPointToLocal; > int* mayPointToLocalIfScope; > // Safe in the future compiler because > // not callable with scope MyType. > // Dangerous in DMD because it infers > // scope for this reference. > @trusted fun(bool cond){return cond? wontEverPointToLocal: > mayPointToLocalIfScope;} > } > ---------------- Nope, still not right. My brains are porridge. Third try: --------------------- struct MyType { int* ptr; // Safe in DMD because return scope is inferred. // Dangerous in our future compiler because // may return an unscoped pointer to local data, // when MyType is scope. @trusted scope getPtr(bool cond){return cond? ptr: null;} } ---------------------
Comment #5 by robert.schadek — 2024-12-13T19:22:56Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/20107 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB