From 4f843111ef45abcfded6cd5f9712b871ca53d0f0 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Thu, 23 Aug 2018 13:48:20 +0100 Subject: [PATCH 1/3] [spec] Add scope parameter caveats Mention unique allocation elision. --- spec/function.dd | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/spec/function.dd b/spec/function.dd index 73b3d3d947..ad961564e6 100644 --- a/spec/function.dd +++ b/spec/function.dd @@ -1242,9 +1242,18 @@ int foo(in int x, out int y, ref int z, int q); $(TROW $(D out), parameter is passed by reference and initialized upon function entry with the default value for its type) - $(TROW $(D scope), references in the parameter - cannot be escaped (e.g. assigned to a global variable). - Ignored for parameters with no references) + $(TROW $(D scope), $(ARGS + The parameter does not escape the function call + (e.g. by being assigned to a global variable). + Ignored for any parameter that is not a reference type. + Escape analysis is only done for `@safe` functions, for other functions `scope` semantics must + be manually enforced. + As the parameter must not escape, the compiler can avoid heap-allocation of a unique argument + to a `scope` parameter. Due to this, passing e.g. a `new T` argument may not violate `@nogc`. + A typical example of this is passing a delegate literal to a `scope` parameter. + $(B Note): `scope` escape analysis is currently only done by `dmd` + when the `-dip1000` switch is passed. + )) $(TROW $(D return), $(ARGS Parameter may be returned or copied to the first parameter, but otherwise does not escape from the function. Such copies are required not to outlive the argument(s) they were derived from. @@ -1422,10 +1431,6 @@ pure void f() $(H3 $(LNAME2 return-ref-parameters, Return Ref Parameters)) - $(P Note: The `return` attribute is currently only enforced by `dmd` - when the `-dip25` switch is passed. - ) - $(P Return ref parameters are used with $(RELATIVE_LINK2 ref-functions, ref functions) to ensure that the returned reference will not outlive the matching argument's lifetime. From 90b2561bb5ab287bd5c3b8264a80d3fd12a0bc45 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 17 Jun 2020 11:55:32 +0100 Subject: [PATCH 2/3] Move note; scope avoiding heap-allocation is only potential --- spec/function.dd | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/spec/function.dd b/spec/function.dd index ad961564e6..fe7adcc03b 100644 --- a/spec/function.dd +++ b/spec/function.dd @@ -1243,16 +1243,17 @@ int foo(in int x, out int y, ref int z, int q); for its type) $(TROW $(D scope), $(ARGS - The parameter does not escape the function call + The parameter must not escape the function call (e.g. by being assigned to a global variable). Ignored for any parameter that is not a reference type. - Escape analysis is only done for `@safe` functions, for other functions `scope` semantics must - be manually enforced. - As the parameter must not escape, the compiler can avoid heap-allocation of a unique argument - to a `scope` parameter. Due to this, passing e.g. a `new T` argument may not violate `@nogc`. - A typical example of this is passing a delegate literal to a `scope` parameter. - $(B Note): `scope` escape analysis is currently only done by `dmd` - when the `-dip1000` switch is passed. + `scope` escape analysis is only done for `@safe` functions. For other functions `scope` + semantics must be manually enforced.) + $(P $(B Note): `scope` escape analysis is currently only done by `dmd` + when the `-dip1000` switch is passed.) + $(P As the parameter must not escape, the compiler can potentially avoid heap-allocation of a + unique argument to a `scope` parameter. Due to this, passing an array literal, delegate + literal or a $(GLINK2 expression, NewExpression) to a scope parameter may be used in a + `@nogc` context, depending on the compiler implementation.) )) $(TROW $(D return), $(ARGS Parameter may be returned or copied to the first parameter, but otherwise does not escape from the function. From 16df53d9656c8655ec1f966e9613b4a04a2129ab Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 17 Jun 2020 12:05:59 +0100 Subject: [PATCH 3/3] Move scope parameter row to its own section Also split return scope example. Reparent `return scope` section headings. Remove note about -dip1000 in return scope section as it is now mentioned in the (earlier) scope parameter section. --- spec/function.dd | 56 ++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/spec/function.dd b/spec/function.dd index fe7adcc03b..941351cc30 100644 --- a/spec/function.dd +++ b/spec/function.dd @@ -1246,14 +1246,6 @@ int foo(in int x, out int y, ref int z, int q); The parameter must not escape the function call (e.g. by being assigned to a global variable). Ignored for any parameter that is not a reference type. - `scope` escape analysis is only done for `@safe` functions. For other functions `scope` - semantics must be manually enforced.) - $(P $(B Note): `scope` escape analysis is currently only done by `dmd` - when the `-dip1000` switch is passed.) - $(P As the parameter must not escape, the compiler can potentially avoid heap-allocation of a - unique argument to a `scope` parameter. Due to this, passing an array literal, delegate - literal or a $(GLINK2 expression, NewExpression) to a scope parameter may be used in a - `@nogc` context, depending on the compiler implementation.) )) $(TROW $(D return), $(ARGS Parameter may be returned or copied to the first parameter, but otherwise does not escape from the function. @@ -1545,10 +1537,14 @@ inout(int)* neptune(inout ref int i) } --- -$(H3 $(LNAME2 return-scope-parameters, Return Scope Parameters)) +$(H3 $(LNAME2 scope-parameters, Scope Parameters)) - $(P Parameters marked as `return scope` that contain indirections - can only escape those indirections via the function's return value.) + $(P A `scope` parameter of reference type must not escape the function call + (e.g. by being assigned to a global variable). It has no effect for non-reference types. + `scope` escape analysis is only done for `@safe` functions. For other functions `scope` + semantics must be manually enforced.) + $(P $(B Note): `scope` escape analysis is currently only done by `dmd` + when the `-dip1000` switch is passed.) --- @safe: @@ -1556,24 +1552,45 @@ $(H3 $(LNAME2 return-scope-parameters, Return Scope Parameters)) int* gp; void thorin(scope int*); void gloin(int*); -int* balin(return scope int* p, scope int* q, int* r) +int* balin(scope int* q, int* r) { - gp = p; // error, p escapes to global gp gp = q; // error, q escapes to global gp gp = r; // ok - thorin(p); // ok, p does not escape thorin() - thorin(q); // ok + thorin(q); // ok, q does not escape thorin() thorin(r); // ok - gloin(p); // error, gloin() escapes p gloin(q); // error, gloin() escapes q gloin(r); // ok that gloin() escapes r - return p; // ok return q; // error, cannot return 'scope' q return r; // ok } +--- + + $(P As a `scope` parameter must not escape, the compiler can potentially avoid heap-allocating a + unique argument to a `scope` parameter. Due to this, passing an array literal, delegate + literal or a $(GLINK2 expression, NewExpression) to a scope parameter may be allowed in a + `@nogc` context, depending on the compiler implementation.) + +$(H4 $(LNAME2 return-scope-parameters, Return Scope Parameters)) + + $(P Parameters marked as `return scope` that contain indirections + can only escape those indirections via the function's return value.) + +--- +@safe: + +int* gp; +void thorin(scope int*); +void gloin(int*); +int* balin(return scope int* p) +{ + gp = p; // error, p escapes to global gp + thorin(p); // ok, p does not escape thorin() + gloin(p); // error, gloin() escapes p + return p; // ok +} --- $(P Class references are considered pointers that are subject to `scope`.) @@ -1617,10 +1634,7 @@ class C $(P Template functions, auto functions, nested functions and lambdas can deduce the `return scope` attribute.) - $(P $(B Note:) Checks for `scope` parameters are currently enabled - only for $(D @safe) functions when compiled with the $(D -dip1000) flag.) - -$(H3 $(LNAME2 ref-return-scope-parameters, Ref Return Scope Parameters)) +$(H4 $(LNAME2 ref-return-scope-parameters, Ref Return Scope Parameters)) $(P Parameters marked as `ref return scope` come in two forms:)