[Ada] Support for C99 and C++ standard boolean types
authorEric Botcazou <ebotcazou@adacore.com>
Fri, 25 May 2018 09:03:29 +0000 (09:03 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Fri, 25 May 2018 09:03:29 +0000 (09:03 +0000)
This change the type Interfaces.C.Extensions.bool to be fully compatible
with the C99 and C++ standard boolean types by making it a fully-fledged
boolean type with convention C.

The following C+Ada program must compile quietly in LTO mode:

bool b;

struct S {};

bool foo (struct S *s) { return true; }

pragma Ada_2005;
pragma Style_Checks (Off);

with Interfaces.C; use Interfaces.C;
with Interfaces.C.Extensions;

package t_c is

   b : aliased Extensions.bool;  -- t.c:3
   pragma Import (C, b, "b");

   type S is record
      null;
   end record;
   pragma Convention (C_Pass_By_Copy, S);  -- t.c:5

   function foo (the_s : access S) return Extensions.bool;  -- t.c:7
   pragma Import (C, foo, "foo");

end t_c;

with t_c; use t_c;

procedure P_C is

  Dummy : aliased S;

begin
  b := foo (Dummy'Access);
end;

2018-05-25  Eric Botcazou  <ebotcazou@adacore.com>

gcc/ada/

* freeze.adb (Freeze_Enumeration_Type): Do not give integer size to a
boolean type with convention C.
* libgnat/i-cexten.ads (bool): Change to boolean with convention C.
* gcc-interface/decl.c (gnat_to_gnu_entity): Add new local variable
FOREIGN and use it throughout the function.
<E_Enumeration_Type>: Set precision 1 on boolean types with foreign
convention.
<E_Enumeration_Subtype>: Likewise for subtypes.
<E_Record_Type>: Force the size of a storage unit on empty classes.
* gcc-interface/utils.c (make_type_from_size) <BOOLEAN_TYPE>: Skip
boolean types with precision 1 if the size is the expected one.

From-SVN: r260721

gcc/ada/ChangeLog
gcc/ada/freeze.adb
gcc/ada/gcc-interface/decl.c
gcc/ada/gcc-interface/utils.c
gcc/ada/libgnat/i-cexten.ads

index 3f183c38520243a875407c92c3c8d5a428dfba69..838c445213c7fa068f1d7f30281a2ce4d9aebb4b 100644 (file)
@@ -1,3 +1,17 @@
+2018-05-25  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * freeze.adb (Freeze_Enumeration_Type): Do not give integer size to a
+       boolean type with convention C.
+       * libgnat/i-cexten.ads (bool): Change to boolean with convention C.
+       * gcc-interface/decl.c (gnat_to_gnu_entity): Add new local variable
+       FOREIGN and use it throughout the function.
+       <E_Enumeration_Type>: Set precision 1 on boolean types with foreign
+       convention.
+       <E_Enumeration_Subtype>: Likewise for subtypes.
+       <E_Record_Type>: Force the size of a storage unit on empty classes.
+       * gcc-interface/utils.c (make_type_from_size) <BOOLEAN_TYPE>: Skip
+       boolean types with precision 1 if the size is the expected one.
+
 2018-05-25  Arnaud Charlet  <charlet@adacore.com>
 
        * pprint.adb (Expression_Name): Do not print non ASCII characters.
index a27561968bed9132b2b37ef88dff3b9440f2cb62..72b8f9536b2ad19406ea7f6cadc0da74659c5177 100644 (file)
@@ -6877,12 +6877,15 @@ package body Freeze is
    procedure Freeze_Enumeration_Type (Typ : Entity_Id) is
    begin
       --  By default, if no size clause is present, an enumeration type with
-      --  Convention C is assumed to interface to a C enum, and has integer
-      --  size. This applies to types. For subtypes, verify that its base
-      --  type has no size clause either. Treat other foreign conventions
-      --  in the same way, and also make sure alignment is set right.
+      --  Convention C is assumed to interface to a C enum and has integer
+      --  size, except for a boolean type because it is assumed to interface
+      --  to _Bool introduced in C99. This applies to types. For subtypes,
+      --  verify that its base type has no size clause either. Treat other
+      --  foreign conventions in the same way, and also make sure alignment
+      --  is set right.
 
       if Has_Foreign_Convention (Typ)
+        and then not Is_Boolean_Type (Typ)
         and then not Has_Size_Clause (Typ)
         and then not Has_Size_Clause (Base_Type (Typ))
         and then Esize (Typ) < Standard_Integer_Size
index a63cc1887bf78ab11b6f5f2943a707ed4f41da03..738211fab5663858b73cd32af1f6d481324f3803 100644 (file)
@@ -282,6 +282,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
   /* True if this entity is to be considered as imported.  */
   const bool imported_p
     = (Is_Imported (gnat_entity) && No (Address_Clause (gnat_entity)));
+  /* True if this entity has a foreign convention.  */
+  const bool foreign = Has_Foreign_Convention (gnat_entity);
   /* For a type, contains the equivalent GNAT node to be used in gigi.  */
   Entity_Id gnat_equiv_type = Empty;
   /* Temporary used to walk the GNAT tree.  */
@@ -658,8 +660,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
          }
 
        /* Get the type after elaborating the renamed object.  */
-       if (Has_Foreign_Convention (gnat_entity)
-           && Is_Descendant_Of_Address (Underlying_Type (gnat_type)))
+       if (foreign && Is_Descendant_Of_Address (Underlying_Type (gnat_type)))
          gnu_type = ptr_type_node;
        else
          {
@@ -1594,6 +1595,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
          tree gnu_list = NULL_TREE;
          Entity_Id gnat_literal;
 
+         /* Boolean types with foreign convention have precision 1.  */
+         if (is_boolean && foreign)
+           esize = 1;
+
          gnu_type = make_node (is_boolean ? BOOLEAN_TYPE : ENUMERAL_TYPE);
          TYPE_PRECISION (gnu_type) = esize;
          TYPE_UNSIGNED (gnu_type) = is_unsigned;
@@ -1774,6 +1779,15 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
          && Is_Bit_Packed_Array (Original_Array_Type (gnat_entity)))
        esize = UI_To_Int (RM_Size (gnat_entity));
 
+      /* Boolean types with foreign convention have precision 1.  */
+      if (Is_Boolean_Type (gnat_entity) && foreign)
+       {
+         gnu_type = make_node (BOOLEAN_TYPE);
+         TYPE_PRECISION (gnu_type) = 1;
+         TYPE_UNSIGNED (gnu_type) = 1;
+         set_min_and_max_values_for_integral_type (gnu_type, 1, UNSIGNED);
+         layout_type (gnu_type);
+       }
       /* First subtypes of Character are treated as Character; otherwise
         this should be an unsigned type if the base type is unsigned or
         if the lower bound is constant and non-negative or if the type
@@ -1783,7 +1797,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
         conversions to it and gives more leeway to the optimizer; but
         this means that we will need to explicitly test for this case
         when we change the representation based on the RM size.  */
-      if (kind == E_Enumeration_Subtype
+      else if (kind == E_Enumeration_Subtype
          && No (First_Literal (Etype (gnat_entity)))
          && Esize (gnat_entity) == RM_Size (gnat_entity)
          && esize == CHAR_TYPE_SIZE
@@ -1808,8 +1822,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
                                         gnat_entity, "U", definition, true,
                                         debug_info_p));
 
-      TYPE_BIASED_REPRESENTATION_P (gnu_type)
-       = Has_Biased_Representation (gnat_entity);
+      if (TREE_CODE (gnu_type) == INTEGER_TYPE)
+       TYPE_BIASED_REPRESENTATION_P (gnu_type)
+         = Has_Biased_Representation (gnat_entity);
 
       /* Do the same processing for Character subtypes as for types.  */
       if (TYPE_STRING_FLAG (TREE_TYPE (gnu_type)))
@@ -3300,6 +3315,15 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
                                  all_rep ? NULL_TREE : bitsize_zero_node,
                                  NULL);
 
