The case itself is fairly pathological (and very likely not human made), but 
it's a clear incentive to get rid of an old kludge in generic instantiation, 
whereby the full view of a type is forced on nodes in the generic unit even 
though only the partial declaration is visible to them.

Tested on x86-64/Linux, applied on the mainline.


2026-03-27  Eric Botcazou  <[email protected]>

        PR ada/124596
        * sem_ch12.ads (Check_Private_View): Move around.
        * sem_ch12.adb (Check_Private_View): Retrieve the partial view
        by means of a call to Incomplete_Or_Partial_View.
        (Save_Global_References.Set_Global_Type): Do not force the full
        view of a type when only the partial declaration is visible.
        * sem_res.adb (Resolve_Actuals.Insert_Default): Remove obsolete
        code coping with the above kludge.


2026-03-27  Eric Botcazou  <[email protected]>

        * gnat.dg/generic_inst21.adb: New test.

-- 
Eric Botcazou
diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb
index c2697c74f96..2710d0545f4 100644
--- a/gcc/ada/sem_ch12.adb
+++ b/gcc/ada/sem_ch12.adb
@@ -9235,15 +9235,19 @@ package body Sem_Ch12 is
            and then (not In_Open_Scopes (Scope (Typ))
                       or else Nkind (Parent (N)) = N_Subtype_Declaration)
          then
+            --  In the generic unit, only the private declaration was visible,
+            --  so restore the partial view of Typ when there was an explicit
+            --  declaration of its full view.
+
             declare
-               Assoc : constant Node_Id := Get_Associated_Node (N);
+               Priv_Typ : constant Entity_Id :=
+                 Incomplete_Or_Partial_View (Typ, Partial_Only => True);
 
             begin
-               --  In the generic, only the private declaration was visible
-
-               Prepend_Elmt (Typ, Exchanged_Views);
-               Exchange_Declarations
-                 (if Comparison then Compare_Type (Assoc) else Etype (Assoc));
+               if Present (Priv_Typ) then
+                  Prepend_Elmt (Typ, Exchanged_Views);
+                  Exchange_Declarations (Priv_Typ);
+               end if;
             end;
 
          --  Check that the available views of Typ match their respective flag.
@@ -18607,22 +18611,10 @@ package body Sem_Ch12 is
          elsif No (Full_View (Typ)) and then Typ /= Etype (Typ) then
             null;
 
-         --  Otherwise mark the type for flipping and set the full view on N2
-         --  when available, which is necessary for Check_Private_View to swap
-         --  back the views in case the full declaration of Typ is visible in
-         --  the instantiation context. Note that this will be problematic if
-         --  N2 is re-analyzed later, e.g. if it's a default value in a call.
+         --  Otherwise mark the node as seeing the private view
 
          else
             Set_Has_Private_View (N);
-
-            if Present (Full_View (Typ)) then
-               if Comparison then
-                  Set_Compare_Type (N2, Full_View (Typ));
-               else
-                  Set_Etype (N2, Full_View (Typ));
-               end if;
-            end if;
          end if;
 
          if Is_Floating_Point_Type (Typ)
diff --git a/gcc/ada/sem_ch12.ads b/gcc/ada/sem_ch12.ads
index 478d968ce95..94f6f9829b1 100644
--- a/gcc/ada/sem_ch12.ads
+++ b/gcc/ada/sem_ch12.ads
@@ -64,6 +64,22 @@ package Sem_Ch12 is
    --  this call, then Parent_Installed is set True, otherwise Parent_Installed
    --  is unchanged by the call.
 
