@@ -4743,6 +4743,12 @@ package body Sem_Ch6 is
Style.Body_With_No_Spec (N);
end if;
+ -- First set Acts_As_Spec if appropriate
+
+ if Nkind (N) /= N_Subprogram_Body_Stub then
+ Set_Acts_As_Spec (N);
+ end if;
+
New_Overloaded_Entity (Body_Id);
-- A subprogram body should cause freezing of its own declaration,
@@ -4767,7 +4773,6 @@ package body Sem_Ch6 is
end if;
if Nkind (N) /= N_Subprogram_Body_Stub then
- Set_Acts_As_Spec (N);
Generate_Definition (Body_Id);
Generate_Reference
(Body_Id, Body_Id, 'b', Set_Ref => False, Force => True);
@@ -9525,15 +9530,85 @@ package body Sem_Ch6 is
-----------------------------
procedure Check_Untagged_Equality (Eq_Op : Entity_Id) is
- Typ : constant Entity_Id := Etype (First_Formal (Eq_Op));
- Decl : constant Node_Id := Unit_Declaration_Node (Eq_Op);
- Obj_Decl : Node_Id;
+ Eq_Decl : constant Node_Id := Unit_Declaration_Node (Eq_Op);
+ Typ : constant Entity_Id := Etype (First_Formal (Eq_Op));
+
+ procedure Freezing_Point_Warning (N : Node_Id; S : String);
+ -- Output a warning about the freezing point N of Typ
+
+ function Is_Actual_Of_Instantiation
+ (E : Entity_Id;
+ Inst : Node_Id) return Boolean;
+ -- Return True if E is an actual parameter of instantiation Inst
+
+ -----------------------------------
+ -- Output_Freezing_Point_Warning --
+ -----------------------------------
+
+ procedure Freezing_Point_Warning (N : Node_Id; S : String) is
+ begin
+ Error_Msg_String (1 .. S'Length) := S;
+ Error_Msg_Strlen := S'Length;
+
+ if Ada_Version >= Ada_2012 then
+ Error_Msg_NE ("type& is frozen by ~??", N, Typ);
+ Error_Msg_N
+ ("\an equality operator cannot be declared after this point??",
+ N);
+
+ else
+ Error_Msg_NE ("type& is frozen by ~ (Ada 2012)?y?", N, Typ);
+ Error_Msg_N
+ ("\an equality operator cannot be declared after this point"
+ & " (Ada 2012)?y?", N);
+ end if;
+ end Freezing_Point_Warning;
+
+ --------------------------------
+ -- Is_Actual_Of_Instantiation --
+ --------------------------------
+
+ function Is_Actual_Of_Instantiation
+ (E : Entity_Id;
+ Inst : Node_Id) return Boolean
+ is
+ Assoc : Node_Id;
+
+ begin
+ if Present (Generic_Associations (Inst)) then
+ Assoc := First (Generic_Associations (Inst));
+
+ while Present (Assoc) loop
+ if Present (Explicit_Generic_Actual_Parameter (Assoc))
+ and then
+ Is_Entity_Name (Explicit_Generic_Actual_Parameter (Assoc))
+ and then
+ Entity (Explicit_Generic_Actual_Parameter (Assoc)) = E
+ then
+ return True;
+ end if;
+
+ Next (Assoc);
+ end loop;
+ end if;
+
+ return False;
+ end Is_Actual_Of_Instantiation;
+
+ -- Local variable
+
+ Decl : Node_Id;
+
+ -- Start of processing for Check_Untagged_Equality
begin
- -- This check applies only if we have a subprogram declaration with an
- -- untagged record type that is conformant to the predefined operator.
+ -- This check applies only if we have a subprogram declaration or a
+ -- subprogram body that is not a completion, for an untagged record
+ -- type, and that is conformant with the predefined operator.
- if Nkind (Decl) /= N_Subprogram_Declaration
+ if (Nkind (Eq_Decl) /= N_Subprogram_Declaration
+ and then not (Nkind (Eq_Decl) = N_Subprogram_Body
+ and then Acts_As_Spec (Eq_Decl)))
or else not Is_Record_Type (Typ)
or else Is_Tagged_Type (Typ)
or else not Is_User_Defined_Equality (Eq_Op)
@@ -9572,9 +9647,59 @@ package body Sem_Ch6 is
elsif Is_Generic_Actual_Type (Typ) then
return;
- -- Here we have a definite error of declaration after freezing
+ -- Here we may have an error of declaration after freezing, but we
+ -- must make sure not to flag the equality operator itself causing
+ -- the freezing when it is a subprogram body.
else
+ Decl := Next (Declaration_Node (Typ));
+
+ while Present (Decl) and then Decl /= Eq_Decl loop
+
+ -- The declaration of an object of the type
+
+ if Nkind (Decl) = N_Object_Declaration
+ and then Etype (Defining_Identifier (Decl)) = Typ
+ then
+ Freezing_Point_Warning (Decl, "declaration");
+ exit;
+
+ -- The instantiation of a generic on the type
+
+ elsif Nkind (Decl) in N_Generic_Instantiation
+ and then Is_Actual_Of_Instantiation (Typ, Decl)
+ then
+ Freezing_Point_Warning (Decl, "instantiation");
+ exit;
+
+ -- A noninstance proper body, body stub or entry body
+
+ elsif Nkind (Decl) in N_Proper_Body
+ | N_Body_Stub
+ | N_Entry_Body
+ and then not Is_Generic_Instance (Defining_Entity (Decl))
+ then
+ Freezing_Point_Warning (Decl, "body");
+ exit;
+
+ -- If we have reached the freeze node and immediately after we
+ -- have the body or generated code for the body, then it is the
+ -- body that caused the freezing and this is legal.
+
+ elsif Nkind (Decl) = N_Freeze_Entity
+ and then Entity (Decl) = Typ
+ and then (Next (Decl) = Eq_Decl
+ or else
+ Sloc (Next (Decl)) = Sloc (Eq_Decl))
+ then
+ return;
+ end if;
+
+ Next (Decl);
+ end loop;
+
+ -- Here we have a definite error of declaration after freezing
+
if Ada_Version >= Ada_2012 then
Error_Msg_NE
("equality operator must be declared before type & is "
@@ -9594,57 +9719,32 @@ package body Sem_Ch6 is
& "frozen (RM 4.5.2 (9.8)) (Ada 2012)?y?", Eq_Op, Typ);
end if;
- -- If we are in the package body, we could just move the
- -- declaration to the package spec, so add a message saying that.
+ -- If we have found no freezing point and the declaration of the
+ -- operator could not be reached from that of the type and we are
+ -- in a package body, this must be because the type is declared
+ -- in the spec of the package. Add a message tailored to this.
- if In_Package_Body (Scope (Typ)) then
+ if No (Decl) and then In_Package_Body (Scope (Typ)) then
if Ada_Version >= Ada_2012 then
- Error_Msg_N
- ("\move declaration to package spec<<", Eq_Op);
- else
- Error_Msg_N
- ("\move declaration to package spec (Ada 2012)?y?", Eq_Op);
- end if;
-
- -- Otherwise try to find the freezing point for better message.
-
- else
- Obj_Decl := Next (Parent (Typ));
- while Present (Obj_Decl) and then Obj_Decl /= Decl loop
- if Nkind (Obj_Decl) = N_Object_Declaration
- and then Etype (Defining_Identifier (Obj_Decl)) = Typ
- then
- -- Freezing point, output warnings
-
- if Ada_Version >= Ada_2012 then
- Error_Msg_NE
- ("type& is frozen by declaration??", Obj_Decl, Typ);
- Error_Msg_N
- ("\an equality operator cannot be declared after "
- & "this point??",
- Obj_Decl);
- else
- Error_Msg_NE
- ("type& is frozen by declaration (Ada 2012)?y?",
- Obj_Decl, Typ);
- Error_Msg_N
- ("\an equality operator cannot be declared after "
- & "this point (Ada 2012)?y?",
- Obj_Decl);
- end if;
-
- exit;
-
- -- If we reach generated code for subprogram declaration
- -- or body, it is the body that froze the type and the
- -- declaration is legal.
-
- elsif Sloc (Obj_Decl) = Sloc (Decl) then
- return;
+ if Nkind (Eq_Decl) = N_Subprogram_Body then
+ Error_Msg_N
+ ("\put declaration in package spec<<", Eq_Op);
+ else
+ Error_Msg_N
+ ("\move declaration to package spec<<", Eq_Op);
end if;
- Next (Obj_Decl);
- end loop;
+ else
+ if Nkind (Eq_Decl) = N_Subprogram_Body then
+ Error_Msg_N
+ ("\put declaration in package spec (Ada 2012)?y?",
+ Eq_Op);
+ else
+ Error_Msg_N
+ ("\move declaration to package spec (Ada 2012)?y?",
+ Eq_Op);
+ end if;
+ end if;
end if;
end if;
@@ -9653,21 +9753,21 @@ package body Sem_Ch6 is
-- a type has been derived from T.
else
- Obj_Decl := Next (Parent (Typ));
+ Decl := Next (Declaration_Node (Typ));
- while Present (Obj_Decl) and then Obj_Decl /= Decl loop
- if Nkind (Obj_Decl) = N_Full_Type_Declaration
- and then Etype (Defining_Identifier (Obj_Decl)) = Typ
+ while Present (Decl) and then Decl /= Eq_Decl loop
+ if Nkind (Decl) = N_Full_Type_Declaration
+ and then Etype (Defining_Identifier (Decl)) = Typ
then
Error_Msg_N
("equality operator cannot appear after derivation", Eq_Op);
Error_Msg_NE
("an equality operator for& cannot be declared after "
& "this point??",
- Obj_Decl, Typ);
+ Decl, Typ);
end if;
- Next (Obj_Decl);
+ Next (Decl);
end loop;
end if;
end Check_Untagged_Equality;
@@ -8967,14 +8967,7 @@ package body Sem_Res is
then
Eq := Get_User_Defined_Equality (T);
- -- We need to make sure that the instance is not within the
- -- same declarative region as the type, or else that it lies
- -- after the declaration of the user-defined "=" operator.
-
- if Present (Eq)
- and then (not In_Same_Extended_Unit (Eq, N)
- or else Earlier_In_Extended_Unit (Eq, N))
- then
+ if Present (Eq) then
if Is_Abstract_Subprogram (Eq) then
Nondispatching_Call_To_Abstract_Operation (N, Eq);
else