Skip to content

Commit 17bb4e6

Browse files
authored
Merge pull request #3280 from dkorpel/pure-scope-inference
Document `scope` inference from `pure`
2 parents 3d0f4b5 + 7ab1edd commit 17bb4e6

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

spec/function.dd

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,48 @@ S test6(ref return scope int* p)
20152015
}
20162016
---
20172017

2018+
$(H3 $(LNAME2 pure-scope-inference, Inferred `scope` parameters in `pure` functions))
2019+
2020+
When a parameter is not marked or inferred `scope`, it may still be `@safe` to assign it a `scope` pointer in a function call.
2021+
The following conditions need to be met:
2022+
2023+
$(UL
2024+
$(LI The function is $(RELATIVE_LINK2 pure-functions, `pure`), hence the argument cannot be assigned to a global variable)
2025+
$(LI The function is $(RELATIVE_LINK2 nothrow-functions, `nothrow`), hence the argument cannot be assigned to a thrown `Exception` object)
2026+
$(LI None of the other parameters have mutable indirections, hence the argument cannot be assigned to a longer-lived variable)
2027+
)
2028+
2029+
Then, the parameter is still treated as `scope` or `return scope` depending on the return type of the function:
2030+
$(UL
2031+
$(LI If the function returns by `ref` or has a return type that contains pointers, the argument could be returned, so it is treated as `return scope`)
2032+
$(LI Otherwise, the argument cannot escape the function, so it is treated as `scope`)
2033+
)
2034+
2035+
---
2036+
@safe:
2037+
2038+
int dereference(int* x) pure nothrow;
2039+
int* identity(int* x) pure nothrow;
2040+
int* identityThrow(int* x) pure;
2041+
void assignToRef(int* x, ref int* escapeHatch) pure nothrow;
2042+
void assignToPtr(int* x, int** escapeHatch) pure nothrow;
2043+
void cannotAssignTo(int* x, const ref int* noEscapeHatch) pure nothrow;
2044+
2045+
int* globalPtr;
2046+
2047+
int* test(scope int* ptr)
2048+
{
2049+
int result = dereference(ptr); // allowed, treated as `scope`
2050+
int* ptr2 = identity(ptr); // allowed, treated as `return scope`
2051+
int* ptr3 = identityThrow(ptr); // not allowed, can throw an `Exception`
2052+
assignToRef(ptr, globalPtr); // not allowed, mutable second parameter
2053+
assignToPtr(ptr, &globalPtr); // not allowed, mutable second parameter
2054+
cannotAssignTo(ptr, globalPtr); // allowed
2055+
2056+
return ptr2; // not allowed, ptr2 is inferred `scope` now
2057+
}
2058+
---
2059+
20182060
$(H3 $(LNAME2 udas-parameters, User-Defined Attributes for Parameters))
20192061

20202062
See also: $(GLINK2_ALTTEXT attribute, UserDefinedAttribute, User-Defined Attributes)

0 commit comments

Comments
 (0)