This patch fixes a gap in the visibility machinery, that allowed the use
of selected component notation on objects of a private type derived from
other private types with a private full view.

Compiling foo.adb must yield:

   foo.adb:7:29: no selector "Exists"
         for type "Optional_Rate_Of_Turn_T" defined at fee.ads:29
   foo.adb:9:53: no selector "Value"
          for type "Optional_Rate_Of_Turn_Value_T" defined at fee.ads:16
---
package Foo is
  function F return Boolean;
  function F return Float;
end Foo;
---
with Fee;

package body Foo is

  O : Fee.Optional_Rate_Of_Turn_T;

  B1 : constant Boolean := O.Exists;
  V1  : constant Fee.Si_Float := Fee.Value (Fee.Value (O).Value);  -- OK
  V2  : constant Fee.Si_Float := Fee.Value (O).Value.Value;        -- Not OK

  function F return Boolean is
  begin
    return True; -- B1;
  end F;

  function F return Float is
  begin
    return V2;
  end F;
end Foo;
---
package body Apre_Optional is

  function Exists (V : T) return Boolean is
  begin
    return V.Exists;
  end Exists;

  function No_Value return T is
  begin
    return (Exists => False);
  end No_Value;

  function Value (V : T) return Value_Type_T is
  begin
    return V.Value;
  end Value;

  function Value (V : Value_Type_T) return T is
  begin
    return (Exists => True, Value => V);
  end Value;

  function Evaluate (V : T) return Value_Type_T is
  begin
    if V.Exists then
      return V.Value;
    else
      return Default_Value;
    end if;
  end Evaluate;

end Apre_Optional;
generic

  -- The type of value that might exist.
  --
  type Value_Type_T is private;

  -- The value is return from the function Value if exists is false.
  --
  Default_Value : Value_Type_T;

package Apre_Optional is

  type T is private;

  function Exists (V : T) return Boolean;

  function No_Value return T;
  function Value (V : Value_Type_T) return T;

  function Value (V : T) return Value_Type_T;

  function Evaluate (V : T) return Value_Type_T;

private

  package Fix is
    type T (Exists : Boolean := False) is
      record
        case Exists is
        when False =>
          null;
        when True =>
          Value : Value_Type_T;
        end case;
      end record;
  end Fix;

  type T is new Fix.T;
end Apre_Optional;
---
with Apre_Optional;
package Fee is

  subtype Si_Float is Float;

  package Optional_Float is new Apre_Optional (Si_Float, Si_Float'Last);
  type Optional_Float_T is new Optional_Float.T;

  type Rate_Of_Turn_T is
    (Left,
     Right,
     Straight,
     Not_Availible);

  type Optional_Rate_Of_Turn_Value_T is new Optional_Float_T;

  type Rate_Of_Turn_Fields_T is
    record
      Rate_Of_Turn : Rate_Of_Turn_T := Not_Availible;
      Value        : Optional_Rate_Of_Turn_Value_T := No_Value;
    end record;

  Null_Rate_Of_Turn_Fields : constant Rate_Of_Turn_Fields_T :=
    (Rate_Of_Turn => Not_Availible,
     Value        => No_Value);

  package Optional_Rate_Of_Turn is new
       Apre_Optional (Rate_Of_Turn_Fields_T, Null_Rate_Of_Turn_Fields);
  type Optional_Rate_Of_Turn_T is new Optional_Rate_Of_Turn.T;

end Fee;

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

2013-04-25  Ed Schonberg  <schonb...@adacore.com>

        * einfo.ads: Extend documentation on use of Is_Private_Ancestor
        for untagged types.
        * sem_ch3.adb (Is_Visible_Component): Refine predicate for the
        case of untagged types derived from private types, to reject
        illegal selected components.

Index: sem_ch3.adb
===================================================================
--- sem_ch3.adb (revision 198244)
+++ sem_ch3.adb (working copy)
@@ -16468,10 +16468,15 @@
          Type_Scope     := Scope (Base_Type (Scope (C)));
       end if;
 
-      --  This test only concerns tagged types
+      --  For an untagged type derived from a private type, the only
+      --  visible components are new discriminants.
 
       if not Is_Tagged_Type (Original_Scope) then
-         return True;
+         return not Has_Private_Ancestor (Original_Scope)
+            or else In_Open_Scopes (Scope (Original_Scope))
+            or else
+              (Ekind (Original_Comp) = E_Discriminant
+                 and then Original_Scope = Type_Scope);
 
       --  If it is _Parent or _Tag, there is no visibility issue
 
@@ -17383,8 +17388,6 @@
          --  now. We have to create a new entity with the same name, Thus we
          --  can't use Create_Itype.
 
-         --  This is messy, should be fixed ???
-
          Full := Make_Defining_Identifier (Sloc (Id), Chars (Id));
          Set_Is_Itype (Full);
          Set_Associated_Node_For_Itype (Full, Related_Nod);
Index: einfo.ads
===================================================================
--- einfo.ads   (revision 198283)
+++ einfo.ads   (working copy)
@@ -1753,12 +1753,14 @@
 --       is defined for the type.
 
 --    Has_Private_Ancestor (Flag151)
---       Applies to type extensions. True if some ancestor is derived from a
---       private type, making some components invisible and aggregates illegal.
---       This flag is set at the point of derivation. The legality of the
---       aggregate must be rechecked because it also depends on the visibility
---       at the point the aggregate is resolved. See sem_aggr.adb.
---       This is part of AI05-0115.
+--       Applies to untagged derived types and to type extensions. True when
+--       some ancestor is derived from a private type, making some components
+--       invisible and aggregates illegal. Used to check the legality of
+--       selected components and aggregates. The flag is set at the point of
+--       derivation.
+--       The legality of an aggregate of a type with a private ancestor  must
+--       be checked because it also depends on the visibility at the point the
+--       aggregate is resolved. See sem_aggr.adb. This is part of AI05-0115.
 
 --    Has_Private_Declaration (Flag155)
 --       Defined in all entities. Returns True if it is the defining entity

Reply via email to