From 418405493337240a724b8f9a3e833530359dabae Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 19 Nov 2023 10:24:31 -0500 Subject: [PATCH 1/4] Add support for attributes and extern on local functions Add support for attributes and extern on local functions fix md formatting --- standard/attributes.md | 8 +++++++- standard/statements.md | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/standard/attributes.md b/standard/attributes.md index 758623ca5..66b1f9a72 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -513,7 +513,7 @@ A class that is decorated with the `AttributeUsage` attribute shall derive from #### 23.5.3.1 General -The attribute `Conditional` enables the definition of ***conditional methods*** and ***conditional attribute classes***. +The attribute `Conditional` enables the definition of ***conditional methods***, ***conditional local functions***, and ***conditional attribute classes***. #### 23.5.3.2 Conditional methods @@ -664,6 +664,12 @@ The use of conditional methods in an inheritance chain can be confusing. Calls m > > *end example* +#### §conditional-local-function Conditional local functions + +A local function may be made conditional in the same sense as a conditional method ([§23.5.3.2](attributes.md#23532-conditional-methods)). + +A conditional local function shall have the modifier `static`. + #### 23.5.3.3 Conditional attribute classes An attribute class ([§23.2](attributes.md#232-attribute-classes)) decorated with one or more `Conditional` attributes is a conditional attribute class. A conditional attribute class is thus associated with the conditional compilation symbols declared in its `Conditional` attributes. diff --git a/standard/statements.md b/standard/statements.md index 925564544..b6e5faa92 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -487,15 +487,15 @@ A *local_function_declaration* declares a local function. ```ANTLR local_function_declaration - : local_function_modifier* return_type local_function_header + : attributes? local_function_modifier* return_type local_function_header local_function_body - | ref_local_function_modifier* ref_kind ref_return_type + | attributes? ref_local_function_modifier* ref_kind ref_return_type local_function_header ref_local_function_body ; local_function_header - : identifier '(' parameter_list? ')' - | identifier type_parameter_list '(' parameter_list? ')' + : identifier parameter_list? + | identifier type_parameter_list parameter_list? type_parameter_constraints_clause* ; @@ -506,6 +506,7 @@ local_function_modifier ref_local_function_modifier : 'static' + | 'extern' | unsafe_modifier // unsafe code support ; @@ -513,11 +514,13 @@ local_function_body : block | '=>' null_conditional_invocation_expression ';' | '=>' expression ';' + | ';' ; ref_local_function_body : block | '=>' 'ref' variable_reference ';' + | ';' ; ``` @@ -562,7 +565,11 @@ Unless specified otherwise below, the semantics of all grammar elements is the s The *identifier* of a *local_function_declaration* shall be unique in its declared block scope, including any enclosing local variable declaration spaces. One consequence of this is that overloaded *local_function_declaration*s are not allowed. -A *local_function_declaration* may include one `async` ([§15.14](classes.md#1514-async-functions)) modifier and one `unsafe` ([§24.1](unsafe-code.md#241-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a `«TaskType»` type ([§15.14.1](classes.md#15141-general)). If the declaration includes the `static` modifier, the function is a ***static local function***; otherwise, it is a ***non-static local function***. It is a compile-time error for *type_parameter_list* or *parameter_list* to contain *attributes*. If the local function is declared in an unsafe context ([§24.2](unsafe-code.md#242-unsafe-contexts)), the local function may include unsafe code, even if the local function declaration doesn’t include the `unsafe` modifier. +A *local_function_declaration* may include one `async` ([§15.14](classes.md#1514-async-functions)) modifier and one `unsafe` ([§24.1](unsafe-code.md#241-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a `«TaskType»` type ([§15.14.1](classes.md#15141-general)). If the declaration includes the `static` modifier, the function is a ***static local function***; otherwise, it is a ***non-static local function***. If the local function is declared in an unsafe context ([§24.2](unsafe-code.md#242-unsafe-contexts)), the local function may include unsafe code, even if the local function declaration doesn’t include the `unsafe` modifier. + +An external local function shall have the modifier `static`, and its *local_function_body* or *ref_local_function_body* shall be a semicolon. + +A *local_function_body* or *ref_local_function_body* shall be a semicolon only for an external local function. A local function is declared at block scope. A non-static local function may capture variables from the enclosing scope while a static local function shall not (so it has no access to enclosing locals, parameters, non-static local functions, or `this`). It is a compile-time error if a captured variable is read by the body of a non-static local function but is not definitely assigned before each call to the function. A compiler shall determine which variables are definitely assigned on return ([§9.4.4.33](variables.md#94433-rules-for-variables-in-local-functions)). From 64c26224aa36f67d7e9217150dc828045e1bc1aa Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Fri, 14 Nov 2025 10:45:47 -0500 Subject: [PATCH 2/4] restore parens --- standard/statements.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/statements.md b/standard/statements.md index b6e5faa92..ced02972e 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -494,8 +494,8 @@ local_function_declaration ; local_function_header - : identifier parameter_list? - | identifier type_parameter_list parameter_list? + : identifier '(' parameter_list? ')' + | identifier type_parameter_list '(' parameter_list? ')' type_parameter_constraints_clause* ; From 78e991a67286193e6fcb4093dde31104e9e5cb73 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Fri, 14 Nov 2025 10:52:35 -0500 Subject: [PATCH 3/4] add new text re local functions --- standard/attributes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/standard/attributes.md b/standard/attributes.md index 66b1f9a72..70b10fd0b 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -839,6 +839,8 @@ For invocations that occur within field or event initializers, the member name u For invocations that occur within declarations of instance constructors, static constructors, finalizers and operators the member name used is implementation-dependent. +For an invocation that occurs within a local function, the name of the method that calls that local function is used. Consider the following: if method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! + ### 23.5.7 Code analysis attributes #### 23.5.7.1 General From 9445dda7aff91591a5791f30bc2af7dcf5953eed Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Fri, 14 Nov 2025 10:58:17 -0500 Subject: [PATCH 4/4] fix md --- standard/attributes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/attributes.md b/standard/attributes.md index 70b10fd0b..00d8a502a 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -839,7 +839,7 @@ For invocations that occur within field or event initializers, the member name u For invocations that occur within declarations of instance constructors, static constructors, finalizers and operators the member name used is implementation-dependent. -For an invocation that occurs within a local function, the name of the method that calls that local function is used. Consider the following: if method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! +For an invocation that occurs within a local function, the name of the method that calls that local function is used. Consider the following: if method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! ### 23.5.7 Code analysis attributes