+   procedure Check_Private_View (N : Node_Id);
+   --  Check whether the type of a generic entity has a different view between
+   --  the point of generic analysis and the point of instantiation. If the
+   --  view has changed, then at the point of instantiation we restore the
+   --  correct view to perform semantic analysis of the instance, and reset
+   --  the current view after instantiation. The processing is driven by the
+   --  current private status of the type of the node, and Has_Private_View,
+   --  a flag that is set at the point of generic compilation. If view and
+   --  flag are inconsistent then the type is updated appropriately. A second
+   --  flag Has_Secondary_Private_View is used to update a second type related
+   --  to this type if need be.
+   --
+   --  This subprogram is used in Check_Generic_Actuals and Copy_Generic_Node,
+   --  and is exported here for the purpose of front-end inlining (see Exp_Ch6.
+   --  Expand_Inlined_Call.Process_Formals).
+
    function Copy_Generic_Node
      (N             : Node_Id;
       Parent_Id     : Node_Id;
@@ -228,20 +244,4 @@ package Sem_Ch12 is
    procedure Initialize;
    --  Initializes internal data structures
 
-   procedure Check_Private_View (N : Node_Id);
-   --  Check whether the type of a generic entity has a different view between
-   --  the point of generic analysis and the point of instantiation. If the
-   --  view has changed, then at the point of instantiation we restore the
-   --  correct view to perform semantic analysis of the instance, and reset
-   --  the current view after instantiation. The processing is driven by the
-   --  current private status of the type of the node, and Has_Private_View,
-   --  a flag that is set at the point of generic compilation. If view and
-   --  flag are inconsistent then the type is updated appropriately. A second
-   --  flag Has_Secondary_Private_View is used to update a second type related
-   --  to this type if need be.
-   --
-   --  This subprogram is used in Check_Generic_Actuals and Copy_Generic_Node,
-   --  and is exported here for the purpose of front-end inlining (see Exp_Ch6.
-   --  Expand_Inlined_Call.Process_Formals).
-
 end Sem_Ch12;
diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb
index 7f168499426..53cef024b32 100644
--- a/gcc/ada/sem_res.adb
+++ b/gcc/ada/sem_res.adb
@@ -4038,23 +4038,6 @@ package body Sem_Res is
                  and then Has_Discriminants (Etype (Actval))
                then
                   Analyze_And_Resolve (Actval, Base_Type (Etype (Actval)));
-
-               --  Resolve entities with their own type, which may differ from
-               --  the type of a reference in a generic context because of the
-               --  trick used in Save_Global_References.Set_Global_Type to set
-               --  full views forcefully, which did not anticipate the need to
-               --  re-analyze default values in calls.
-
-               elsif Is_Entity_Name (Actval) then
-                  Analyze_And_Resolve (Actval, Etype (Entity (Actval)));
-
-               --  Ditto for calls whose name is an entity, for the same reason
-
-               elsif Nkind (Actval) = N_Function_Call
-                 and then Is_Entity_Name (Name (Actval))
-               then
-                  Analyze_And_Resolve (Actval, Etype (Entity (Name (Actval))));
-
                else
                   Analyze_And_Resolve (Actval, Etype (Actval));
                end if;
-- { dg-do compile }

procedure Generic_Inst21 is

   package Config is
      type Config_Data is private;
   private
      type Config_Data is null record;
   end Config;

   generic
   package Config_Saving is

      type Config_Saver is synchronized interface;

      procedure Register_For_Saving
        (This : in out Config_Saver; Config_Data : Config.Config_Data)
      is abstract;

      type Instance is synchronized new Config_Saver with private;

   private

      protected type Instance is new Config_Saver with
         overriding
         procedure Register_For_Saving (Config_Data : Config.Config_Data);
      end Instance;

   end Config_Saving;

   package body Config_Saving is

      protected body Instance is
         procedure Register_For_Saving (Config_Data : Config.Config_Data) is
         begin
            null;
         end Register_For_Saving;
      end Instance;

   end Config_Saving;

   package My_Config_Saving is new Config_Saving;

   X : aliased My_Config_Saving.Instance;
   Y : access My_Config_Saving.Config_Saver'Class := X'Access;
   Z : Config.Config_Data;

begin
   Y.Register_For_Saving (Z);
end;

Reply via email to