From: Mathias Aparicio <[email protected]>

When a record is frozen it must be completely defined. This requires that
all of its components' types must also be completely defined
ARM 3.11.1 (8).

Before this patch, if a record was frozen while one of its components
was of a private type, the compiler complained that the record had a
private component, although privacy was not the root issue.

Now, the compiler states the actual problem directly: the type is not
completely defined.

gcc/ada/ChangeLog:

        * freeze.adb (Check_And_Freeze_Type): Emit a more precise error
        message when a component's frozen record is incompletely defined
        instead of printing private component error.
        * sem_util.ads (Incompletely_Defined): New function that
        traverses recursively a type and returns the first incompletely
        defined component or itself if it is incompletely defined.
        * sem_util.adb (Incompletely_Defined): Likewise.
        (Is_Incompletely_Defined): Refactor to a test of the new
        Incompletely_Defined function for equality with Empty.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/freeze.adb   |  2 +-
 gcc/ada/sem_util.adb | 70 ++++++++++++++++++++++++++++++--------------
 gcc/ada/sem_util.ads | 12 ++++++++
 3 files changed, 61 insertions(+), 23 deletions(-)

diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb
index 2b9ef460c36..5a694c99d63 100644
--- a/gcc/ada/freeze.adb
+++ b/gcc/ada/freeze.adb
@@ -9422,7 +9422,7 @@ package body Freeze is
                if Is_Incompletely_Defined (Typ)
                  and then not Is_Private_Type (Typ)
                then
-                  Error_Msg_NE ("\\type& has private component", N, Typ);
+                  Error_Msg_NE ("\\type& is not completely defined", N, Typ);
                end if;
 
                Explain_Error;
diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb
index 7feaa6b9879..fb587ee0919 100644
--- a/gcc/ada/sem_util.adb
+++ b/gcc/ada/sem_util.adb
@@ -18628,14 +18628,23 @@ package body Sem_Util is
    -----------------------------
 
    function Is_Incompletely_Defined (Type_Id : Entity_Id) return Boolean is
+   begin
+      return Present (Not_Fully_Declared_Part (Type_Id));
+   end Is_Incompletely_Defined;
+
+   -----------------------------
+   -- Not_Fully_Declared_Part --
+   -----------------------------
+
+   function Not_Fully_Declared_Part
+     (Type_Id : Entity_Id) return Entity_Id
+   is
       Btype     : Entity_Id := Base_Type (Type_Id);
       Component : Entity_Id;
-
    begin
-      if Error_Posted (Type_Id)
-        or else Error_Posted (Btype)
+      if Error_Posted (Type_Id) or else Error_Posted (Btype)
       then
-         return False;
+         return Empty;
       end if;
 
       if Is_Class_Wide_Type (Btype) then
@@ -18648,43 +18657,60 @@ package body Sem_Util is
          begin
             if No (UT) then
                if No (Full_View (Btype)) then
-                  return not Is_Generic_Type (Btype)
-                            and then
-                         not Is_Generic_Type (Root_Type (Btype));
+                  if not Is_Generic_Type (Btype)
+                    and then
+                  not Is_Generic_Type (Root_Type (Btype))
+                  then
+                     return Btype;
+                  end if;
                else
-                  return not Is_Generic_Type (Root_Type (Full_View (Btype)));
+                  if not Is_Generic_Type (Root_Type (Full_View (Btype))) then
+                     return Btype;
+                  end if;
                end if;
             else
-               return
-                 not Is_Frozen (UT) and then Is_Incompletely_Defined (UT);
+               if not Is_Frozen (UT) then
+                  return Not_Fully_Declared_Part (UT);
+               end if;
             end if;
+            return Empty;
          end;
 
       elsif Is_Array_Type (Btype) then
-         return Is_Incompletely_Defined (Component_Type (Btype));
+         return Not_Fully_Declared_Part (Component_Type (Btype));
 
       elsif Is_Record_Type (Btype) then
          Component := First_Component (Btype);
-         while Present (Component) loop
-            if Is_Incompletely_Defined (Etype (Component)) then
-               return True;
-            end if;
+         declare
+            Inc_par : Entity_Id;
+         begin
+            while Present (Component) loop
+               Inc_par :=
+                 Not_Fully_Declared_Part (Etype (Component));
+               if Present (Inc_par) then
+                  if Is_Type (Inc_par) then
+                     return Component;
+                  else
+                     return Inc_par;
+                  end if;
+               end if;
 
-            Next_Component (Component);
-         end loop;
-
-         return False;
+               Next_Component (Component);
+            end loop;
 
+            return Empty;
+         end;
       elsif Is_Protected_Type (Btype)
         and then Present (Corresponding_Record_Type (Btype))
       then
          return
-           Is_Incompletely_Defined (Corresponding_Record_Type (Btype));
+           Not_Fully_Declared_Part
+             (Corresponding_Record_Type (Btype));
 
       else
-         return False;
+         return Empty;
       end if;
-   end Is_Incompletely_Defined;
+   end Not_Fully_Declared_Part;
 
    ---------------------------
    -- Is_Independent_Object --
diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads
index 5f345273023..e3349a1b595 100644
--- a/gcc/ada/sem_util.ads
+++ b/gcc/ada/sem_util.ads
@@ -2255,6 +2255,18 @@ package Sem_Util is
    --  Returns True if N appears within the context clause of a unit, and False
    --  for any other placement.
 
+   function Not_Fully_Declared_Part
+      (Type_Id : Entity_Id) return Entity_Id;
+   --  Given a type, returns the reason it is not "completely defined".
+   --  We say that a type is "completely defined" at a place that is after
+   --  its full type definition (if it has one) and after all of its
+   --  subcomponent types are completely defined (RM 3.11.1 (8)).
+   --  If the return value is not Empty, Type_Id is incompletely defined
+   --  and the returned value points to the responsible subcomponent.
+   --
+   --  Used to enforce the rules on type freezing (RM 13.14), which require
+   --  that a type must be completely defined before it is frozen.
+
    function Is_Incompletely_Defined (Type_Id : Entity_Id) return Boolean;
    --  Returns True iff Type_Id is incompletely defined. See RM 3.11.1 (8) for
    --  the definition of "completely defined". Note that "incompletely defined"
-- 
2.53.0

Reply via email to