[Ada] Spurious run time error on anonymous access formals
authorJustin Squirek <squirek@adacore.com>
Wed, 18 Sep 2019 08:33:07 +0000 (08:33 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Wed, 18 Sep 2019 08:33:07 +0000 (08:33 +0000)
commit43b264110f5581af0cc93308f9433fe8053f01cc
treebf5040d78121224b3f819b3ec3708201aabd818a
parentc8324fe7b12851c16c867f16ce248c95d2dbae7d
[Ada] Spurious run time error on anonymous access formals

This patch fixes an issue whereby subprograms with anonymous access
formals may trigger spurious runtime accessibility errors when such
formals are used as actuals in calls to nested subprograms.

Running these commands:

  gnatmake -q pass.adb
  gnatmake -q fail.adb
  gnatmake -q test_main.adb
  gnatmake -q indirect_call_test.adb
  pass
  fail
  test_main
  indirect_call_test

On the following sources:

--  pass.adb

procedure Pass is

  function A (Param : access Integer) return Boolean is
    type Typ is access all Integer;
    function A_Inner (Param : access Integer) return Typ is
      begin
        return Typ (Param); --  OK
      end;
    begin
      return A_Inner (Param) = Typ (Param);
    end;

  function B (Param : access Integer) return Boolean;
  function B (Param : access Integer) return Boolean is
    type Typ is access all Integer;
    function B_Inner (Param : access Integer) return Typ is
      begin
        return Typ (Param); --  OK
      end;
    begin
      return B_Inner (Param) = Typ (Param);
    end;

  procedure C (Param : access Integer) is
    type Typ is access all Integer;
    Var : Typ;
    procedure C_Inner (Param : access Integer) is
      begin
        Var := Typ (Param); --  OK
      end;
    begin
      C_Inner (Param);
    end;

  procedure D (Param : access Integer);
  procedure D (Param : access Integer) is
    type Typ is access all Integer;
    Var : Typ;
    procedure D_Inner (Param : access Integer) is
      begin
        Var := Typ (Param); --  OK
      end;
    begin
      D_Inner (Param);
    end;

  protected type E is
    function G (Param : access Integer) return Boolean;
    procedure I (Param : access Integer);
  end;

  protected body E is
    function F (Param : access Integer) return Boolean is
      type Typ is access all Integer;
      function F_Inner (Param : access Integer) return Typ is
        begin
          return Typ (Param); --  OK
        end;
      begin
        return F_Inner (Param) = Typ (Param);
      end;

    function G (Param : access Integer) return Boolean is
      type Typ is access all Integer;
      function G_Inner (Param : access Integer) return Typ is
        begin
          return Typ (Param); --  OK
        end;
      B : Boolean := F (Param); --  OK
      begin
        return G_Inner (Param) = Typ (Param);
      end;

    procedure H (Param : access Integer) is
      type Typ is access all Integer;
      Var : Typ;
      procedure H_Inner (Param : access Integer) is
        begin
          Var := Typ (Param); --  OK
        end;
      begin
        H_Inner (Param);
      end;

    procedure I (Param : access Integer) is
      type Typ is access all Integer;
      Var : Typ;
      procedure I_Inner (Param : access Integer) is
        begin
          Var := Typ (Param); --  OK
        end;
      begin
        H (Param); --  OK
        I_Inner (Param);
      end;
  end;

  task type J is end;

  task body J is
    function K (Param : access Integer) return Boolean is
      type Typ is access all Integer;
      function K_Inner (Param : access Integer) return Typ is
        begin
          return Typ (Param); --  OK
        end;
      begin
        return K_Inner (Param) = Typ (Param);
      end;

    function L (Param : access Integer) return Boolean;
    function L (Param : access Integer) return Boolean is
      type Typ is access all Integer;
      function L_Inner (Param : access Integer) return Typ is
        begin
          return Typ (Param); --  OK
        end;
      begin
        return L_Inner (Param) = Typ (Param);
      end;

    procedure M (Param : access Integer) is
      type Typ is access all Integer;
      Var : Typ;
      procedure M_Inner (Param : access Integer) is
        begin
          Var := Typ (Param); --  OK
        end;
      begin
        M_Inner (Param);
      end;

    procedure N (Param : access Integer);
    procedure N (Param : access Integer) is
      type Typ is access all Integer;
      Var : Typ;
      procedure N_Inner (Param : access Integer) is
        begin
          Var := Typ (Param); --  OK
        end;
      begin
        N_Inner (Param);
      end;
    Var : aliased Integer := 666;
    begin
      if K (Var'Access) then null; end if; --  OK
      if L (Var'Access) then null; end if; --  OK
      M (Var'Access);                      --  OK
      N (Var'Access);                      --  OK
    end;

begin
  begin
    begin
      declare
      Var  : aliased Integer := 666;
      T    : J;
      Prot : E;
      begin
        if A (Var'Access) then null; end if;      --  OK
        if B (Var'Access) then null; end if;      --  OK
        C (Var'Access);                           --  OK
        D (Var'Access);                           --  OK
        if Prot.G (Var'Access) then null; end if; --  OK
        Prot.I (Var'Access);                      --  OK
      end;
    end;
  end;
end;

--  fail.adb

procedure Fail is
  Failures : Integer := 0;

  type Base_Typ is access all Integer;

  function A (Param : access Integer) return Boolean is
    subtype Typ is Base_Typ;
    function A_Inner (Param : access Integer) return Typ is
      begin
        return Typ (Param); --  ERROR
      end;
    begin
      return A_Inner (Param) = Typ (Param);
    exception
      when others => Failures := Failures + 1;
      return False;
    end;

  function B (Param : access Integer) return Boolean;
  function B (Param : access Integer) return Boolean is
    subtype Typ is Base_Typ;
    function B_Inner (Param : access Integer) return Typ is
      begin
        return Typ (Param); --  ERROR
      end;
    begin
      return B_Inner (Param) = Typ (Param);
    exception
      when others => Failures := Failures + 1;
      return False;
    end;

  procedure C (Param : access Integer) is
    subtype Typ is Base_Typ;
    Var : Typ;
    procedure C_Inner (Param : access Integer) is
      begin
        Var := Typ (Param); --  ERROR
      end;
    begin
      C_Inner (Param);
    exception
      when others => Failures := Failures + 1;
    end;

  procedure D (Param : access Integer);
  procedure D (Param : access Integer) is
    subtype Typ is Base_Typ;
    Var : Typ;
    procedure D_Inner (Param : access Integer) is
      begin
        Var := Typ (Param); --  ERROR
      end;
    begin
      D_Inner (Param);
    exception
      when others => Failures := Failures + 1;
    end;

  protected type E is
    function G (Param : access Integer) return Boolean;
    procedure I (Param : access Integer);
  end;

  protected body E is
    function F (Param : access Integer) return Boolean is
      subtype Typ is Base_Typ;
      function F_Inner (Param : access Integer) return Typ is
        begin
          return Typ (Param); --  ERROR
        end;
      begin
        return F_Inner (Param) = Typ (Param);
      exception
        when others => Failures := Failures + 1;
        return False;
      end;

    function G (Param : access Integer) return Boolean is
      subtype Typ is Base_Typ;
      function G_Inner (Param : access Integer) return Typ is
        begin
          return Typ (Param); --  ERROR
        end;
      B : Boolean := F (Param); --  ERROR
      begin
        return G_Inner (Param) = Typ (Param);
      exception
        when others => Failures := Failures + 1;
        return False;
      end;

    procedure H (Param : access Integer) is
      subtype Typ is Base_Typ;
      Var : Typ;
      procedure H_Inner (Param : access Integer) is
        begin
          Var := Typ (Param); --  ERROR
        end;
      begin
        H_Inner (Param);
      exception
        when others => Failures := Failures + 1;
      end;

    procedure I (Param : access Integer) is
      subtype Typ is Base_Typ;
      Var : Typ;
      procedure I_Inner (Param : access Integer) is
        begin
          Var := Typ (Param); --  ERROR
        end;
      begin
        H (Param); --  ERROR
        I_Inner (Param);
      exception
        when others => Failures := Failures + 1;
      end;
  end;

  task type J is end;

  task body J is
    function K (Param : access Integer) return Boolean is
      subtype Typ is Base_Typ;
      function K_Inner (Param : access Integer) return Typ is
        begin
          return Typ (Param); --  ERROR
        end;
      begin
        return K_Inner (Param) = Typ (Param);
      exception
        when others => Failures := Failures + 1;
        return False;
      end;

    function L (Param : access Integer) return Boolean;
    function L (Param : access Integer) return Boolean is
      subtype Typ is Base_Typ;
      function L_Inner (Param : access Integer) return Typ is
        begin
          return Typ (Param); --  ERROR
        end;
      begin
        return L_Inner (Param) = Typ (Param);
      exception
        when others => Failures := Failures + 1;
        return False;
      end;

    procedure M (Param : access Integer) is
      subtype Typ is Base_Typ;
      Var : Typ;
      procedure M_Inner (Param : access Integer) is
        begin
          Var := Typ (Param); --  ERROR
        end;
      begin
        M_Inner (Param);
      exception
        when others => Failures := Failures + 1;
      end;

    procedure N (Param : access Integer);
    procedure N (Param : access Integer) is
      subtype Typ is Base_Typ;
      Var : Typ;
      procedure N_Inner (Param : access Integer) is
        begin
          Var := Typ (Param); --  ERROR
        end;
      begin
        N_Inner (Param);
      exception
        when others => Failures := Failures + 1;
      end;
    Var : aliased Integer := 666;
    begin
      if K (Var'Access) then null; end if; --  ERROR
      if L (Var'Access) then null; end if; --  ERROR
      M (Var'Access);                      --  ERROR
      N (Var'Access);                      --  ERROR
    end;

begin
  begin
    begin
      declare
      Var  : aliased Integer := 666;
      T    : J;
      Prot : E;
      begin
        if A (Var'Access) then null; end if;      --  ERROR
        if B (Var'Access) then null; end if;      --  ERROR
        C (Var'Access);                           --  ERROR
        D (Var'Access);                           --  ERROR
        if Prot.G (Var'Access) then null; end if; --  ERROR
        Prot.I (Var'Access);                      --  ERROR
        if Failures /= 12 then
          raise Program_Error;
        end if;
      end;
    end;
  end;
end;

--  indirect_call_test.adb

with Text_IO;

procedure Indirect_Call_Test is

   Tracing_Enabled : constant Boolean := False;
   procedure Trace (S : String) is
   begin
      if Tracing_Enabled then
        Text_IO.Put_Line (S);
      end if;
   end;

   package Pkg is
      type Root is abstract tagged null record;
      function F (X : Root; Param : access Integer)
        return Boolean is abstract;
   end Pkg;

   function F_Wrapper
     (X : Pkg.Root; Param : access Integer)
     return Boolean
     is (Pkg.F (Pkg.Root'Class (X), Param));
     -- dispatching call

   function A (Param : access Integer) return Boolean is
      type Typ is access all Integer;

      package Nested is
         type Ext is new Pkg.Root with null record;
         overriding function F
           (X : Ext; Param : access Integer)
           return Boolean;
      end Nested;

      function A_Inner
        (Param : access Integer) return Typ is
      begin
         return Typ (Param);  -- OK
      end A_Inner;

      package body Nested is
         function F (X : Ext; Param : access Integer)
          return Boolean is
         begin
            return A_Inner (Param) = null;
         end;
      end;

       Ext_Obj : Nested.Ext;
   begin
       Trace ("In subtest A");
       return F_Wrapper (Pkg.Root (Ext_Obj), Param);
   exception
      when Program_Error =>
          Trace ("Failed");
          return True;
   end A;

   function B (Param : access Integer) return Boolean is
      type Typ is access all Integer;

      function B_Inner
        (Param : access Integer) return Typ is
      begin
         return Typ (Param); -- OK
      end B_Inner;

      type Ref is access function
         (Param : access Integer) return Typ;
      Ptr : Ref := B_Inner'Access;

      function Ptr_Caller return Typ is
        (Ptr.all (Param)); -- access-to-subp value
   begin
      Trace ("In subtest B");
      return Ptr_Caller = null;
   exception
      when Program_Error =>
          Trace ("*** failed");
          return True;
   end B;

begin
   begin
      begin
         declare
            Var : aliased Integer := 666;
         begin
            if A (Var'Access) then
               null;
            end if;
            Trace ("Subtest A done");
            if B (Var'Access) then
               null;
            end if;
            Trace ("Subtest B done");
         end;
      end;
   end;
end Indirect_Call_Test;

Should produce the following output:

  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure
  Failure

2019-09-18  Justin Squirek  <squirek@adacore.com>

gcc/ada/

* einfo.adb, einfo.ads (Minimum_Accessibility): Added new field.
(Set_Minimum_Accessibility): Added to set new field.
(Minimum_Accessibility): Added to fetch new field.
* exp_ch6.adb (Expand_Subprogram_Call): Modify calls to fetch
accessibility levels to the new subprogram Get_Accessibility
which handles cases where minimum accessibility might be needed.
* sem_ch6.adb (Analyze_Subprogram_Body_Helper): Add section to
generate a Minimum_Accessibility object within relevant
subprograms.
* sem_util.adb, sem_util.ads (Dynamic_Accessibility_Level):
Additional documentation added and modify section to use new
function Get_Accessibility.
(Get_Accessibility): Added to centralize processing of
accessibility levels.

From-SVN: r275858
gcc/ada/ChangeLog
gcc/ada/einfo.adb
gcc/ada/einfo.ads
gcc/ada/exp_ch6.adb
gcc/ada/sem_ch6.adb
gcc/ada/sem_util.adb
gcc/ada/sem_util.ads