This deals with 3 very old reports about illegal constructs being silently 
accepted by the compiler, in two different ways:

PR ada/18762: the compiler accepts the renaming of an inherited subprogram of 
a derived untagged type, because it sets convention Ada instead of Intrinsic 
on the subprogram.

PR ada/31417: the compiler accepts nonstatic constraints for the discriminants 
of the ancestor part of a private extension, whereas only statically matching 
ones are legal, because it checks only the full conformance of constraints.

PR ada/38330: the compiler accepts simple aggregates for the extension of a 
formal tagged private type, whereas only extension aggregates are legal.

The first 2 cases are benign and cannot be rejected without breaking working 
code, so the tweaks are mostly made to the commentary for them; the latter 
case is more problematic and, therefore, is fully fixed.

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


2026-10-21  Eric Botcazou  <[email protected]>

        PR ada/18762
        PR ada/31417
        PR ada/38330
        * sem_ch3.adb (Build_Derived_Record_Type): Set Has_Private_Ancestor
        on the extension of a formal tagged private type.  Implement the RM
        7.3(13) subclause consistently independently of whether the derived
        type itself is declared with discriminants.
        (Derive_Subprogram): Document the implementation of RM 6.3.1(7).
        (Process_Full_View): Remove obsolete comment about RM 7.3(13).


2026-10-21  Eric Botcazou  <[email protected]>

        * gnat.dg/specs/private4.ads: New test.

-- 
Eric Botcazou
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index 9dafd710799..f95cea479d6 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -9448,7 +9448,9 @@ package body Sem_Ch3 is
       --  type, mark it accordingly.
 
       if Is_Private_Type (Parent_Type) then
-         if Scope (Parent_Base) = Scope (Derived_Type) then
+         if Scope (Parent_Base) = Scope (Derived_Type)
+           and then not Is_Generic_Type (Parent_Base)
+         then
             null;
 
          elsif In_Open_Scopes (Scope (Parent_Base))
@@ -9593,14 +9595,15 @@ package body Sem_Ch3 is
             New_Discrs := No_Elist;
          end if;
 
+         --  RM 7.3(13) says that the constraints on the full view must
+         --  statically match those given in the partial view, but we
+         --  implement full conformance instead for historical reasons.
+
          if Has_Discriminants (Derived_Type)
            and then Has_Private_Declaration (Derived_Type)
            and then Present (Discriminant_Constraint (Derived_Type))
            and then Present (New_Discrs)
          then
-            --  Verify that constraints of the full view statically match
-            --  those given in the partial view.
-
             declare
                C1, C2 : Elmt_Id;
 
@@ -9620,8 +9623,8 @@ package body Sem_Ch3 is
                   else
                      if Constraint_Present then
                         Error_Msg_N
-                          ("constraint not conformant to previous declaration",
-                           Node (C1));
+                          ("constraint not conformant with previous "
+                           & "declaration", Node (C1));
                      else
                         Error_Msg_N
                           ("constraint of full view is incompatible "
@@ -9935,32 +9938,32 @@ package body Sem_Ch3 is
 
             Discs := Build_Discriminant_Constraints (Parent_Type, Indic, True);
 
-            --  For untagged types all new discriminants must rename
-            --  discriminants in the parent. For private extensions new
-            --  discriminants cannot rename old ones (implied by [7.3(13)]).
-
             Discrim := First_Discriminant (Derived_Type);
             while Present (Discrim) loop
+               --  For untagged types, all new discriminants must rename
+               --  discriminants in the parent.
+
                if not Is_Tagged
                  and then No (Corresponding_Discriminant (Discrim))
                then
                   Error_Msg_N
                     ("new discriminants must constrain old ones", Discrim);
 
+               --  For private extensions, new discriminants cannot rename
+               --  old ones (implied by RM 7.3(13)).
+
                elsif Private_Extension
                  and then Present (Corresponding_Discriminant (Discrim))
                then
                   Error_Msg_N
                     ("only static constraints allowed for parent"
                      & " discriminants in the partial view", Indic);
-                  exit;
-               end if;
 
                --  If a new discriminant is used in the constraint, then its
                --  subtype must be statically compatible with the subtype of
                --  the parent discriminant (RM 3.7(15)).
 
-               if Present (Corresponding_Discriminant (Discrim)) then
+               elsif Present (Corresponding_Discriminant (Discrim)) then
                   Check_Constraining_Discriminant
                     (Discrim, Corresponding_Discriminant (Discrim));
                end if;
@@ -9968,10 +9971,14 @@ package body Sem_Ch3 is
                Next_Discriminant (Discrim);
             end loop;
 
-            --  Check whether the constraints of the full view statically
-            --  match those imposed by the parent subtype [7.3(13)].
+            --  RM 7.3(13) says that the constraints on the full view must
+            --  statically match those given in the partial view, but we
+            --  implement full conformance instead for historical reasons.
 
-            if Present (Stored_Constraint (Derived_Type)) then
+            if Has_Private_Declaration (Derived_Type)
+              and then Present (Stored_Constraint (Derived_Type))
+              and then Present (Discs)
+            then
                declare
                   C1, C2 : Elmt_Id;
 
@@ -9979,12 +9986,19 @@ package body Sem_Ch3 is
                   C1 := First_Elmt (Discs);
                   C2 := First_Elmt (Stored_Constraint (Derived_Type));
                   while Present (C1) and then Present (C2) loop
-                     if not
-                       Fully_Conformant_Expressions (Node (C1), Node (C2))
+                     if Fully_Conformant_Expressions (Node (C1), Node (C2))
+                       or else
+                         (Is_OK_Static_Expression (Node (C1))
+                           and then Is_OK_Static_Expression (Node (C2))
+                           and then
+                            Expr_Value (Node (C1)) = Expr_Value (Node (C2)))
                      then
+                        null;
+
+                     else
                         Error_Msg_N
-                          ("not conformant with previous declaration",
-                           Node (C1));
+                          ("constraint not conformant with previous "
+                           & "declaration", Node (C1));
                      end if;
 
                      Next_Elmt (C1);
@@ -16949,7 +16963,8 @@ package body Sem_Ch3 is
 
       --  Derived subprograms of a tagged type must inherit the convention
       --  of the parent subprogram (a requirement of AI95-117). Derived
-      --  subprograms of untagged types simply get convention Ada by default.
+      --  subprograms of untagged types get convention Ada by default for
+      --  historical reasons, although RM 6.3.1(7) says it is intrinsic.
 
       --  If the derived type is a tagged generic formal type with unknown
       --  discriminants, its convention is intrinsic (RM 6.3.1 (8)).
@@ -22020,12 +22035,6 @@ package body Sem_Ch3 is
                  ("full view must define a constrained type if partial view "
                   & "has no discriminants", Full_T);
             end if;
-
-            --  Do we implement the following properly???
-            --  If the ancestor subtype of a private extension has constrained
-            --  discriminants, then the parent subtype of the full view shall
-            --  impose a statically matching constraint on those discriminants
-            --  [7.3(13)].
          end if;
 
       else
-- { dg-do compile }

generic

  type T1 is tagged private;

package Private4 is

  type T2 is new T1 with record
    I : Integer;
    J : Integer;
  end record;

  X : T2 := T2'(2,3); -- { dg-error "private ancestor|extension aggregate" }
  Y : T2 := T2'(T1 with 2,3);

end Private4;

Reply via email to