c-pragma.c (handle_pragma_pack): Initialize align to -1.
authorMike Coleman <mcoleman2@kc.rr.com>
Sat, 28 Oct 2000 00:04:11 +0000 (00:04 +0000)
committerZack Weinberg <zack@gcc.gnu.org>
Sat, 28 Oct 2000 00:04:11 +0000 (00:04 +0000)
2000-10-21  Mike Coleman  <mcoleman2@kc.rr.com>

* c-pragma.c (handle_pragma_pack): Initialize align to -1.
Improve error messages.  Correct parsing of
#pragma pack(pop [,id]).  Do not check the user-supplied
alignment if we're popping.

* gcc.dg/pack-test-1.c: New test case.
* gcc.dg/pack-test-2.c: New test case.
* gcc.dg/pack-test-1.h: New file.

From-SVN: r37095

gcc/ChangeLog
gcc/c-pragma.c
gcc/testsuite/gcc.dg/pack-test-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pack-test-1.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/pack-test-2.c [new file with mode: 0644]

index d23a4e2cf26b96970c8a7e13ef8913cc1775d867..ff659375336bb44bf67f0221bdbd0998bdb705a2 100644 (file)
@@ -1,3 +1,14 @@
+2000-10-21  Mike Coleman  <mcoleman2@kc.rr.com>
+
+       * c-pragma.c (handle_pragma_pack): Initialize align to -1.
+       Improve error messages.  Correct parsing of 
+       #pragma pack(pop [,id]).  Do not check the user-supplied
+       alignment if we're popping.
+
+       * gcc.dg/pack-test-1.c: New test case.
+       * gcc.dg/pack-test-2.c: New test case.
+       * gcc.dg/pack-test-1.h: New file.
+
 2000-10-27  Neil Booth  <neilb@earthling.net>
 
        * cpp.texi: Update.
index 8503f3cacca41362ea1cb52f1b6e9b13f6220964..a9f41f91aa6e27c8822f48647d72a0e1c986734a 100644 (file)
@@ -60,8 +60,8 @@ typedef struct align_stack
 
 static struct align_stack * alignment_stack = NULL;
 
-/* If we have a "global" #pragma pack(<n>) if effect when the first
-   #pragma push(pack,<n>) is encountered, this stores the the value of 
+/* If we have a "global" #pragma pack(<n>) in effect when the first
+   #pragma pack(push,<n>) is encountered, this stores the value of 
    maximum_field_alignment in effect.  When the final pop_alignment() 
    happens, we restore the value to this, not to a value of 0 for
    maximum_field_alignment.  Value is in bits. */
@@ -186,7 +186,7 @@ handle_pragma_pack (dummy)
      cpp_reader *dummy ATTRIBUTE_UNUSED;
 {
   tree x, id = 0;
-  int align;
+  int align = -1;
   enum cpp_ttype token;
   enum { set, push, pop } action;
 
@@ -208,6 +208,12 @@ handle_pragma_pack (dummy)
     }
   else if (token == CPP_NAME)
     {
+#define BAD_ACTION do { if (action == push) \
+         BAD ("malformed '#pragma pack(push[, id], <n>)' - ignored"); \
+       else \
+         BAD ("malformed '#pragma pack(pop[, id])' - ignored"); \
+       } while (0)
+
       const char *op = IDENTIFIER_POINTER (x);
       if (!strcmp (op, "push"))
        action = push;
@@ -216,25 +222,36 @@ handle_pragma_pack (dummy)
       else
        BAD2 ("unknown action '%s' for '#pragma pack' - ignored", op);
 
-      if (c_lex (&x) != CPP_COMMA)
-       BAD2 ("malformed '#pragma pack(%s[, id], <n>)' - ignored", op);
-
       token = c_lex (&x);
