From a8271dfceb512900e232e7250730508765dbbc84 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 --- standard/statements.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/standard/statements.md b/standard/statements.md index a8fc58a60..abd65ec6c 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -487,36 +487,40 @@ 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 '(' formal_parameter_list? ')' - | identifier type_parameter_list '(' formal_parameter_list? ')' + : identifier parameter_list? + | identifier type_parameter_list parameter_list? type_parameter_constraints_clause* ; local_function_modifier : ref_local_function_modifier | 'async' + | 'extern' ; ref_local_function_modifier - : unsafe_modifier // unsafe code support + : 'extern' + | unsafe_modifier // unsafe code support ; local_function_body : block | '=>' null_conditional_invocation_expression ';' | '=>' expression ';' + | ';' ; ref_local_function_body : block | '=>' 'ref' variable_reference ';' + | ';' ; ``` @@ -561,7 +565,11 @@ Unless specified otherwise below, the semantics of all grammar elements is the s The *identifier* of a *local_function_declaration* must 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.15](classes.md#1515-async-functions)) modifier and one `unsafe` ([§23.1](unsafe-code.md#231-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a `«TaskType»` type ([§15.15.1](classes.md#15151-general)). The `unsafe` modifier uses the containing lexical scope. The `async` modifier does not use the containing lexical scope. It is a compile-time error for *type_parameter_list* or *formal_parameter_list* to contain *attributes*. +A *local_function_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)), one `async` ([§15.15](classes.md#1515-async-functions)) modifier, one `extern` ([§15.6.8](classes.md#1568-external-methods)) modifier, and one `unsafe` ([§23.1](unsafe-code.md#231-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a `«TaskType»` type ([§15.15.1](classes.md#15151-general)). The `unsafe` modifier uses the containing lexical scope. The `async` modifier does not use the containing lexical scope. + +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, and that function may capture variables from the enclosing scopes. It is a compile-time error if a captured variable is read by the body of the local function but is not definitely assigned before each call to the function. The compiler shall determine which variables are definitely assigned on return ([§9.4.4.33](variables.md#94433-rules-for-variables-in-local-functions)). From 6cda407f73f9abbe015c0871143771cce5150777 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 19 Nov 2023 10:30:42 -0500 Subject: [PATCH 2/4] Add support for attributes and extern on local functions --- standard/attributes.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/standard/attributes.md b/standard/attributes.md index 6afb317d8..3615dc48e 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -539,7 +539,7 @@ A class that is decorated with the `AttributeUsage` attribute shall derive from #### 22.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***. #### 22.5.3.2 Conditional methods @@ -688,6 +688,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 ([§22.5.3.2](attributes.md#22532-conditional-methods)). + +A conditional local function shall have the modifier `static`. + #### 22.5.3.3 Conditional attribute classes An attribute class ([§22.2](attributes.md#222-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. @@ -852,6 +858,39 @@ 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. +> *Example*: Consider the following: +> +> +> ```csharp +> class Program +> { +> static void Main() +> { +> F1(); +> +> void F1([CallerMemberName] string? name = null) +> { +> Console.WriteLine($"F1 MemberName: |{name}|"); +> F2(); +> } +> +> static void F2([CallerMemberName] string? name = null) +> { +> Console.WriteLine($"F2 MemberName: |{name}|"); +> } +> } +> } +> ``` +> +> which produces the output +> +> ```console +> F1 MemberName: |Main| +> F2 MemberName: |Main| +> ``` +> +> This attribute supplies the name of the calling function member, which for local function `F1` is the method `Main`. And even though `F2` is called by `F1`, a local function is *not* a function member, so the reported caller of `F2` is also `Main`. *end example* + ## 22.6 Attributes for interoperation For interoperation with other languages, an indexer may be implemented using indexed properties. If no `IndexerName` attribute is present for an indexer, then the name `Item` is used by default. The `IndexerName` attribute enables a developer to override this default and specify a different name. From 9d18c8d7a72d0b152e23a66378880b018e56a2ae Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 19 Nov 2023 10:42:48 -0500 Subject: [PATCH 3/4] fix md formatting --- standard/attributes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/attributes.md b/standard/attributes.md index 3615dc48e..4d623891f 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -888,7 +888,7 @@ For invocations that occur within declarations of instance constructors, static > F1 MemberName: |Main| > F2 MemberName: |Main| > ``` -> +> > This attribute supplies the name of the calling function member, which for local function `F1` is the method `Main`. And even though `F2` is called by `F1`, a local function is *not* a function member, so the reported caller of `F2` is also `Main`. *end example* ## 22.6 Attributes for interoperation From eada9c19252ab1e37b890be7b1e2881cfd88f2fe Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 19 Nov 2023 13:35:22 -0500 Subject: [PATCH 4/4] remove duplicate rule --- standard/statements.md | 1 - 1 file changed, 1 deletion(-) diff --git a/standard/statements.md b/standard/statements.md index abd65ec6c..72ad0fb0f 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -502,7 +502,6 @@ local_function_header local_function_modifier : ref_local_function_modifier | 'async' - | 'extern' ; ref_local_function_modifier