From: Bob Duff <duff@adacore.com>
Prior to this fix, if pp(N) tried to print a "base type only" field, and
Base_Type(N) was not yet set, it would raise an exception, which was
confusing. This patch makes it simply ignore such fields. Similarly
for Impl_Base_Type_Only and Root_Type_Only fields.
We do this by having alternative versions of Base_Type,
Implementation_Base_Type, and Root_Type that return Empty
in error cases, and call these alteratives from Treepr.
We don't want to Base_Type and friends to return Empty;
we want them to blow up when called from anywhere but
Treepr.
gcc/ada/ChangeLog:
* atree.ads (Node_To_Fetch_From_If_Set): Alternative to
Node_To_Fetch_From that returns Empty in error cases.
For use only in Treepr.
* treepr.adb (Print_Entity_Field): Avoid printing field
if Node_To_Fetch_From_If_Set returns Empty.
* einfo-utils.ads (Base_Type_If_Set): Alternative to
Base_Type that returns Empty in error cases.
(Implementation_Base_Type_If_Set): Likewise.
(Root_Type_If_Set): Likewise.
(Underlying_Type): Use more accurate result subtype.
* einfo-utils.adb (Base_Type): Add Asserts.
(Implementation_Base_Type): Add Assert; minor cleanup.
(Root_Type): Add Assert; minor cleanup. Remove Assert that
is redundant with predicate.
(Base_Type_If_Set): Body of new function.
(Implementation_Base_Type_If_Set): Body of new function.
(Root_Type_If_Set): Body of new function.
Tested on x86_64-pc-linux-gnu, committed on master.
---
gcc/ada/atree.ads | 14 ++++
gcc/ada/einfo-utils.adb | 167 +++++++++++++++++++++++++++-------------
gcc/ada/einfo-utils.ads | 11 ++-
gcc/ada/treepr.adb | 6 +-
4 files changed, 141 insertions(+), 57 deletions(-)
@@ -651,6 +651,20 @@ package Atree is
-- similarly for the other two cases. This can return something other
-- than N only if N is an Entity.
+ function Node_To_Fetch_From_If_Set
+ (N : Node_Or_Entity_Id; Field : Node_Or_Entity_Field)
+ return Node_Or_Entity_Id is
+ (case Field_Descriptors (Field).Type_Only is
+ when No_Type_Only => N,
+ when Base_Type_Only => Base_Type_If_Set (N),
+ when Impl_Base_Type_Only => Implementation_Base_Type_If_Set (N),
+ when Root_Type_Only => Root_Type_If_Set (N));
+ -- This is a more permissive version of Node_To_Fetch_From, which
+ -- returns the same value, except it returns Empty in cases where
+ -- Node_To_Fetch_From would crash because relevant fields are not yet
+ -- set. This is used in Treepr, to allow it to print half-baked nodes
+ -- without crashing.
+
-----------------------------
-- Private Part Subpackage --
-----------------------------
@@ -669,6 +669,8 @@ package body Einfo.Utils is
Result := Id;
else
pragma Assert (Is_Type (Id));
+ -- ...because Is_Base_Type returns True for nontypes
+
Result := Etype (Id);
if False then
pragma Assert (Is_Base_Type (Result));
@@ -679,9 +681,29 @@ package body Einfo.Utils is
-- expect.
end if;
end if;
+
+ -- pragma Assert (Result = Base_Type_If_Set (Id));
+ -- Disabled; too slow
end return;
end Base_Type;
+ ----------------------
+ -- Base_Type_If_Set --
+ ----------------------
+
+ function Base_Type_If_Set (Id : E) return Opt_N_Entity_Id is
+ begin
+ return Result : Opt_N_Entity_Id do
+ if Is_Base_Type (Id) then
+ Result := Id;
+ elsif Field_Is_Initial_Zero (Id, F_Etype) then
+ Result := Empty;
+ else
+ Result := Etype (Id);
+ end if;
+ end return;
+ end Base_Type_If_Set;
+
----------------------
-- Declaration_Node --
----------------------
@@ -1374,30 +1396,43 @@ package body Einfo.Utils is
------------------------------
function Implementation_Base_Type (Id : E) return E is
- Bastyp : Entity_Id;
Imptyp : Entity_Id;
-
begin
- Bastyp := Base_Type (Id);
+ return Result : E := Base_Type (Id) do
+ if Is_Incomplete_Or_Private_Type (Result) then
+ Imptyp := Underlying_Type (Result);
- if Is_Incomplete_Or_Private_Type (Bastyp) then
- Imptyp := Underlying_Type (Bastyp);
+ -- If we have an implementation type, return its Base_Type.
- -- If we have an implementation type, then just return it,
- -- otherwise we return the Base_Type anyway. This can only
- -- happen in error situations and should avoid some error bombs.
-
- if Present (Imptyp) then
- return Base_Type (Imptyp);
- else
- return Bastyp;
+ if Present (Imptyp) then
+ Result := Base_Type (Imptyp);
+ end if;
end if;
- else
- return Bastyp;
- end if;
+ -- pragma Assert (Result = Implementation_Base_Type_If_Set (Id));
+ -- Disabled; too slow
+ end return;
end Implementation_Base_Type;
+ -------------------------------------
+ -- Implementation_Base_Type_If_Set --
+ -------------------------------------
+
+ function Implementation_Base_Type_If_Set (Id : E) return Opt_N_Entity_Id is
+ Imptyp : Entity_Id;
+ begin
+ return Result : Opt_N_Entity_Id := Base_Type_If_Set (Id) do
+ if Present (Result) and then Is_Incomplete_Or_Private_Type (Result)
+ then
+ Imptyp := Underlying_Type (Result);
+
+ if Present (Imptyp) then
+ Result := Base_Type_If_Set (Imptyp);
+ end if;
+ end if;
+ end return;
+ end Implementation_Base_Type_If_Set;
+
-------------------------
-- Invariant_Procedure --
-------------------------
@@ -2540,52 +2575,76 @@ package body Einfo.Utils is
---------------
function Root_Type (Id : E) return E is
- T, Etyp : Entity_Id;
+ Etyp : Entity_Id;
begin
- pragma Assert (Nkind (Id) in N_Entity);
+ return T : E := Base_Type (Id) do
+ if Ekind (T) = E_Class_Wide_Type then
+ T := Etype (T);
+ else
+ loop
+ Etyp := Etype (T);
- T := Base_Type (Id);
+ exit when T = Etyp
+ or else
+ (Is_Private_Type (T) and then Etyp = Full_View (T))
+ or else
+ (Is_Private_Type (Etyp) and then Full_View (Etyp) = T);
- if Ekind (T) = E_Class_Wide_Type then
- return Etype (T);
+ T := Etyp;
- -- Other cases
+ -- Quit if there is a circularity in the inheritance chain.
+ -- This happens in some error situations and we do not want
+ -- to get stuck in this loop.
- else
- loop
- Etyp := Etype (T);
+ if T = Base_Type (Id) then
+ Check_Error_Detected;
+ exit;
+ end if;
+ end loop;
+ end if;
- if T = Etyp then
- return T;
-
- -- Following test catches some error cases resulting from
- -- previous errors.
-
- elsif No (Etyp) then
- Check_Error_Detected;
- return T;
-
- elsif Is_Private_Type (T) and then Etyp = Full_View (T) then
- return T;
-
- elsif Is_Private_Type (Etyp) and then Full_View (Etyp) = T then
- return T;
- end if;
-
- T := Etyp;
-
- -- Return if there is a circularity in the inheritance chain. This
- -- happens in some error situations and we do not want to get
- -- stuck in this loop.
-
- if T = Base_Type (Id) then
- return T;
- end if;
- end loop;
- end if;
+ -- pragma Assert (T = Root_Type_If_Set (Id));
+ -- Disabled; too slow
+ end return;
end Root_Type;
+ function Root_Type_If_Set (Id : E) return Opt_N_Entity_Id is
+ Etyp : Entity_Id;
+
+ begin
+ return T : Opt_N_Entity_Id := Base_Type_If_Set (Id) do
+ if Ekind (T) = E_Class_Wide_Type then
+ T := Etype (T);
+ else
+ loop
+ Etyp := Etype (T);
+
+ if No (Etyp) then
+ T := Empty;
+ exit;
+ end if;
+
+ exit when T = Etyp
+ or else
+ (Is_Private_Type (T) and then Etyp = Full_View (T))
+ or else
+ (Is_Private_Type (Etyp) and then Full_View (Etyp) = T);
+
+ T := Etyp;
+
+ -- Quit if there is a circularity in the inheritance chain.
+ -- This happens in some error situations and we do not want
+ -- to get stuck in this loop.
+
+ if T = Base_Type_If_Set (Id) then
+ exit;
+ end if;
+ end loop;
+ end if;
+ end return;
+ end Root_Type_If_Set;
+
---------------------
-- Safe_Emax_Value --
---------------------
@@ -3010,7 +3069,7 @@ package body Einfo.Utils is
-- Underlying_Type --
---------------------
- function Underlying_Type (Id : E) return Entity_Id is
+ function Underlying_Type (Id : E) return Opt_N_Entity_Id is
begin
-- For record_with_private the underlying type is always the direct full
-- view. Never try to take the full view of the parent it does not make
@@ -161,6 +161,15 @@ package Einfo.Utils is
function First_Formal (Id : E) return Entity_Id;
function First_Formal_With_Extras (Id : E) return Entity_Id;
+ function Base_Type_If_Set (Id : E) return Opt_N_Entity_Id;
+ function Implementation_Base_Type_If_Set (Id : E) return Opt_N_Entity_Id;
+ function Root_Type_If_Set (Id : E) return Opt_N_Entity_Id;
+ -- Base_Type_If_Set is a more permissive version of Base_Type, which
+ -- returns the same value, except it returns Empty in cases where Base_Type
+ -- would crash because relevant fields are not yet set. Likewise for the
+ -- other two. These are used in Treepr, to allow it to print half-baked
+ -- nodes without crashing.
+
function Float_Rep
(N : Entity_Id) return F with Inline, Pre =>
N in E_Void_Id
@@ -238,7 +247,7 @@ package Einfo.Utils is
function Stream_Size_Clause (Id : E) return N with Inline;
function Type_High_Bound (Id : E) return N with Inline;
function Type_Low_Bound (Id : E) return N with Inline;
- function Underlying_Type (Id : E) return Entity_Id;
+ function Underlying_Type (Id : E) return Opt_N_Entity_Id;
function Scope_Depth (Id : Scope_Kind_Id) return U with Inline;
function Scope_Depth_Set (Id : Scope_Kind_Id) return B with Inline;
@@ -1047,9 +1047,11 @@ package body Treepr is
FD : Field_Descriptor;
Format : UI_Format := Auto)
is
- NN : constant Node_Id := Node_To_Fetch_From (N, Field);
+ NN : constant Node_Id := Node_To_Fetch_From_If_Set (N, Field);
+ -- If NN is Empty, it means that we cannot compute the
+ -- Node_To_Fetch_From, so we simply skip this field.
begin
- if not Field_Is_Initial_Zero (N, Field) then
+ if Present (NN) and then not Field_Is_Initial_Zero (N, Field) then
Print_Field (Prefix, Image (Field), NN, FD, Format);
end if;
end Print_Entity_Field;