+           /* Empty classes have the size of a storage unit in C++.  */
+           if (TYPE_SIZE (gnu_type) == bitsize_zero_node
+               && Convention (gnat_entity) == Convention_CPP)
+             {
+               TYPE_SIZE (gnu_type) = bitsize_unit_node;
+               TYPE_SIZE_UNIT (gnu_type) = size_one_node;
+               compute_record_mode (gnu_type);
+             }
+
            /* If there are entities in the chain corresponding to components
               that we did not elaborate, ensure we elaborate their types if
               they are Itypes.  */
@@ -3966,8 +3990,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
        /* If we should request stack realignment for a foreign convention
           subprogram, do so.  Note that this applies to task entry points
           in particular.  */
-       if (FOREIGN_FORCE_REALIGN_STACK
-           && Has_Foreign_Convention (gnat_entity))
+       if (FOREIGN_FORCE_REALIGN_STACK && foreign)
          prepend_one_attribute
            (&attr_list, ATTR_MACHINE_ATTRIBUTE,
             get_identifier ("force_align_arg_pointer"), NULL_TREE,
index eb2c2573a3f429a3d1d63a46d31984f93c826273..cc25973c2e90b65dffed234d4ddfe9246dd5e8de 100644 (file)
@@ -1133,9 +1133,15 @@ make_type_from_size (tree type, tree size_tree, bool for_biased)
 
   switch (TREE_CODE (type))
     {
+    case BOOLEAN_TYPE:
+      /* Do not mess with boolean types that have foreign convention.  */
+      if (TYPE_PRECISION (type) == 1 && TYPE_SIZE (type) == size_tree)
+       break;
+
+      /* ... fall through ... */
+
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
-    case BOOLEAN_TYPE:
       biased_p = (TREE_CODE (type) == INTEGER_TYPE
                  && TYPE_BIASED_REPRESENTATION_P (type));
 
index 8e770b5f859a3ac116c2aba5723c6d7904175cdb..d643b95224d7fbc63adb1e8f7a3a62b84d92d545 100644 (file)
@@ -56,7 +56,8 @@ package Interfaces.C.Extensions is
 
    --  C bool
 
-   subtype bool is plain_char;
+   type bool is new Boolean;
+   pragma Convention (C, bool);
 
    --  64-bit integer types