-      if (token == CPP_NAME)
+      if (token != CPP_COMMA && action == push)
+       BAD_ACTION;
+
+      if (token == CPP_COMMA)
        {
-         id = x;
-         if (c_lex (&x) != CPP_COMMA)
-           BAD2 ("malformed '#pragma pack(%s[, id], <n>)' - ignored", op);
          token = c_lex (&x);
-       }
+         if (token == CPP_NAME)
+           {
+             id = x;
+             if (action == push && c_lex (&x) != CPP_COMMA)
+               BAD_ACTION;
+             token = c_lex (&x);
+           }
 
-      if (token == CPP_NUMBER)
-       align = TREE_INT_CST_LOW (x);
-      else
-       BAD2 ("malformed '#pragma pack(%s[, id], <n>)' - ignored", op);
+         if (action == push)
+           {
+             if (token == CPP_NUMBER)
+               {
+                 align = TREE_INT_CST_LOW (x);
+                 token = c_lex (&x);
+               }
+             else
+               BAD_ACTION;
+           }
+       }
 
-      if (c_lex (&x) != CPP_CLOSE_PAREN)
-       BAD ("malformed '#pragma pack' - ignored");
+      if (token != CPP_CLOSE_PAREN)
+       BAD_ACTION;
+#undef BAD_ACTION
     }
   else
     BAD ("malformed '#pragma pack' - ignored");
@@ -242,19 +259,20 @@ handle_pragma_pack (dummy)
   if (c_lex (&x) != CPP_EOF)
     warning ("junk at end of '#pragma pack'");
 
