flags.h (warn_padded, [...]): Add global var decls.
authorGreg McGary <gkm@gnu.org>
Fri, 3 Dec 1999 19:02:20 +0000 (19:02 +0000)
committerGeoffrey Keating <geoffk@gcc.gnu.org>
Fri, 3 Dec 1999 19:02:20 +0000 (19:02 +0000)
* flags.h (warn_padded, warn_packed): Add global var decls.
* toplev.c (warn_padded, warn_packed): Add global var defns.
(W_options): Add warnings `-Wpacked' and `-Wpadded'.
* stor-layout.c (layout_record): Add local variable `type'
to hold often-used TREE_TYPE (field).  Add local variable
`unpacked_align' to hold alignment that would be in force
if no `packed' attribute were present.  Warn if `packed' attribute
is unnecessary, or even harmful.  Warn when gcc inserts padding
to satisfy alignment requirements of members.  Use NULL_TREE
when checking whether var_size is set.
* invoke.texi: Document new flags.

Co-Authored-By: Geoff Keating <geoffk@cygnus.com>
From-SVN: r30770

gcc/ChangeLog
gcc/flags.h
gcc/invoke.texi
gcc/stor-layout.c
gcc/toplev.c

index 51af97f3f9a856ba49735f77a0376e84bb439cd2..2fbc0721964bf3b2def003aba20d1ab279ddafad 100644 (file)
@@ -1,3 +1,18 @@
+Thu Dec  2 21:22:45 1999  Greg McGary  <gkm@gnu.org>
+                         Geoffrey Keating  <geoffk@cygnus.com>
+
+       * flags.h (warn_padded, warn_packed): Add global var decls.
+       * toplev.c (warn_padded, warn_packed): Add global var defns.
+       (W_options): Add warnings `-Wpacked' and `-Wpadded'.
+       * stor-layout.c (layout_record): Add local variable `type'
+       to hold often-used TREE_TYPE (field).  Add local variable
+       `unpacked_align' to hold alignment that would be in force
+       if no `packed' attribute were present.  Warn if `packed' attribute
+       is unnecessary, or even harmful.  Warn when gcc inserts padding
+       to satisfy alignment requirements of members.  Use NULL_TREE
+       when checking whether var_size is set.
+       * invoke.texi: Document new flags.
+
 1999-12-03  Nathan Sidwell  <nathan@acm.org>
 
        * frame.c (fde_split): Reimplement to avoid variable sized array.
index 1cca4816808b77e61382677b4f82a4e16fd9af2a..c93784cdee6a5713741e55385ba17f3555ef6370 100644 (file)
@@ -141,6 +141,14 @@ extern unsigned larger_than_size;
 
 extern int warn_aggregate_return;
 
+/* Warn if packed attribute on struct is unnecessary and inefficient.  */
+
+extern int warn_packed;
+
+/* Warn when gcc pads a structure to an alignment boundary.  */
+
+extern int warn_padded;
+
 /* Nonzero if generating code to do profiling.  */
 
 extern int profile_flag;
index 7e76139f320604d08872522821e7aa5df14992a6..ea90467f4747fbd4127f370b65e15a17d53d548b 100644 (file)
@@ -128,7 +128,7 @@ in the following sections.
 -Werror-implicit-function-declaration  -Wfloat-equal -Winline
 -Wlarger-than-@var{len}  -Wlong-long
 -Wmain  -Wmissing-declarations  -Wmissing-noreturn
--Wmultichar  -Wno-import  
+-Wmultichar  -Wno-import  -Wpacked  -Wpadded
 -Wparentheses -Wpointer-arith  -Wredundant-decls
 -Wreturn-type -Wshadow  -Wsign-compare -Wswitch
 -Wtrigraphs -Wundef  -Wuninitialized  -Wunknown-pragmas -Wunreachable-code 
@@ -1430,7 +1430,7 @@ arguments, two, or three arguments of appropriate types.
 Warn if a multicharacter constant (@samp{'FOOF'}) is used.  Usually they
 indicate a typo in the user's code, as they have implementation-defined
 values, and should not be used in portable code.
