The problem is that the freezing of the expression function is incomplete
and does not cause the freezing of stand-alone objects declared in the same
declarative part as the expression function.

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


2026-09-22  Eric Botcazou  <[email protected]>

        * freeze.adb (Freeze_Full_Expression): Also freeze the stand-alone
        objects of the current scope when they are referenced.
        * sem_ch6.adb (Analyze_Expression_Function): Do not check the use
        of a dynamically tagged expression if an error has been posted.

-- 
Eric Botcazou
diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb
index 634010e452f..c5156715d6e 100644
--- a/gcc/ada/freeze.adb
+++ b/gcc/ada/freeze.adb
@@ -9254,9 +9254,6 @@ package body Freeze is
       procedure Explain_Error;
       --  Output an explanation of the error as continuation messages
 
-      procedure Find_Incomplete_Constant (Node : Node_Id);
-      --  Search for a deferred constant without completion
-
       function Freeze_Type_Refs (Node : Node_Id) return Traverse_Result;
       --  Freeze all types referenced in the subtree rooted at Node
 
@@ -9344,41 +9341,6 @@ package body Freeze is
          end if;
       end Explain_Error;
 
-      ------------------------------
-      -- Find_Incomplete_Constant --
-      ------------------------------
-
-      procedure Find_Incomplete_Constant (Node : Node_Id) is
-      begin
-         --  When a constant is initialized with the result of a dispatching
-         --  call, the constant declaration is rewritten as a renaming of the
-         --  displaced function result. This scenario is not a premature use of
-         --  a constant even though the Has_Completion flag is not set.
-
-         if Is_Entity_Name (Node)
-           and then Present (Entity (Node))
-           and then Ekind (Entity (Node)) = E_Constant
-           and then Scope (Entity (Node)) = Current_Scope
-           and then Nkind (Declaration_Node (Entity (Node))) =
-                                                         N_Object_Declaration
-           and then not Is_Imported (Entity (Node))
-           and then not Has_Completion (Entity (Node))
-           and then not
-             (Present (Full_View (Entity (Node)))
-               and then (Has_Completion (Full_View (Entity (Node)))
-                          or else
-                            Declaration_Node (Full_View (Entity (Node))) = N))
-         then
-            Error_Msg_NE
-              ("deferred constant& is frozen before completion",
-               N, Entity (Node));
-
-            Explain_Error;
-
-            Set_Is_Frozen (Entity (Node));
-         end if;
-      end Find_Incomplete_Constant;
-
       ----------------------
       -- Freeze_Type_Refs --
       ----------------------
@@ -9437,22 +9399,59 @@ package body Freeze is
          --  Check that a type referenced by an entity can be frozen
 
          if Is_Entity_Name (Node) and then Present (Entity (Node)) then
-            --  The entity itself may be a type, as in a membership test
-            --  or an attribute reference. Freezing its own type would be
-            --  incomplete if the entity is derived or an extension.
+            declare
+               E : constant Entity_Id := Entity (Node);
 
-            if Is_Type (Entity (Node)) then
-               Check_And_Freeze_Type (Entity (Node));
+            begin
+               --  The entity itself may be a type, as in a membership test
+               --  or an attribute reference. Freezing its own type would be
+               --  incomplete if the entity is derived or an extension.
 
-            else
-               Check_And_Freeze_Type (Etype (Entity (Node)));
-            end if;
+               if Is_Type (E) then
+                  Check_And_Freeze_Type (E);
+               else
+                  Check_And_Freeze_Type (Etype (E));
+               end if;
 
-            --  Check that the enclosing record type can be frozen
+               --  Check that the enclosing record type can be frozen
 
-            if Ekind (Entity (Node)) in E_Component | E_Discriminant then
-               Check_And_Freeze_Type (Scope (Entity (Node)));
-            end if;
+               if Ekind (E) in E_Component | E_Discriminant then
+                  Check_And_Freeze_Type (Scope (E));
+               end if;
+
+               --  Freeze stand-alone objects declared in the current scope
+
+               if Ekind (E) in E_Constant | E_Variable
+                 and then Nkind (Declaration_Node (E)) = N_Object_Declaration
+                 and then Scope (E) = Current_Scope
+                 and then not Is_Frozen (E)
+               then
+                  --  The completion of a deferred constant declaration must
+                  --  occur before the constant is frozen (RM 7.4(9)). Give a
+                  --  better error message here than at the completion point.
+
+                  if Ekind (E) = E_Constant
+                    and then not Is_Imported (E)
+                    and then not Has_Completion (E)
+                    and then not (Present (Full_View (E))
+                                   and then Has_Completion (Full_View (E)))
+                  then
+                     Error_Msg_NE
+                       ("deferred constant& is frozen before completion",
+                        N, E);
+
+                     Explain_Error;
+
+                     Set_Is_Frozen (E);
+
+                  elsif Before then
+                     Freeze_Before (N, E);
+
+                  else
+                     Freeze_And_Append (E, N, Result);
+                  end if;
+               end if;
+            end;
 
          --  Freezing an access type does not freeze the designated type, but
          --  freezing conversions between access to interfaces requires that
@@ -9509,15 +9508,9 @@ package body Freeze is
             end;
          end if;
 
-         Find_Incomplete_Constant (Node);
-
          --  No point in posting several errors on the same expression
 
-         if Serious_Errors_Detected > 0 then
-            return Abandon;
-         else
-            return OK;
-         end if;
+         return (if Serious_Errors_Detected > 0 then Abandon else OK);
       end Freeze_Type_Refs;
 
       procedure Freeze_References is new Traverse_Proc (Freeze_Type_Refs);
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index 130cbcc7c97..2ed3b7c3f47 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -712,6 +712,7 @@ package body Sem_Ch6 is
 
       if Present (Def_Id)
         and then Is_Tagged_Type (Typ)
+        and then not Error_Posted (N)
       then
          Check_Dynamically_Tagged_Expression
            (Expr        => Expr,

Reply via email to