-  switch (align)
-    {
-    case 0:
-    case 1:
-    case 2:
-    case 4:
-    case 8:
-    case 16:
-      align *= BITS_PER_UNIT;
-      break;
-    default:
-      BAD2 ("alignment must be a small power of two, not %d", align);
-    }
+  if (action != pop)
+    switch (align)
+      {
+      case 0:
+      case 1:
+      case 2:
+      case 4:
+      case 8:
+      case 16:
+       align *= BITS_PER_UNIT;
+       break;
+      default:
+       BAD2 ("alignment must be a small power of two, not %d", align);
+      }
 
   switch (action)
     {
diff --git a/gcc/testsuite/gcc.dg/pack-test-1.c b/gcc/testsuite/gcc.dg/pack-test-1.c
new file mode 100644 (file)
index 0000000..1ceee99
--- /dev/null
@@ -0,0 +1,146 @@
+/* Test semantics of #pragma pack.
+   Contributed by Mike Coleman <mcoleman2@kc.rr.com> */
+
+/* { dg-do compile { target *-*-linux* *-*-cygwin* } } */
+
+/* We only test the alignment of char, short, and int, because these
+   are the only ones that are pretty certain to be the same across
+   platforms (and maybe not even those).  Mainly we're just testing
+   whether pushing and popping seem to be working correctly, and
+   verifying the (alignment == 1) case, which is really the only
+   reason anyone would use this pragma anyway.
+*/
+
+#include <stddef.h>
+
+/* gap in bytes between fields a and b in struct s */
+#define gap(s, a, b) (offsetof(struct s, a) - offsetof(struct s, b))
+/* generalized compile-time test expression */
+#define test(n, expr) int test_##n [(expr) ? 1 : -1]
+/* test a gap */
+#define testgap(n, a, b, val) test(n, gap(SNAME, a, b) == val)
+
+#define SNAME s0
+#include "pack-test-1.h"
+
+/* Save original alignment values.  Can't use const ints because they
+   won't be expanded and we'll get bogus errors about variable length
+   arrays.  (Possible bug in C front end?)  Use s0, not SNAME, so these
+   won't change later.  */
+#define al1 gap(s0, f1, f0)
+#define al2 gap(s0, f2, f1)
+#define al3 gap(s0, f3, f2)
+#define al4 gap(s0, f4, f3)
+#define al5 gap(s0, f5, f4)
+#define al6 gap(s0, f6, f5)
+#define al7 gap(s0, f7, f6)
+
+#undef SNAME
+#define SNAME s1
+#pragma pack(push, p1, 1)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, sizeof(char));
+  testgap(1, f3, f2, sizeof(short));
+  testgap(2, f5, f4, sizeof(int));
+}
+
+#undef SNAME
+#define SNAME s2
+#pragma pack(push, p2, 2)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, sizeof(short));
+  testgap(1, f3, f2, sizeof(short));
+  testgap(2, f5, f4, sizeof(int));
+}
+
+#undef SNAME
+#define SNAME s3
+#pragma pack(push, p3, 4)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, sizeof(int));
+  testgap(1, f3, f2, sizeof(int));
+  testgap(2, f5, f4, sizeof(int));
+}
+
+#undef SNAME
+#define SNAME s4
+#pragma pack(pop)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, sizeof(short));
+  testgap(1, f3, f2, sizeof(short));
+  testgap(2, f5, f4, sizeof(int));
+}
+
+#undef SNAME
+#define SNAME s5
+#pragma pack(pop, p2)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, sizeof(char));
+  testgap(1, f3, f2, sizeof(short));
+  testgap(2, f5, f4, sizeof(int));
+}
+
+#undef SNAME
+#define SNAME s6
+#pragma pack(pop, p1)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, al1);
+  testgap(1, f3, f2, al3);
+  testgap(2, f5, f4, al5);
+}
+
+#undef SNAME
+#define SNAME s7
+#pragma pack(1)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, sizeof(char));
+  testgap(1, f3, f2, sizeof(short));
+  testgap(2, f5, f4, sizeof(int));
+}
+
+#undef SNAME
+#define SNAME s8
+#pragma pack(push, p2, 2)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, sizeof(short));
+  testgap(1, f3, f2, sizeof(short));
+  testgap(2, f5, f4, sizeof(int));
+}
+
+#undef SNAME
+#define SNAME s9
+#pragma pack(pop)
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, sizeof(char));
+  testgap(1, f3, f2, sizeof(short));
+  testgap(2, f5, f4, sizeof(int));
+}
+
+#undef SNAME
+#define SNAME s10
+#pragma pack()
+#include "pack-test-1.h"
+
+void SNAME() {
+  testgap(0, f1, f0, al1);
+  testgap(1, f3, f2, al3);
+  testgap(2, f5, f4, al5);
+}
diff --git a/gcc/testsuite/gcc.dg/pack-test-1.h b/gcc/testsuite/gcc.dg/pack-test-1.h
new file mode 100644 (file)
index 0000000..f4889fa
--- /dev/null
@@ -0,0 +1,12 @@
+/* Helper file, included repeatedly by pack-test-1.c.  */
+
+struct SNAME {
+  char f0;
+  double f1;
+  short f2;
+  double f3;
+  int f4;
+  double f5;
+  double f6;
+  double f7;
+};
diff --git a/gcc/testsuite/gcc.dg/pack-test-2.c b/gcc/testsuite/gcc.dg/pack-test-2.c
new file mode 100644 (file)
index 0000000..65960ed
--- /dev/null
@@ -0,0 +1,23 @@
+/* Tests for syntax checking of #pragma pack.
+   Contributed by Mike Coleman <mcoleman2@kc.rr.com> */
+
+/* { dg-do compile { target *-*-linux* *-*-cygwin* } } */
+
+#pragma pack(push)              /* { dg-error "malformed" } */
+#pragma pack(pop)               /* { dg-error "without matching" } */
+
+#pragma pack(push, foo, 1)
+#pragma pack(pop, foo, 1)       /* { dg-error "malformed" } (/
+#pragma pack(pop)               /* reset */
+
+#pragma pack(push, foo, 1)
+#pragma pack(pop, bar)          /* { dg-error "without matching" } */
+#pragma pack(pop)               /* reset */
+
+#pragma pack(push, foo, 1)
+#pragma pack(pop)
+#pragma pack(pop, foo)          /* { dg-error "without matching" } */
+
+#pragma pack(push, foo, 3)      /* { dg-error "small power of two" } */
+
+extern int blah;       /* prevent "ISO C forbids an empty source file" */