diff mbox

[Ada] Rejection of legal use of subp'Access within a generic body

Message ID 20150130150231.GA10768@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Jan. 30, 2015, 3:02 p.m. UTC
When the Access attribute is applied within a generic body to a prefix
that denotes a subprogram declared in an enclosing generic unit, the
compiler rejects this as a violation of the rule in the last sentence
of RM 3.10.2(32/3). This is happening because the compiler is requiring
both the access type and subprogram to be declared within the same
enclosing generic unit, but it should be allowing the type to be
anywhere within the declarative part of the generic unit where the
subprogram is declared.

The compiler must issue this output for the test below (based on ACATS B3A2017)
using the command 'gcc -c -gnatd70 generic_subp_access.adb', flagging only
the lines marked 'ERROR':

generic_subp_access.adb:42:22: 'Access attribute not allowed in
                               generic body, because access type
                               "Ref" is declared outside generic unit
                               (RM 3.10.2(32)), move 'Access to
                               private part, or (Ada 2005) use
                               anonymous access type instead of "Ref"
generic_subp_access.adb:44:15: subprogram must not be deeper than
                               access type
generic_subp_access.adb:48:19: 'Access attribute not allowed in
                               generic body, because access type
                               "Ref" is declared outside generic unit
                               (RM 3.10.2(32)), move 'Access to
                               private part, or (Ada 2005) use
                               anonymous access type instead of "Ref"
generic_subp_access.adb:50:12: subprogram must not be deeper than
                               access type

----

procedure Generic_Subp_Access is

   package Pkg is
      type Ref is access procedure;
      P, Q, R : Ref;
   end Pkg;

   generic
     type Formal_Subp_Acc is access procedure;
   package Outer_Generic is

      procedure Foo;

      generic
      package Inner_Generic is

        type Inner_Ref is access procedure;
        Y : Inner_Ref;

      end Inner_Generic;

   end Outer_Generic;

   package body Outer_Generic is
      X : Natural := 0;

      type Local_Ref is access procedure;
      W : Local_Ref;

      V : Formal_Subp_Acc;

      procedure Foo is
      begin
         X := X + 1;
      end Foo;

      package body Inner_Generic is

         M : Formal_Subp_Acc;

      begin
         Pkg.Q := Foo'Access;   -- ERROR
         Y := Foo'Access;       -- OK (was incorrectly flagged as an error)
         M := Foo'Access;       -- ERROR
      end Inner_Generic;

   begin
      Pkg.P := Foo'Access;      -- ERROR
      W := Foo'Access;          -- OK
      V := Foo'Access;          -- ERROR
   end Outer_Generic;

begin
   null;
end Generic_Subp_Access;

Tested on x86_64-pc-linux-gnu, committed on trunk

2015-01-30  Gary Dismukes  <dismukes@adacore.com>

	* sem_attr.adb (Declared_Within_Generic_Unit):
	New function to test whether an entity is declared within the
	declarative region of a given generic unit.
	(Resolve_Attribute): For checking legality of subprogram'Access within
	a generic unit, call new Boolean function Declared_Within_Generic_Unit
	instead of simply comparing the results of Enclosing_Generic_Unit on
	the prefix and access type.  Correct minor comment typos.
diff mbox

Patch

Index: sem_attr.adb
===================================================================
--- sem_attr.adb	(revision 220282)
+++ sem_attr.adb	(working copy)
@@ -9762,6 +9762,12 @@ 
       --  Error, or warning within an instance, if the static accessibility
       --  rules of 3.10.2 are violated.
 
+      function Declared_Within_Generic_Unit
+        (Entity       : Entity_Id;
+         Generic_Unit : Node_Id) return Boolean;
+      --  Returns True if Declared_Entity is declared within the declarative
+      --  region of Generic_Unit; otherwise returns False.
+
       ---------------------------
       -- Accessibility_Message --
       ---------------------------
@@ -9811,6 +9817,33 @@ 
          end if;
       end Accessibility_Message;
 
+      ----------------------------------
+      -- Declared_Within_Generic_Unit --
+      ----------------------------------
+
+      function Declared_Within_Generic_Unit
+        (Entity       : Entity_Id;
+         Generic_Unit : Node_Id) return Boolean
+      is
+         Generic_Encloser : Node_Id := Enclosing_Generic_Unit (Entity);
+
+      begin
+         while Present (Generic_Encloser) loop
+            if Generic_Encloser = Generic_Unit then
+               return True;
+            end if;
+
+            --  We have to step to the scope of the generic's entity, because
+            --  otherwise we'll just get back the same generic.
+
+            Generic_Encloser :=
+              Enclosing_Generic_Unit
+                (Scope (Defining_Entity (Generic_Encloser)));
+         end loop;
+
+         return False;
+      end Declared_Within_Generic_Unit;
+
    --  Start of processing for Resolve_Attribute
 
    begin
@@ -10058,11 +10091,11 @@ 
                   --  level of the actual type is not known). This restriction
                   --  does not apply when the attribute type is an anonymous
                   --  access-to-subprogram type. Note that this check was
-                  --  revised by AI-229, because the originally Ada 95 rule
+                  --  revised by AI-229, because the original Ada 95 rule
                   --  was too lax. The original rule only applied when the
                   --  subprogram was declared within the body of the generic,
                   --  which allowed the possibility of dangling references).
-                  --  The rule was also too strict in some case, in that it
+                  --  The rule was also too strict in some cases, in that it
                   --  didn't permit the access to be declared in the generic
                   --  spec, whereas the revised rule does (as long as it's not
                   --  a formal type).
@@ -10106,13 +10139,15 @@ 
                   then
                      --  The attribute type's ultimate ancestor must be
                      --  declared within the same generic unit as the
-                     --  subprogram is declared. The error message is
+                     --  subprogram is declared (including within another
+                     --  nested generic unit). The error message is
                      --  specialized to say "ancestor" for the case where the
                      --  access type is not its own ancestor, since saying
                      --  simply "access type" would be very confusing.
 
-                     if Enclosing_Generic_Unit (Entity (P)) /=
-                          Enclosing_Generic_Unit (Root_Type (Btyp))
+                     if not Declared_Within_Generic_Unit
+                              (Root_Type (Btyp),
+                               Enclosing_Generic_Unit (Entity (P)))
                      then
                         Error_Msg_N
                           ("''Access attribute not allowed in generic body",