This implements AI12-0402 in the function computing the accessibility level of
function calls in the general case, as opposed to the more specific case of
the RM 6.4.1(6.4) legality rule. This also removes a ??? note attached to the
handling of N_Assignment_Statement nodes in this function. This is needed to
plug the loophole reported under PR ada/124376.
Tested on x86-64/Linux, applied on the mainline.
2026-03-12 Eric Botcazou <[email protected]>
PR ada/124376
* accessibility.adb (Accessibility_Level): Minor formatting tweaks.
(Accessibility_Level.Function_Call_Or_Allocator_Level): Implement
AI12-0402. Reimplement the loop climbing up the parent chain to
find an object being initialized. Restrict the specific handling
of N_Assignment_Statement nodes to the anonymous access type case.
* doc/gnat_rm/implementation_of_ada_2022_features.rst: Adjust the
entries of AI12-0277, AI12-0345 & AI12-0372, add one for AI12-0402.
* gnat_rm.texi: Regenerate.
--
Eric Botcazoudiff --git a/gcc/ada/accessibility.adb b/gcc/ada/accessibility.adb
index 4c0863b798c..a6518c21611 100644
--- a/gcc/ada/accessibility.adb
+++ b/gcc/ada/accessibility.adb
@@ -255,8 +255,11 @@ package body Accessibility is
--------------------------------------
function Function_Call_Or_Allocator_Level (N : Node_Id) return Node_Id is
- Par : Node_Id;
- Prev_Par : Node_Id;
+ Prev_Par : Node_Id := Expr;
+ Par : Node_Id := Parent (Expr);
+ -- Par and Prev_Par will be used for traversing the AST, while
+ -- maintaining an invariant that Par = Parent (Prev_Par).
+
begin
-- First deal with function calls in Ada 95
@@ -282,26 +285,24 @@ package body Accessibility is
-- Otherwise the accessibility level of the innermost master
else
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
+ return Make_Level_Literal (Innermost_Master_Scope_Depth (Expr));
end if;
-- We ignore coextensions as they cannot be implemented under the
- -- "small-integer" model.
+ -- "small integer" model.
elsif Nkind (N) = N_Allocator
and then (Is_Static_Coextension (N)
or else Is_Dynamic_Coextension (N))
then
return Make_Level_Literal (Scope_Depth (Standard_Standard));
- end if;
- -- Named access types have a designated level
+ -- Objects of a named access type get their level from their type
- if Is_Named_Access_Type (Etype (N)) then
+ elsif Is_Named_Access_Type (Etype (N)) then
return Make_Level_Literal (Typ_Access_Level (Etype (N)));
- -- Otherwise, the level is dictated by RM 3.10.2 (10.7/3)
+ -- Function calls in Ada 2005 and later, and anonymous allocators
else
-- Check No_Dynamic_Accessibility_Checks restriction override for
@@ -318,16 +319,27 @@ package body Accessibility is
return Make_Level_Literal (Typ_Access_Level (Etype (N)));
-- For function calls the level is that of the innermost
- -- master, otherwise (for allocators etc.) we get the level
- -- of the corresponding anonymous access type, which is
+ -- master; otherwise, for allocators we get the level of
+ -- the corresponding anonymous access type, which is
-- calculated through the normal path of execution.
elsif Nkind (N) = N_Function_Call then
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
+ return
+ Make_Level_Literal (Innermost_Master_Scope_Depth (Expr));
end if;
end if;
+ -- AI12-0402: The master of the function call for a function
+ -- whose result type is a scalar type is always the innermost
+ -- master invoking the function.
+
+ if Ada_Version >= Ada_2022
+ and then Nkind (N) = N_Function_Call
+ and then Is_Scalar_Type (Etype (N))
+ then
+ return Make_Level_Literal (Innermost_Master_Scope_Depth (Expr));
+ end if;
+
-- Dynamic checks are generated when we are within a return
-- value or we are in a function call within an anonymous
-- access discriminant constraint of a return object (signified
@@ -361,76 +373,99 @@ package body Accessibility is
end;
end if;
- -- When the call is being dereferenced the level is that of the
- -- enclosing master of the dereferenced call.
+ -- Find any relevant parent nodes that designate an object being
+ -- initialized and stop when there is an inappropriate construct.
- if Nkind (Parent (N)) in N_Explicit_Dereference
- | N_Indexed_Component
- | N_Selected_Component
- then
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
- end if;
+ while Present (Par) loop
- -- Find any relevant enclosing parent nodes that designate an
- -- object being initialized.
+ case Nkind (Par) is
- -- Note: The above is only relevant if the result is used "in its
- -- entirety" as RM 3.10.2 (10.2/3) states. However, this is
- -- accounted for in the case statement in the main body of
- -- Accessibility_Level for N_Selected_Component.
+ -- RM 3.10.2 (10.2/5) is relevant only if the result is used
+ -- to "directly initialize" the object.
- Par := Parent (Expr);
- Prev_Par := Empty;
- while Present (Par) loop
- -- Detect an expanded implicit conversion, typically this
- -- occurs on implicitly converted actuals in calls.
+ when N_Explicit_Dereference | N_Function_Call | N_Op =>
+ exit;
- -- Does this catch all implicit conversions ???
+ -- RM 3.10.2 (10.2/5) is relevant only if the result is used
+ -- "in its entirety".
- if Nkind (Par) = N_Type_Conversion
- and then Is_Named_Access_Type (Etype (Par))
- then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Par)));
- end if;
+ when N_Indexed_Component | N_Selected_Component | N_Slice =>
+ exit;
- -- Jump out when we hit an object declaration or the right-hand
- -- side of an assignment, or a construct such as an aggregate
- -- subtype indication which would be the result is not used
- -- "in its entirety."
+ -- Accept operative constituents
- exit when Nkind (Par) in N_Object_Declaration
- or else (Nkind (Par) = N_Assignment_Statement
- and then Name (Par) /= Prev_Par);
+ when N_Case_Expression =>
+ exit when Prev_Par = Expression (Par);
- Prev_Par := Par;
- Par := Parent (Par);
- end loop;
+ when N_If_Expression =>
+ exit when Prev_Par = First (Expressions (Par));
- -- Assignment statements are handled in a similar way in
- -- accordance to the left-hand part. However, strictly speaking,
- -- this is illegal according to the RM, but this change is needed
- -- to pass an ACATS C-test and is useful in general ???
+ when N_Case_Expression_Alternative
+ | N_Qualified_Expression
+ | N_Unchecked_Type_Conversion
+ =>
+ null;
- case Nkind (Par) is
- when N_Object_Declaration =>
- return Make_Level_Literal
- (Scope_Depth
- (Scope (Defining_Identifier (Par))));
+ -- Detect an expanded implicit conversion, typically this
+ -- occurs on implicitly converted actuals in calls.
- when N_Assignment_Statement =>
- -- Return the accessibility level of the left-hand part
+ -- Does this catch all implicit conversions ???
- return Accessibility_Level
- (Expr => Name (Par),
- Level => Object_Decl_Level,
- In_Return_Context => In_Return_Context);
+ when N_Type_Conversion =>
+ if Is_Named_Access_Type (Etype (Par)) then
+ return
+ Make_Level_Literal (Typ_Access_Level (Etype (Par)));
+ end if;
- when others =>
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
- end case;
+ -- For the (static) declaration of an object, return the
+ -- accessibility level of the master of the object.
+
+ when N_Object_Declaration =>
+ return
+ Make_Level_Literal
+ (Scope_Depth (Scope (Defining_Identifier (Par))));
+
+ -- For the dynamic allocation of an object, return the
+ -- accessibility level of the allocator.
+
+ when N_Allocator =>
+ return Accessibility_Level (Par);
+
+ -- RM 3.10.2(10.3/5): If the result is of an anonymous
+ -- access type and is converted to a (named or anonymous)
+ -- access type, the master is determined following the
+ -- rules given for determining the master of an object
+ -- created by an allocator.
+
+ -- The conversion can be an implicit subtype conversion,
+ -- in particular the one in an assignment (RM 5.2(11/5)).
+
+ -- For an anonymous allocator in an assignment, return the
+ -- accessibility level of the name (RM 3.10.2(14/6)).
+
+ when N_Assignment_Statement =>
+ exit when Prev_Par = Name (Par)
+ or else not Is_Anonymous_Access_Type (Etype (N));
+
+ return Accessibility_Level
+ (Expr => Name (Par),
+ Level => Object_Decl_Level,
+ In_Return_Context => In_Return_Context);
+
+ when others =>
+ -- Prevent the search from going too far
+
+ exit when Is_Statement (Par)
+ or else Is_Body_Or_Package_Declaration (Par);
+ end case;
+
+ Prev_Par := Par;
+ Par := Parent (Par);
+ end loop;
+
+ -- Return the accessibility level of the innermost master
+
+ return Make_Level_Literal (Innermost_Master_Scope_Depth (Expr));
end if;
end Function_Call_Or_Allocator_Level;
@@ -544,8 +579,7 @@ package body Accessibility is
-- Named access types
if Is_Named_Access_Type (Etype (Pre)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Pre)));
+ return Make_Level_Literal (Typ_Access_Level (Etype (Pre)));
-- Anonymous access types
@@ -698,11 +732,10 @@ package body Accessibility is
then
return Accessibility_Level (Renamed_Entity_Or_Object (E));
- -- Named access types get their level from their associated type
+ -- Objects of a named access type get their level from their type
elsif Is_Named_Access_Type (Etype (E)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
+ return Make_Level_Literal (Typ_Access_Level (Etype (E)));
-- Check if E is an expansion-generated renaming of an iterator
-- by examining Related_Expression. If so, determine the
@@ -758,16 +791,14 @@ package body Accessibility is
-- of the named access type in the prefix.
elsif Is_Named_Access_Type (Etype (Pre)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Pre)));
+ return Make_Level_Literal (Typ_Access_Level (Etype (Pre)));
-- The current expression is a named access type, so there is no
-- reason to look at the prefix. Instead obtain the level of E's
-- named access type.
elsif Is_Named_Access_Type (Etype (E)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
+ return Make_Level_Literal (Typ_Access_Level (Etype (E)));
-- A nondiscriminant selected component where the component
-- is an anonymous access type means that its associated
@@ -809,14 +840,13 @@ package body Accessibility is
and then No_Dynamic_Accessibility_Checks_Enabled (E)
and then Debug_Flag_Underscore_B
then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
+ return Make_Level_Literal (Typ_Access_Level (Etype (E)));
end if;
-- Otherwise proceed normally
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Prefix (E))));
+ return
+ Make_Level_Literal (Typ_Access_Level (Etype (Prefix (E))));
-- The accessibility calculation routine that handles function
-- calls (Function_Call_Level) assumes, in the case the
@@ -862,8 +892,7 @@ package body Accessibility is
when N_Qualified_Expression =>
if Is_Named_Access_Type (Etype (E)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
+ return Make_Level_Literal (Typ_Access_Level (Etype (E)));
else
return Accessibility_Level (Expression (E));
end if;
@@ -908,8 +937,7 @@ package body Accessibility is
-- access type.
elsif Is_Named_Access_Type (Etype (E)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
+ return Make_Level_Literal (Typ_Access_Level (Etype (E)));
-- In section RM 3.10.2 (10/4) the accessibility rules for
-- aggregates and value conversions are outlined. Are these
diff --git a/gcc/ada/doc/gnat_rm/implementation_of_ada_2022_features.rst b/gcc/ada/doc/gnat_rm/implementation_of_ada_2022_features.rst
index 1e065e89891..f06f37f5fed 100644
--- a/gcc/ada/doc/gnat_rm/implementation_of_ada_2022_features.rst
+++ b/gcc/ada/doc/gnat_rm/implementation_of_ada_2022_features.rst
@@ -1627,7 +1627,7 @@ http://www.ada-auth.org/AI12-SUMMARY.HTML.
.. index:: AI12-0277 (Ada 2022 feature)
-* *AI12-0277 The meaning of "accessibility level of the body of F" (0000-00-00)*
+* *AI12-0277 The meaning of "accessibility level of the body of F" (2020-09-09)*
Clarify that the only time that an explicitly aliased formal parameter has different accessibility properties than an aliased part of a "normal" parameter is for the accessibility checking associated with a return statement.
@@ -1943,7 +1943,7 @@ http://www.ada-auth.org/AI12-SUMMARY.HTML.
.. index:: AI12-0345 (Ada 2022 feature)
-* *AI12-0345 Dynamic accessibility of explicitly aliased parameters (0000-00-00)*
+* *AI12-0345 Dynamic accessibility of explicitly aliased parameters (2020-09-09)*
Further clarify (after AI12-0277) accessibility rules for explicitly aliased parameters.
@@ -2038,7 +2038,7 @@ http://www.ada-auth.org/AI12-SUMMARY.HTML.
.. index:: AI12-0372 (Ada 2022 feature)
-* *AI12-0372 Static accessibility of "master of the call" (0000-00-00)*
+* *AI12-0372 Static accessibility of "master of the call" (2020-09-09)*
Add an extra compile-time accessibility check for explicitly aliased parameters needed to prevent dangling references.
@@ -2201,6 +2201,16 @@ http://www.ada-auth.org/AI12-SUMMARY.HTML.
RM references: 3.03 (23.2/3) 8.05.01 (4.7/5) 8.05.01 (5/3)
+.. index:: AI12-0402 (Ada 2022 feature)
+
+* *AI12-0402 Master of a function call with elementary result type (2026-01-07)*
+
+ This AI restricts the rule that makes the master of a function call, which
+ is used to directly initialize part of an object, that of the object being
+ initialized, to the case where the result type of the function is composite.
+
+ RM references: 3.10.2 (10.2/5)
+
.. index:: AI12-0409 (Ada 2022 feature)
* *AI12-0409 Preelaborable_Initialization and bounded containers (2021-06-23)*
diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi
index af3c1eadbd4..468206219d4 100644
--- a/gcc/ada/gnat_rm.texi
+++ b/gcc/ada/gnat_rm.texi
@@ -29745,7 +29745,7 @@ RM references: 8.05.01 (2/3) 8.05.01 (3/2)
@itemize *
@item
-`AI12-0277 The meaning of “accessibility level of the body of F” (0000-00-00)'
+`AI12-0277 The meaning of “accessibility level of the body of F” (2020-09-09)'
Clarify that the only time that an explicitly aliased formal parameter has different accessibility properties than an aliased part of a “normal” parameter is for the accessibility checking associated with a return statement.
@@ -30226,7 +30226,7 @@ RM references: 6.05 (5.12/5) 6.05 (8/4) 6.05 (8.1/3) 6.05 (21/3)
@itemize *
@item
-`AI12-0345 Dynamic accessibility of explicitly aliased parameters (0000-00-00)'
+`AI12-0345 Dynamic accessibility of explicitly aliased parameters (2020-09-09)'
Further clarify (after AI12-0277) accessibility rules for explicitly aliased parameters.
@@ -30376,7 +30376,7 @@ RM references: D.07 (1.3/5) D.07 (10.12/5)
@itemize *
@item
-`AI12-0372 Static accessibility of “master of the call” (0000-00-00)'
+`AI12-0372 Static accessibility of “master of the call” (2020-09-09)'
Add an extra compile-time accessibility check for explicitly aliased parameters needed to prevent dangling references.
@@ -30620,6 +30620,21 @@ the operand is a constant, or the target subtype statically matches the nominal
RM references: 3.03 (23.2/3) 8.05.01 (4.7/5) 8.05.01 (5/3)
@end itemize
+@geindex AI12-0402 (Ada 2022 feature)
+
+
+@itemize *
+
+@item
+`AI12-0402 Master of a function call with elementary result type (2026-01-07)'
+
+This AI restricts the rule that makes the master of a function call, which
+is used to directly initialize part of an object, that of the object being
+initialized, to the case where the result type of the function is composite.
+
+RM references: 3.10.2 (10.2/5)
+@end itemize
+
@geindex AI12-0409 (Ada 2022 feature)