public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [Ada] Improve and unify warning machinery for address clauses
@ 2016-06-22 10:06 Arnaud Charlet
  0 siblings, 0 replies; only message in thread
From: Arnaud Charlet @ 2016-06-22 10:06 UTC (permalink / raw)
  To: gcc-patches; +Cc: Eric Botcazou

[-- Attachment #1: Type: text/plain, Size: 3025 bytes --]

This change moves the rest of the warning machinery for address clauses to
Validate_Address_Clauses, ensuring that all the variants are issued from it.
This affects only absolute address clauses in practice, i.e. address clauses
of the form for I'Address use To_Address (16#XXXX_XXXX#) and variants thereof.

This automatically brings a couple of improvements: warnings are more accurate
because they take into account the final alignment set by the back-end and they
catch more cases because the back-end sets the alignment of every single type
and object in the program.  The warning also prints the alignment value now.

The following code gives an example of the warnings:

pragma Unsuppress (Alignment_Check);


     1. with System.Storage_Elements; use System.Storage_Elements;
     2.
     3. package P is
     4.
     5.   I : Integer;
     6.   for I'Address use To_Address (16#7FFF_0001#); -- warning
          |
        >>> warning: specified address for "I" is inconsistent with alignment
        >>> warning: program execution may be erroneous (RM 13.3(27))
        >>> warning: alignment of "I" is 4

     7.
     8.   type Rec is record
     9.     I : Integer;
    10.   end record;
    11.
    12.   R1 : Rec;
    13.   for R1'Address use To_Address (16#7FFF_0001#); -- warning
          |
        >>> warning: specified address for "R1" is inconsistent with alignment
        >>> warning: program execution may be erroneous (RM 13.3(27))
        >>> warning: alignment of "R1" is 4

    14.
    15.   C : constant System.Address := To_Address (16#7FFF_0001#); -- warning
    16.
    17.   R2 : Rec;
    18.   for R2'Address use C;
          |
        >>> warning: specified address for "R2" is inconsistent with alignment
        >>> warning: program execution may be erroneous (RM 13.3(27))
        >>> warning: alignment of "R2" is 4

    19.
    20.   R3 : Rec;
    21.   for R3'Address use To_Address (16#7FFF_0004#); -- no warning
    22.
    23. end P;

 23 lines: No errors, 9 warnings

Tested on x86_64-pc-linux-gnu, committed on trunk

2016-06-22  Eric Botcazou  <ebotcazou@adacore.com>

	* sem_util.ads (Address_Value): Declare new function.
	* sem_util.adb (Address_Value): New function extracted
	unmodified from Apply_Address_Clause_Check, which returns the
	underlying value of the expression of an address clause.
	* checks.adb (Compile_Time_Bad_Alignment): Delete.
	(Apply_Address_Clause_Check): Call Address_Value on
	the expression.  Do not issue the main warning here and
	issue the secondary warning only when the value of the
	expression is not known at compile time.
	* sem_ch13.adb (Address_Clause_Check_Record): Add A component and
	adjust the description.
	(Analyze_Attribute_Definition_Clause): In the case
	of an address, move up the code creating an entry in the table of
	address clauses.  Also create an entry for an absolute address.
	(Validate_Address_Clauses): Issue the warning for absolute
	addresses here too.  Tweak condition associated with overlays
	for consistency.


[-- Attachment #2: difs --]
[-- Type: text/plain, Size: 15914 bytes --]

Index: checks.adb
===================================================================
--- checks.adb	(revision 237687)
+++ checks.adb	(revision 237688)
@@ -638,36 +638,12 @@
       AC   : constant Node_Id    := Address_Clause (E);
       Loc  : constant Source_Ptr := Sloc (AC);
       Typ  : constant Entity_Id  := Etype (E);
-      Aexp : constant Node_Id    := Expression (AC);
 
       Expr : Node_Id;
       --  Address expression (not necessarily the same as Aexp, for example
       --  when Aexp is a reference to a constant, in which case Expr gets
       --  reset to reference the value expression of the constant).
 
-      procedure Compile_Time_Bad_Alignment;
-      --  Post error warnings when alignment is known to be incompatible. Note
-      --  that we do not go as far as inserting a raise of Program_Error since
-      --  this is an erroneous case, and it may happen that we are lucky and an
-      --  underaligned address turns out to be OK after all.
-
-      --------------------------------
-      -- Compile_Time_Bad_Alignment --
-      --------------------------------
-
-      procedure Compile_Time_Bad_Alignment is
-      begin
-         if Address_Clause_Overlay_Warnings then
-            Error_Msg_FE
-              ("?o?specified address for& may be inconsistent with alignment",
-               Aexp, E);
-            Error_Msg_FE
-              ("\?o?program execution may be erroneous (RM 13.3(27))",
-               Aexp, E);
-            Set_Address_Warning_Posted (AC);
-         end if;
-      end Compile_Time_Bad_Alignment;
-
    --  Start of processing for Apply_Address_Clause_Check
 
    begin
@@ -690,44 +666,12 @@
 
       --  Obtain expression from address clause
 
-      Expr := Expression (AC);
+      Expr := Address_Value (Expression (AC));
 
-      --  The following loop digs for the real expression to use in the check
+      --  See if we know that Expr has an acceptable value at compile time. If
+      --  it hasn't or we don't know, we defer issuing the warning until the
+      --  end of the compilation to take into account back end annotations.
 
-      loop
-         --  For constant, get constant expression
-
-         if Is_Entity_Name (Expr)
-           and then Ekind (Entity (Expr)) = E_Constant
-         then
-            Expr := Constant_Value (Entity (Expr));
-
-         --  For unchecked conversion, get result to convert
-
-         elsif Nkind (Expr) = N_Unchecked_Type_Conversion then
-            Expr := Expression (Expr);
-
-         --  For (common case) of To_Address call, get argument
-
-         elsif Nkind (Expr) = N_Function_Call
-           and then Is_Entity_Name (Name (Expr))
-           and then Is_RTE (Entity (Name (Expr)), RE_To_Address)
-         then
-            Expr := First (Parameter_Associations (Expr));
-
-            if Nkind (Expr) = N_Parameter_Association then
-               Expr := Explicit_Actual_Parameter (Expr);
-            end if;
-
-         --  We finally have the real expression
-
-         else
-            exit;
-         end if;
-      end loop;
-
-      --  See if we know that Expr has a bad alignment at compile time
-
       if Compile_Time_Known_Value (Expr)
         and then (Known_Alignment (E) or else Known_Alignment (Typ))
       then
@@ -742,9 +686,7 @@
                AL := Alignment (E);
             end if;
 
-            if Expr_Value (Expr) mod AL /= 0 then
-               Compile_Time_Bad_Alignment;
-            else
+            if Expr_Value (Expr) mod AL = 0 then
                return;
             end if;
          end;
@@ -818,12 +760,11 @@
          Warning_Msg := No_Error_Msg;
          Analyze (First (Actions (N)), Suppress => All_Checks);
 
-         --  If the address clause generated a warning message (for example,
+         --  If the above raise action generated a warning message (for example
          --  from Warn_On_Non_Local_Exception mode with the active restriction
          --  No_Exception_Propagation).
 
          if Warning_Msg /= No_Error_Msg then
-
             --  If the expression has a known at compile time value, then
             --  once we know the alignment of the type, we can check if the
             --  exception will be raised or not, and if not, we don't need
@@ -832,13 +773,13 @@
             if Compile_Time_Known_Value (Expr) then
                Alignment_Warnings.Append
                  ((E => E, A => Expr_Value (Expr), W => Warning_Msg));
-            end if;
+            else
+               --  Add explanation of the warning generated by the check
 
-            --  Add explanation of the warning that is generated by the check
-
-            Error_Msg_N
-              ("\address value may be incompatible with alignment "
-               & "of object?X?", AC);
+               Error_Msg_N
+                 ("\address value may be incompatible with alignment "
+                  & "of object?X?", AC);
+            end if;
          end if;
 
          return;
Index: sem_util.adb
===================================================================
--- sem_util.adb	(revision 237687)
+++ sem_util.adb	(revision 237688)
@@ -286,6 +286,49 @@
       end if;
    end Address_Integer_Convert_OK;
 
+   -------------------
+   -- Address_Value --
+   -------------------
+
+   function Address_Value (N : Node_Id) return Node_Id is
+      Expr : Node_Id := N;
+
+   begin
+      loop
+         --  For constant, get constant expression
+
+         if Is_Entity_Name (Expr)
+           and then Ekind (Entity (Expr)) = E_Constant
+         then
+            Expr := Constant_Value (Entity (Expr));
+
+         --  For unchecked conversion, get result to convert
+
+         elsif Nkind (Expr) = N_Unchecked_Type_Conversion then
+            Expr := Expression (Expr);
+
+         --  For (common case) of To_Address call, get argument
+
+         elsif Nkind (Expr) = N_Function_Call
+           and then Is_Entity_Name (Name (Expr))
+           and then Is_RTE (Entity (Name (Expr)), RE_To_Address)
+         then
+            Expr := First (Parameter_Associations (Expr));
+
+            if Nkind (Expr) = N_Parameter_Association then
+               Expr := Explicit_Actual_Parameter (Expr);
+            end if;
+
+         --  We finally have the real expression
+
+         else
+            exit;
+         end if;
+      end loop;
+
+      return Expr;
+   end Address_Value;
+
    -----------------
    -- Addressable --
    -----------------
Index: sem_util.ads
===================================================================
--- sem_util.ads	(revision 237687)
+++ sem_util.ads	(revision 237688)
@@ -65,6 +65,9 @@
    --  and one of the types is (a descendant of) System.Address (and this type
    --  is private), and the other type is any integer type.
 
+   function Address_Value (N : Node_Id) return Node_Id;
+   --  Return the underlying value of the expression N of an address clause
+
    function Addressable (V : Uint) return Boolean;
    function Addressable (V : Int)  return Boolean;
    pragma Inline (Addressable);
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb	(revision 237687)
+++ sem_ch13.adb	(revision 237688)
@@ -273,9 +273,10 @@
 
    --    for X'Address use Expr
 
-   --  where Expr is of the form Y'Address or recursively is a reference to a
-   --  constant of either of these forms, and X and Y are entities of objects,
-   --  then if Y has a smaller alignment than X, that merits a warning about
+   --  where Expr has a value known at compile time or is of the form Y'Address
+   --  or recursively is a reference to a constant initialized with either of
+   --  these forms, and the value of Expr is not a multiple of X's alignment,
+   --  or if Y has a smaller alignment than X, then that merits a warning about
    --  possible bad alignment. The following table collects address clauses of
    --  this kind. We put these in a table so that they can be checked after the
    --  back end has completed annotation of the alignments of objects, since we
@@ -286,13 +287,16 @@
       --  The address clause
 
       X : Entity_Id;
-      --  The entity of the object overlaying Y
+      --  The entity of the object subject to the address clause
 
+      A : Uint;
+      --  The value of the address in the first case
+
       Y : Entity_Id;
-      --  The entity of the object being overlaid
+      --  The entity of the object being overlaid in the second case
 
       Off : Boolean;
-      --  Whether the address is offset within Y
+      --  Whether the address is offset within Y in the second case
    end record;
 
    package Address_Clause_Checks is new Table.Table (
@@ -4849,6 +4853,40 @@
                         Set_Overlays_Constant (U_Ent);
                      end if;
 
+                     --  If the address clause is of the form:
+
+                     --    for X'Address use Y'Address;
+
+                     --  or
+
+                     --    C : constant Address := Y'Address;
+                     --    ...
+                     --    for X'Address use C;
+
+                     --  then we make an entry in the table to check the size
+                     --  and alignment of the overlaying variable. But we defer
+                     --  this check till after code generation to take full
+                     --  advantage of the annotation done by the back end.
+
+                     --  If the entity has a generic type, the check will be
+                     --  performed in the instance if the actual type justifies
+                     --  it, and we do not insert the clause in the table to
+                     --  prevent spurious warnings.
+
+                     --  Note: we used to test Comes_From_Source and only give
+                     --  this warning for source entities, but we have removed
+                     --  this test. It really seems bogus to generate overlays
+                     --  that would trigger this warning in generated code.
+                     --  Furthermore, by removing the test, we handle the
+                     --  aspect case properly.
+
+                     if Is_Object (O_Ent)
+                       and then not Is_Generic_Type (Etype (U_Ent))
+                       and then Address_Clause_Overlay_Warnings
+                     then
+                        Address_Clause_Checks.Append
+                          ((N, U_Ent, No_Uint, O_Ent, Off));
+                     end if;
                   else
                      --  If this is not an overlay, mark a variable as being
                      --  volatile to prevent unwanted optimizations. It's a
@@ -4861,6 +4899,21 @@
                      if Ekind (U_Ent) = E_Variable then
                         Set_Treat_As_Volatile (U_Ent);
                      end if;
+
+                     --  Make an entry in the table for an absolute address as
+                     --  above to check that the value is compatible with the
+                     --  alignment of the object.
+
+                     declare
+                        Addr : constant Node_Id := Address_Value (Expr);
+                     begin
+                        if Compile_Time_Known_Value (Addr)
+                          and then Address_Clause_Overlay_Warnings
+                        then
+                           Address_Clause_Checks.Append
+                             ((N, U_Ent, Expr_Value (Addr), Empty, False));
+                        end if;
+                     end;
                   end if;
 
                   --  Overlaying controlled objects is erroneous. Emit warning
@@ -4950,41 +5003,6 @@
                   --  the variable, it is somewhere else.
 
                   Kill_Size_Check_Code (U_Ent);
-
-                  --  If the address clause is of the form:
-
-                  --    for Y'Address use X'Address
-
-                  --  or
-
-                  --    Const : constant Address := X'Address;
-                  --    ...
-                  --    for Y'Address use Const;
-
-                  --  then we make an entry in the table for checking the size
-                  --  and alignment of the overlaying variable. We defer this
-                  --  check till after code generation to take full advantage
-                  --  of the annotation done by the back end.
-
-                  --  If the entity has a generic type, the check will be
-                  --  performed in the instance if the actual type justifies
-                  --  it, and we do not insert the clause in the table to
-                  --  prevent spurious warnings.
-
-                  --  Note: we used to test Comes_From_Source and only give
-                  --  this warning for source entities, but we have removed
-                  --  this test. It really seems bogus to generate overlays
-                  --  that would trigger this warning in generated code.
-                  --  Furthermore, by removing the test, we handle the
-                  --  aspect case properly.
-
-                  if Present (O_Ent)
-                    and then Is_Object (O_Ent)
-                    and then not Is_Generic_Type (Etype (U_Ent))
-                    and then Address_Clause_Overlay_Warnings
-                  then
-                     Address_Clause_Checks.Append ((N, U_Ent, O_Ent, Off));
-                  end if;
                end;
 
             --  Not a valid entity for an address clause
@@ -13183,16 +13201,16 @@
             if not Address_Warning_Posted (ACCR.N) then
                Expr := Original_Node (Expression (ACCR.N));
 
-               --  Get alignments
+               --  Get alignments, sizes and offset, if any
 
                X_Alignment := Alignment (ACCR.X);
-               Y_Alignment := Alignment (ACCR.Y);
+               X_Size := Esize (ACCR.X);
 
-               --  Similarly obtain sizes and offset
+               if Present (ACCR.Y) then
+                  Y_Alignment := Alignment (ACCR.Y);
+                  Y_Size := Esize (ACCR.Y);
+               end if;
 
-               X_Size := Esize (ACCR.X);
-               Y_Size := Esize (ACCR.Y);
-
                if ACCR.Off
                  and then Nkind (Expr) = N_Attribute_Reference
                  and then Attribute_Name (Expr) = Name_Address
@@ -13202,9 +13220,27 @@
                   X_Offs := Uint_0;
                end if;
 
+               --  Check for known value not multiple of alignment
+
+               if No (ACCR.Y) then
+                  if not Alignment_Checks_Suppressed (ACCR.X)
+                    and then X_Alignment /= 0
+                    and then ACCR.A mod X_Alignment /= 0
+                  then
+                     Error_Msg_NE
+                       ("??specified address for& is inconsistent with "
+                        & "alignment", ACCR.N, ACCR.X);
+                     Error_Msg_N
+                       ("\??program execution may be erroneous (RM 13.3(27))",
+                        ACCR.N);
+
+                     Error_Msg_Uint_1 := X_Alignment;
+                     Error_Msg_NE ("\??alignment of & is ^", ACCR.N, ACCR.X);
+                  end if;
+
                --  Check for large object overlaying smaller one
 
-               if Y_Size > Uint_0
+               elsif Y_Size > Uint_0
                  and then X_Size > Uint_0
                  and then X_Offs + X_Size > Y_Size
                then
@@ -13232,7 +13268,7 @@
                --  Note: we do not check the alignment if we gave a size
                --  warning, since it would likely be redundant.
 
-               elsif not Alignment_Checks_Suppressed (ACCR.Y)
+               elsif not Alignment_Checks_Suppressed (ACCR.X)
                  and then Y_Alignment /= Uint_0
                  and then
                    (Y_Alignment < X_Alignment

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2016-06-22 10:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-22 10:06 [Ada] Improve and unify warning machinery for address clauses Arnaud Charlet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).