-  
+
 @item -Wparentheses
 Warn if parentheses are omitted in certain contexts, such
 as when there is an assignment in a context where a truth value
@@ -1798,6 +1798,33 @@ be taken to manually verify functions actually do not ever return before
 adding the @code{noreturn} attribute, otherwise subtle code generation
 bugs could be introduced.
 
+@item -Wpacked
+Warn if a structure is given the packed attribute, but the packed
+attribute has no effect on the layout or size of the structure.  
+Such structures may be mis-aligned for little benefit.  For
+instance, in this code, the variable @code{f.x} in @code{struct bar}
+will be misaligned even though @code{struct bar} does not itself
+have the packed attribute:
+
+@smallexample
+@group
+struct foo @{
+  int x;
+  char a, b, c, d;
+@} __attribute__((packed));
+struct bar @{
+  char z;
+  struct foo f;
+@};
+@end group
+@end smallexample
+
+@item -Wpadded
+Warn if padding is included in a structure, either to align an element
+of the structure or to align the whole structure.  Sometimes when this
+happens it is possible to rearrange the fields of the structure to
+reduce the padding and so make the structure smaller.
+
 @item -Wredundant-decls
 Warn if anything is declared more than once in the same scope, even in
 cases where multiple declaration is valid and changes nothing.
