diff --git a/standard/attributes.md b/standard/attributes.md index f15cb3b55..b48aad59d 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -156,7 +156,7 @@ The types of positional and named parameters for an attribute class are limited ## 23.3 Attribute specification -Application of a previously defined attribute to a program entity is called ***attribute specification***. An attribute is a piece of additional declarative information that is specified for a program entity. Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for *type_declaration*s ([§14.7](namespaces.md#147-type-declarations)), *class_member_declaration*s ([§15.3](classes.md#153-class-members)), *interface_member_declaration*s ([§19.4](interfaces.md#194-interface-members)), *struct_member_declaration*s ([§16.3](structs.md#163-struct-members)), *enum_member_declaration*s ([§20.2](enums.md#202-enum-declarations)), *accessor_declaration*s ([§15.7.3](classes.md#1573-accessors)), *event_accessor_declaration*s ([§15.8](classes.md#158-events)), elements of *parameter_list*s ([§15.6.2](classes.md#1562-method-parameters)), and elements of *type_parameter_list*s ([§15.2.3](classes.md#1523-type-parameters)). +Application of a previously defined attribute to a program entity is called ***attribute specification***. An attribute is a piece of additional declarative information that is specified for a program entity. Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for *type_declaration*s ([§14.7](namespaces.md#147-type-declarations)), *class_member_declaration*s ([§15.3](classes.md#153-class-members)), *interface_member_declaration*s ([§19.4](interfaces.md#194-interface-members)), *struct_member_declaration*s ([§16.3](structs.md#163-struct-members)), *enum_member_declaration*s ([§20.2](enums.md#202-enum-declarations)), *accessor_declaration*s ([§15.7.3](classes.md#1573-accessors)), *event_accessor_declaration*s ([§15.8](classes.md#158-events)), *local_function_declaration*s ([§13.6.4](statements.md#1364-local-function-declarations)), elements of *parameter_list*s ([§15.6.2](classes.md#1562-method-parameters)), and elements of *type_parameter_list*s ([§15.2.3](classes.md#1523-type-parameters)). Attributes are specified in ***attribute section***s. An attribute section consists of a pair of square brackets, which surround a comma-separated list of one or more attributes. The order in which attributes are specified in such a list, and the order in which sections attached to the same program entity are arranged, is not significant. For instance, the attribute specifications `[A][B]`, `[B][A]`, `[A, B]`, and `[B, A]` are equivalent. @@ -252,10 +252,10 @@ The standardized *attribute_target* names are `event`, `field`, `method`, `param - `event` — an event. - `field` — a field. A field-like event (i.e., one without accessors) ([§15.8.2](classes.md#1582-field-like-events)) and an automatically implemented property ([§15.7.4](classes.md#1574-automatically-implemented-properties)) can also have an attribute with this target. -- `method` — a constructor, finalizer, method, operator, property get and set accessors, indexer get and set accessors, and event add and remove accessors. A field-like event (i.e., one without accessors) can also have an attribute with this target. -- `param` — a property set accessor, an indexer set accessor, event add and remove accessors, and a parameter in a constructor, method, and operator. +- `method` — a constructor, finalizer, method, local function, operator, property get and set accessors, indexer get and set accessors, and event add and remove accessors. A field-like event (i.e., one without accessors) can also have an attribute with this target. +- `param` — a property set accessor, an indexer set accessor, event add and remove accessors, and a parameter in a constructor, method, local function, and operator. - `property` — a property and an indexer. -- `return` — a delegate, method, operator, property get accessor, and indexer get accessor. +- `return` — a delegate, method, local function, operator, property get accessor, and indexer get accessor. - `type` — a delegate, class, struct, enum, and interface. - `typevar` — a type parameter. @@ -267,6 +267,9 @@ Certain contexts permit the specification of an attribute on more than one targe - For an attribute on a method declaration the default target is the method. Otherwise when the *attribute_target* is equal to: - `method` — the target is the method - `return` — the target is the return value +- For an attribute on a local function declaration the default target is the local function. Otherwise when the *attribute_target* is equal to: + - `method` — the target is the local function + - `return` — the target is the return value - For an attribute on an operator declaration the default target is the operator. Otherwise when the *attribute_target* is equal to: - `method` — the target is the operator - `return` — the target is the return value @@ -513,7 +516,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 method***s and ***conditional attribute class***es. +The attribute `Conditional` enables the definition of ***conditional method***s, ***conditional local function***s, and ***conditional attribute class***es. #### 23.5.3.2 Conditional methods @@ -667,6 +670,12 @@ The use of conditional methods in an inheritance chain can be confusing. Calls m > > *end example* +#### §conditional-local-function Conditional local functions + +A static local function may be made conditional in the same sense as a conditional method ([§23.5.3.2](attributes.md#23532-conditional-methods)). + +A compile time error occurs if a non-static local function is made conditional. + #### 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. @@ -836,6 +845,41 @@ 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 or an anonymous function, the name of the member method that calls that function is used. + +> *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* + ### 23.5.7 Code analysis attributes #### 23.5.7.1 General diff --git a/standard/statements.md b/standard/statements.md index 925564544..ced02972e 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -487,9 +487,9 @@ 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 ; @@ -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)). diff --git a/standard/variables.md b/standard/variables.md index e5b3d435f..a78601886 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -677,7 +677,7 @@ For an expression *expr*, which has subexpressions *expr₁*, *expr₂*, …, *e #### 9.4.4.24 Invocation expressions and object creation expressions -If the method to be invoked is a partial method that has no implementing partial method declaration, or is a conditional method for which the call is omitted ([§23.5.3.2](attributes.md#23532-conditional-methods)), then the definite-assignment state of *v* after the invocation is the same as the definite-assignment state of *v* before the invocation. Otherwise the following rules apply: +If the method to be invoked is a partial method that has no implementing partial method declaration, or is a conditional method or conditional local function for which the call is omitted ([§23.5.3.2](attributes.md#23532-conditional-methods), §conditional-local-function), then the definite-assignment state of *v* after the invocation is the same as the definite-assignment state of *v* before the invocation. Otherwise the following rules apply: For an invocation expression *expr* of the form: