From bcc76900bdc0ec96d96a0a6290a3c21d1444e61b Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Fri, 9 Dec 2016 12:13:50 +0100
Subject: [PATCH] Ada/DWARF: add a DW_AT_type attribute to
 DW_TAG_enumeration_type

Currently, the DWARF description does not specify the signedness of the
representation of enumeration types.  This is a problem in some
contexts where DWARF consumers need to determine if value X is greater
than value Y.

For instance in Ada:

    type Enum_Type is ( A, B, C, D);
    for Enum_Type use (-1, 0, 1, 2);

    type Rec_Type (E : Enum_Type) is record
       when A .. B => null;
       when others => B : Booleann;
    end record;

The above can be described in DWARF the following way:

    DW_TAG_enumeration_type(Enum_Type)
    | DW_AT_byte_size: 1
      DW_TAG_enumerator(A)
      | DW_AT_const_value: -1
      DW_TAG_enumerator(B)
      | DW_AT_const_value: 0
      DW_TAG_enumerator(C)
      | DW_AT_const_value: 1
      DW_TAG_enumerator(D)
      | DW_AT_const_value: 2

    DW_TAG_structure_type(Rec_Type)
      DW_TAG_member(E)
      | DW_AT_type: <Enum_Type>
      DW_TAG_variant_part
      | DW_AT_discr: <E>
        DW_TAG_variant
        | DW_AT_discr_list: DW_DSC_range 0x7f 0
        DW_TAG_variant
        | DW_TAG_member(b)

DWARF consumers need to know that enumerators (A, B, C and D) are signed
in order to determine the set of E values for which Rec_Type has a B
field.  In practice, they need to know how to interpret the 0x7f LEB128
number above (-1, not 127).

There seems to be only two legal DWARF alternatives to solve this issue:
one is to add a DW_AT_type attribute to DW_TAG_enumerator_type DIEs to
make it point to a base type that specifies the signedness.  The other
is to make sure the form of the DW_AT_const_value attribute carries the
signedness information.

The first alternative is valid only starting with DWARF3. The second
alternative is valid will all versions of the DWARF standard, however it
removes the size information embedded in the form used to encode
DW_AT_const_value attributes (DW_FORM_data8/16/32).

This patch implements the first alternative.

gcc/

	* dwarf2out.h (gen_enumeration_type_die): If the selected DWARF
	standard allows it, add a DW_AT_type attribute for the
	enum's TREE_TYPE, if any.

gcc/ada/

	* gcc-interface/decl.c (gnat_to_gnu_entity): Assign a base type
	to enumeration types.
	* gcc-interface/misc.c (gnat_get_array_descr_info): Don't strip
	types in the bounds subrange type's TREE_TYPE chain if they
	bring information about the kind of integral type involved.
	* gcc-interface/utils.c (make_type_from_size): Likewise for the
	base types involved.
---
 gcc/ada/gcc-interface/decl.c  |  4 ++++
 gcc/ada/gcc-interface/misc.c  |  6 ++++--
 gcc/ada/gcc-interface/utils.c | 12 +++++++++++-
 gcc/dwarf2out.c               |  4 ++++
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 9de85ef..961499d 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -1670,6 +1670,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
 	  if (!is_boolean)
 	    TYPE_VALUES (gnu_type) = nreverse (gnu_list);
 
+	  /* Provide a base type so that in debug info, the enumeration type
+	     has signedness information associated.  */
+	  TREE_TYPE (gnu_type) = gnat_type_for_size (esize, is_unsigned);
+
 	  /* Note that the bounds are updated at the end of this function
 	     to avoid an infinite recursion since they refer to the type.  */
 	  goto discrete_type;
diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 1fed72a..7eeec81 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -964,8 +964,10 @@ gnat_get_array_descr_info (const_tree const_type,
 	}
 
       /* The DWARF back-end will output BOUNDS_TYPE as the base type of
-	 the array index, so get to the base type of INDEX_TYPE.  */
-      while (TREE_TYPE (index_type))
+	 the array index.  All subtypes in the TREE_TYPE chain that just bring
+	 bounds can be ignored: strip them.  */
+      while (TREE_CODE (index_type) == INTEGER_TYPE
+	     && TREE_TYPE (index_type) != NULL_TREE)
 	index_type = TREE_TYPE (index_type);
 
       info->dimen[i].bounds_type = maybe_debug_type (index_type);
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index cde17fe..bd9a5a4 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -1136,7 +1136,17 @@ make_type_from_size (tree type, tree size_tree, bool for_biased)
 	new_type = make_unsigned_type (size);
       else
 	new_type = make_signed_type (size);
-      TREE_TYPE (new_type) = TREE_TYPE (type) ? TREE_TYPE (type) : type;
+
+      /* If TYPE is a special integral type (e.g. an ENUMERAL_TYPE) while
+	 TYPE's base type is an INTEGER_TYPE, we need to keep the information
+	 that NEW_TYPE is a special integral type as well.  So in this case,
+	 don't skip TYPE in the base type chain.  */
+      TREE_TYPE (new_type)
+	= (TREE_TYPE (type)
+	   && TREE_CODE (TREE_TYPE (type)) == TREE_CODE (type))
+	  ? TREE_TYPE (type)
+	  : type;
+
       SET_TYPE_RM_MIN_VALUE (new_type, TYPE_MIN_VALUE (type));
       SET_TYPE_RM_MAX_VALUE (new_type, TYPE_MAX_VALUE (type));
       /* Copy the name to show that it's essentially the same type and
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 8dc8523..a61f114 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -20923,6 +20923,10 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
 			  scope_die_for (type, context_die), type);
       equate_type_number_to_die (type, type_die);
       add_name_attribute (type_die, type_tag (type));
+      if ((dwarf_version >= 3 || !dwarf_strict)
+	  && TREE_TYPE (type) != NULL_TREE)
+	add_type_attribute (type_die, TREE_TYPE (type), 0, TYPE_UNQUALIFIED,
+			    context_die);
       if (dwarf_version >= 4 || !dwarf_strict)
 	{
 	  if (ENUM_IS_SCOPED (type))
-- 
2.10.2