index 1433e8b439d96bfec5123f2bb7cb51ddc88b7ee9..1688fc30a00f0516c3c1ffffbc2a1a7d8beddd5a 100644 (file)
@@ -347,6 +347,7 @@ layout_record (rec)
 {
   register tree field;
   unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
+  unsigned unpacked_align = record_align;
   /* These must be laid out *after* the record is.  */
   tree pending_statics = NULL_TREE;
   /* Record size so far is CONST_SIZE + VAR_SIZE bits,
@@ -354,11 +355,12 @@ layout_record (rec)
      and VAR_SIZE is a tree expression.
      If VAR_SIZE is null, the size is just CONST_SIZE.
      Naturally we try to avoid using VAR_SIZE.  */
- register HOST_WIDE_INT const_size = 0;
 register HOST_WIDE_INT const_size = 0;
   register tree var_size = 0;
   /* Once we start using VAR_SIZE, this is the maximum alignment
      that we know VAR_SIZE has.  */
   register int var_align = BITS_PER_UNIT;
+  int packed_maybe_necessary = 0;
 
 #ifdef STRUCTURE_SIZE_BOUNDARY
   /* Packed structures don't need to have minimum size.  */
@@ -370,6 +372,7 @@ layout_record (rec)
     {
       register int known_align = var_size ? var_align : const_size;
       register int desired_align = 0;
+      tree type = TREE_TYPE (field);
 
       /* If FIELD is static, then treat it like a separate variable,
         not really like a structure field.
@@ -408,12 +411,10 @@ layout_record (rec)
         Otherwise, the alignment of the field within the record
         is meaningless.  */
 
-#ifndef PCC_BITFIELD_TYPE_MATTERS
-      record_align = MAX (record_align, desired_align);
-#else
-      if (PCC_BITFIELD_TYPE_MATTERS && TREE_TYPE (field) != error_mark_node
+#ifdef PCC_BITFIELD_TYPE_MATTERS
+      if (PCC_BITFIELD_TYPE_MATTERS && type != error_mark_node
          && DECL_BIT_FIELD_TYPE (field)
-         && ! integer_zerop (TYPE_SIZE (TREE_TYPE (field))))
+         && ! integer_zerop (TYPE_SIZE (type)))
        {
          /* For these machines, a zero-length field does not
             affect the alignment of the structure as a whole.
@@ -422,23 +423,47 @@ layout_record (rec)
          if (! integer_zerop (DECL_SIZE (field)))
            record_align = MAX ((int)record_align, desired_align);
          else if (! DECL_PACKED (field))
-           desired_align = TYPE_ALIGN (TREE_TYPE (field));
+           desired_align = TYPE_ALIGN (type);
          /* A named bit field of declared type `int'
             forces the entire structure to have `int' alignment.  */
          if (DECL_NAME (field) != 0)
            {
-             int type_align = TYPE_ALIGN (TREE_TYPE (field));
+             int type_align = TYPE_ALIGN (type);
              if (maximum_field_alignment != 0)
                type_align = MIN (type_align, maximum_field_alignment);
              else if (DECL_PACKED (field))
                type_align = MIN (type_align, BITS_PER_UNIT);
 
-             record_align = MAX ((int)record_align, type_align);
+             record_align = MAX ((int) record_align, type_align);
+             if (warn_packed)
+               unpacked_align = MAX (unpacked_align, TYPE_ALIGN (type));
            }
        }
       else
-       record_align = MAX ((int)record_align, desired_align);
 #endif
+       {
+         record_align = MAX ((int) record_align, desired_align);
+         if (warn_packed)
+           unpacked_align = MAX (unpacked_align, TYPE_ALIGN (type));
+       }
+
+      if (warn_packed && DECL_PACKED (field))
+       {
+         if (const_size % TYPE_ALIGN (type) == 0
+             || (var_align % TYPE_ALIGN (type) == 0
+                 && var_size != NULL_TREE))
+           {
+             if (TYPE_ALIGN (type) > desired_align)
+               {
+                 if (STRICT_ALIGNMENT)
+                   warning_with_decl (field, "packed attribute causes inefficient alignment for `%s'");
+                 else
+                   warning_with_decl (field, "packed attribute is unnecessary for `%s'");
+               }
+           }
+         else
+           packed_maybe_necessary = 1;
+       }
 
       /* Does this field automatically have alignment it needs
         by virtue of the fields that precede it and the record's
@@ -446,12 +471,15 @@ layout_record (rec)
 
       if (const_size % desired_align != 0
          || (var_align % desired_align != 0
-             && var_size != 0))
+             && var_size != NULL_TREE))
        {
          /* No, we need to skip space before this field.
             Bump the cumulative size to multiple of field alignment.  */
 
-         if (var_size == 0
+         if (warn_padded)
+           warning_with_decl (field, "padding struct to align `%s'");
+
+         if (var_size == NULL_TREE
              || var_align % desired_align == 0)
            const_size
              = CEIL (const_size, desired_align) * desired_align;
@@ -469,13 +497,13 @@ layout_record (rec)
 #ifdef PCC_BITFIELD_TYPE_MATTERS
       if (PCC_BITFIELD_TYPE_MATTERS
          && TREE_CODE (field) == FIELD_DECL
-         && TREE_TYPE (field) != error_mark_node
+         && type != error_mark_node
          && DECL_BIT_FIELD_TYPE (field)
          && !DECL_PACKED (field)
          && maximum_field_alignment == 0
          && !integer_zerop (DECL_SIZE (field)))
        {
-         int type_align = TYPE_ALIGN (TREE_TYPE (field));
+         int type_align = TYPE_ALIGN (type);
          register tree dsize = DECL_SIZE (field);
          int field_size = TREE_INT_CST_LOW (dsize);
 
@@ -493,12 +521,12 @@ layout_record (rec)
 #ifdef BITFIELD_NBYTES_LIMITED
       if (BITFIELD_NBYTES_LIMITED
          && TREE_CODE (field) == FIELD_DECL
-         && TREE_TYPE (field) != error_mark_node
+         && type != error_mark_node
          && DECL_BIT_FIELD_TYPE (field)
          && !DECL_PACKED (field)
          && !integer_zerop (DECL_SIZE (field)))
        {
-         int type_align = TYPE_ALIGN (TREE_TYPE (field));
+         int type_align = TYPE_ALIGN (type);
          register tree dsize = DECL_SIZE (field);
          int field_size = TREE_INT_CST_LOW (dsize);
 
@@ -556,7 +584,7 @@ layout_record (rec)
          const_size += TREE_INT_CST_LOW (dsize);
        else
          {
-           if (var_size == 0)
+           if (var_size == NULL_TREE)
              var_size = dsize;
            else
              var_size = size_binop (PLUS_EXPR, var_size, dsize);
@@ -568,7 +596,7 @@ layout_record (rec)
      as one expression and store in the record type.
      Round it up to a multiple of the record's alignment.  */
 
-  if (var_size == 0)
+  if (var_size == NULL_TREE)
     {
       TYPE_SIZE (rec) = bitsize_int (const_size, 0L);
     }
@@ -591,13 +619,59 @@ layout_record (rec)
      the size of TYPE_BINFO to make sure that BINFO_SIZE is available.  */
   if (TYPE_BINFO (rec) && TREE_VEC_LENGTH (TYPE_BINFO (rec)) > 6)
     TYPE_BINFO_SIZE (rec) = TYPE_SIZE (rec);
-
+  
+  {
+    tree unpadded_size = TYPE_SIZE (rec);
 #ifdef ROUND_TYPE_SIZE
-  TYPE_SIZE (rec) = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), TYPE_ALIGN (rec));
+    TYPE_SIZE (rec) = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), TYPE_ALIGN (rec));
 #else
-  /* Round the size up to be a multiple of the required alignment */
-  TYPE_SIZE (rec) = round_up (TYPE_SIZE (rec), TYPE_ALIGN (rec));
+    /* Round the size up to be a multiple of the required alignment */
+    TYPE_SIZE (rec) = round_up (TYPE_SIZE (rec), TYPE_ALIGN (rec));
 #endif
+    if (warn_padded && var_size == NULL_TREE
+       && simple_cst_equal (unpadded_size, TYPE_SIZE (rec)) == 0)
+      warning ("padding struct size to alignment boundary");
+  }
+  
+  if (warn_packed && TYPE_PACKED (rec) && !packed_maybe_necessary
+      && var_size == NULL_TREE)
+    {
+      tree unpacked_size;
+      TYPE_PACKED (rec) = 0;
+#ifdef ROUND_TYPE_ALIGN
+      unpacked_align = ROUND_TYPE_ALIGN (rec, TYPE_ALIGN (rec), unpacked_align);
+#else
+      unpacked_align = MAX (TYPE_ALIGN (rec), unpacked_align);
+#endif
+#ifdef ROUND_TYPE_SIZE
+      unpacked_size = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), unpacked_align);
+#else
+      unpacked_size = round_up (TYPE_SIZE (rec), unpacked_align);
+#endif
+      if (simple_cst_equal (unpacked_size, TYPE_SIZE (rec)))
+       {
+         if (TYPE_NAME (rec))
+           {
+             char *name;
+             if (TREE_CODE (TYPE_NAME (rec)) == IDENTIFIER_NODE)
+               name = IDENTIFIER_POINTER (TYPE_NAME (rec));
+             else
+               name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (rec)));
+             if (STRICT_ALIGNMENT)
+               warning ("packed attribute causes inefficient alignment for `%s'", name);
+             else
+               warning ("packed attribute is unnecessary for `%s'", name);
+           }
+         else
+           {
+             if (STRICT_ALIGNMENT)
+               warning ("packed attribute causes inefficient alignment");
+             else
+               warning ("packed attribute is unnecessary");
+           }
+       }
+      TYPE_PACKED (rec) = 1;
+    }
 
   return pending_statics;
 }
index 06789158d9e66d7fabf83cbda571700e6300199c..70ea2a15945b81841d1a6b13f482e5801e8c6ba2 100644 (file)
@@ -1258,6 +1258,14 @@ int warn_inline;
 
 int warn_aggregate_return;
 
+/* Warn if packed attribute on struct is unnecessary and inefficient.  */
+
+int warn_packed;
+
+/* Warn when gcc pads a structure to an alignment boundary.  */
+
+int warn_padded;
+
 /* Likewise for -W.  */
 
 lang_independent_options W_options[] =
@@ -1276,7 +1284,11 @@ lang_independent_options W_options[] =
   {"uninitialized", &warn_uninitialized, 1,
    "Warn about unitialized automatic variables"},
   {"inline", &warn_inline, 1,
-   "Warn when an inlined function cannot be inlined"}
+   "Warn when an inlined function cannot be inlined"},
+  {"packed", &warn_packed, 1,
+   "Warn when the packed attribute has no effect on struct layout"},
+  {"padded", &warn_padded, 1,
+   "Warn when padding is required to align struct members"}
 };
 \f
 /* Output files for assembler code (real compiler output)