This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to implement C99 _Bool
- To: <gcc-patches at gcc dot gnu dot org>
- Subject: Patch to implement C99 _Bool
- From: "Joseph S. Myers" <jsm28 at cam dot ac dot uk>
- Date: Wed, 1 Nov 2000 02:18:07 +0000 (GMT)
This patch implements C99's _Bool type in GCC.
Some notes:
(a) It seems to work, judging by the testcase included, but there may
well be some bugs.
(b) Hopefully debug information output will "just work" (using
existing support for output of information for boolean types).
(c) _Bool is always the same size as char, though it can never (except
through reading uninitialized memory or memory initialized with
another type, which is undefined behavior anyway) have any value other
than 0 or 1. This is binary incompatible with the existing (broken -
based on an old draft) stdbool.h, but hopefully no-one was using that,
and should be compatible with the new C++ ABI.
(d) The code for handling ++ on boolean types can be shared with C++,
so that in the C++ front end is moved by this patch to a function in
c-common.c.
Bootstrapped with no regressions on i686-pc-linux-gnu. OK to commit?
gcc/ChangeLog:
2000-11-01 Joseph S. Myers <jsm28@cam.ac.uk>
* c-common.c (boolean_increment): New function.
* c-common.h (enum c_tree_index): Add CTI_C_BOOL_TYPE,
CTI_C_BOOL_TRUE and CTI_C_BOOL_FALSE.
(c_bool_type_node, c_bool_true_node, c_bool_false_node): Define.
(boolean_increment): Declare.
* c-convert.c (convert): Allow for BOOLEAN_TYPE.
* c-decl.c (init_decl_processing): Create boolean nodes.
(finish_struct): Allow for _Bool bitfields.
* c-parse.in (reswords): Add _Bool.
(rid_to_yy): Allow for RID_BOOL.
* c-typeck.c (default_conversion): Make booleans promote to int.
(convert_arguments, build_unary_op, build_modify_expr,
convert_for_assignment): Allow for booleans.
* ginclude/stdbool.h: Make conforming to C99.
gcc/cp/ChangeLog:
2000-11-01 Joseph S. Myers <jsm28@cam.ac.uk>
* typeck.c (build_unary_op): Use boolean_increment from
c-common.c, moving the relevant code there.
gcc/testsuite/ChangeLog:
2000-11-01 Joseph S. Myers <jsm28@cam.ac.uk>
* gcc.dg/c99-bool-1.c: New test.
--- c-common.c.orig Tue Oct 24 19:38:02 2000
+++ c-common.c Tue Oct 31 21:28:54 2000
@@ -6084,3 +6084,44 @@ c_expand_builtin_printf (arglist, target
(ignore ? const0_rtx : target),
tmode, modifier);
}
+
+
+/* Given a boolean expression ARG, return a tree representing an increment
+ or decrement (as indicated by CODE) of ARG. The front end must check for
+ invalid cases (e.g., decrement in C++). */
+tree
+boolean_increment (code, arg)
+ enum tree_code code;
+ tree arg;
+{
+ tree val;
+ tree true_res = (c_language == clk_cplusplus
+ ? boolean_true_node
+ : c_bool_true_node);
+ arg = stabilize_reference (arg);
+ switch (code)
+ {
+ case PREINCREMENT_EXPR:
+ val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+ break;
+ case POSTINCREMENT_EXPR:
+ val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+ arg = save_expr (arg);
+ val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+ val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+ break;
+ case PREDECREMENT_EXPR:
+ val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+ break;
+ case POSTDECREMENT_EXPR:
+ val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+ arg = save_expr (arg);
+ val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+ val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+ break;
+ default:
+ abort ();
+ }
+ TREE_SIDE_EFFECTS (val) = 1;
+ return val;
+}
--- c-common.h.orig Wed Oct 18 21:27:38 2000
+++ c-common.h Tue Oct 31 21:12:53 2000
@@ -130,9 +130,14 @@ enum c_tree_index
CTI_STRING_TYPE,
CTI_CONST_STRING_TYPE,
+ /* Type for boolean expressions (bool in C++, int in C). */
CTI_BOOLEAN_TYPE,
CTI_BOOLEAN_TRUE,
CTI_BOOLEAN_FALSE,
+ /* C99's _Bool type. */
+ CTI_C_BOOL_TYPE,
+ CTI_C_BOOL_TRUE,
+ CTI_C_BOOL_FALSE,
CTI_DEFAULT_FUNCTION_TYPE,
CTI_VOID_LIST,
@@ -172,6 +177,10 @@ enum c_tree_index
#define boolean_true_node c_global_trees[CTI_BOOLEAN_TRUE]
#define boolean_false_node c_global_trees[CTI_BOOLEAN_FALSE]
+#define c_bool_type_node c_global_trees[CTI_C_BOOL_TYPE]
+#define c_bool_true_node c_global_trees[CTI_C_BOOL_TRUE]
+#define c_bool_false_node c_global_trees[CTI_C_BOOL_FALSE]
+
#define char_array_type_node c_global_trees[CTI_CHAR_ARRAY_TYPE]
#define wchar_array_type_node c_global_trees[CTI_WCHAR_ARRAY_TYPE]
#define int_array_type_node c_global_trees[CTI_INT_ARRAY_TYPE]
@@ -690,6 +699,10 @@ extern tree common_type
extern tree expand_tree_builtin PARAMS ((tree, tree, tree));
extern tree decl_constant_value PARAMS ((tree));
+
+/* Handle increment and decrement of boolean types. */
+extern tree boolean_increment PARAMS ((enum tree_code,
+ tree));
/* Hook currently used only by the C++ front end to reset internal state
after entering or leaving a header file. */
--- c-convert.c.orig Sat Jun 24 19:26:42 2000
+++ c-convert.c Tue Oct 31 21:34:56 2000
@@ -88,6 +88,8 @@ convert (type, expr)
#endif
if (code == INTEGER_TYPE || code == ENUMERAL_TYPE)
return fold (convert_to_integer (type, e));
+ if (code == BOOLEAN_TYPE)
+ return fold (build1 (NOP_EXPR, type, truthvalue_conversion (expr)));
if (code == POINTER_TYPE || code == REFERENCE_TYPE)
return fold (convert_to_pointer (type, e));
if (code == REAL_TYPE)
--- c-decl.c.orig Sun Oct 29 10:45:46 2000
+++ c-decl.c Tue Oct 31 23:55:08 2000
@@ -3104,6 +3104,19 @@ init_decl_processing ()
boolean_true_node = integer_one_node;
boolean_false_node = integer_zero_node;
+ /* With GCC, C99's _Bool is always of size 1. */
+ c_bool_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
+ TREE_SET_CODE (c_bool_type_node, BOOLEAN_TYPE);
+ TYPE_MAX_VALUE (c_bool_type_node) = build_int_2 (1, 0);
+ TREE_TYPE (TYPE_MAX_VALUE (c_bool_type_node)) = c_bool_type_node;
+ TYPE_PRECISION (c_bool_type_node) = 1;
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("_Bool"),
+ c_bool_type_node));
+ c_bool_false_node = build_int_2 (0, 0);
+ TREE_TYPE (c_bool_false_node) = c_bool_type_node;
+ c_bool_true_node = build_int_2 (1, 0);
+ TREE_TYPE (c_bool_true_node) = c_bool_type_node;
+
string_type_node = build_pointer_type (char_type_node);
const_string_type_node
= build_pointer_type (build_type_variant (char_type_node, 1, 0));
@@ -5422,6 +5435,7 @@ finish_struct (t, fieldlist, attributes)
/* Detect invalid bit-field type. */
if (DECL_INITIAL (x)
&& TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (x)) != BOOLEAN_TYPE
&& TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE)
{
error_with_decl (x, "bit-field `%s' has invalid type");
@@ -5431,6 +5445,7 @@ finish_struct (t, fieldlist, attributes)
if (DECL_INITIAL (x) && pedantic
&& TYPE_MAIN_VARIANT (TREE_TYPE (x)) != integer_type_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (x)) != unsigned_type_node
+ && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != c_bool_type_node
/* Accept an enum that's equivalent to int or unsigned int. */
&& !(TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
&& (TYPE_PRECISION (TREE_TYPE (x))
@@ -5441,10 +5456,14 @@ finish_struct (t, fieldlist, attributes)
field widths. */
if (DECL_INITIAL (x))
{
+ int max_width;
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (x)) == c_bool_type_node)
+ max_width = CHAR_TYPE_SIZE;
+ else
+ max_width = TYPE_PRECISION (TREE_TYPE (x));
if (tree_int_cst_sgn (DECL_INITIAL (x)) < 0)
error_with_decl (x, "negative width in bit-field `%s'");
- else if (0 < compare_tree_int (DECL_INITIAL (x),
- TYPE_PRECISION (TREE_TYPE (x))))
+ else if (0 < compare_tree_int (DECL_INITIAL (x), max_width))
pedwarn_with_decl (x, "width of `%s' exceeds its type");
else if (integer_zerop (DECL_INITIAL (x)) && DECL_NAME (x) != 0)
error_with_decl (x, "zero width for bit-field `%s'");
--- c-parse.in.orig Sun Sep 17 15:40:10 2000
+++ c-parse.in Tue Oct 31 23:08:57 2000
@@ -2776,6 +2776,7 @@ struct resword
static const struct resword reswords[] =
{
+ { "_Bool", RID_BOOL, 0 },
{ "_Complex", RID_COMPLEX, 0 },
{ "__alignof", RID_ALIGNOF, 0 },
{ "__alignof__", RID_ALIGNOF, 0 },
@@ -2951,7 +2952,7 @@ static const short rid_to_yy[RID_MAX] =
/* RID_PTRVALUE */ PTR_VALUE,
/* C++ */
- /* RID_BOOL */ 0,
+ /* RID_BOOL */ TYPESPEC,
/* RID_WCHAR */ 0,
/* RID_CLASS */ 0,
/* RID_PUBLIC */ 0,
--- c-typeck.c.orig Tue Oct 31 20:35:11 2000
+++ c-typeck.c Tue Oct 31 22:06:06 2000
@@ -947,6 +947,9 @@ default_conversion (exp)
return convert (integer_type_node, exp);
}
+ if (code == BOOLEAN_TYPE)
+ return convert (integer_type_node, exp);
+
if (flag_traditional && !flag_allow_single_precision
&& TYPE_MAIN_VARIANT (type) == float_type_node)
return convert (double_type_node, exp);
@@ -1732,7 +1735,8 @@ convert_arguments (typelist, values, nam
if (PROMOTE_PROTOTYPES
&& (TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
+ || TREE_CODE (type) == ENUMERAL_TYPE
+ || TREE_CODE (type) == BOOLEAN_TYPE)
&& (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
parmval = default_conversion (parmval);
}
@@ -2789,7 +2793,7 @@ build_unary_op (code, xarg, noconvert)
if (typecode == ERROR_MARK)
return error_mark_node;
- if (typecode == ENUMERAL_TYPE)
+ if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
typecode = INTEGER_TYPE;
switch (code)
@@ -2984,18 +2988,23 @@ build_unary_op (code, xarg, noconvert)
else
{
tree incremented, modify, value;
- arg = stabilize_reference (arg);
- if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
- value = arg;
+ if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
+ value = boolean_increment (code, arg);
else
- value = save_expr (arg);
- incremented = build (((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? PLUS_EXPR : MINUS_EXPR),
- argtype, value, inc);
- TREE_SIDE_EFFECTS (incremented) = 1;
- modify = build_modify_expr (arg, NOP_EXPR, incremented);
- value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+ {
+ arg = stabilize_reference (arg);
+ if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
+ value = arg;
+ else
+ value = save_expr (arg);
+ incremented = build (((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? PLUS_EXPR : MINUS_EXPR),
+ argtype, value, inc);
+ TREE_SIDE_EFFECTS (incremented) = 1;
+ modify = build_modify_expr (arg, NOP_EXPR, incremented);
+ value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+ }
TREE_USED (value) = 1;
return value;
}
@@ -3020,7 +3029,10 @@ build_unary_op (code, xarg, noconvert)
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"));
- val = build (code, TREE_TYPE (arg), arg, inc);
+ if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
+ val = boolean_increment (code, arg);
+ else
+ val = build (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
val = convert (result_type, val);
if (TREE_CODE (val) != code)
@@ -3968,6 +3980,7 @@ build_modify_expr (lhs, modifycode, rhs)
if (TREE_CODE (lhs) == COMPONENT_REF
&& (TREE_CODE (lhstype) == INTEGER_TYPE
+ || TREE_CODE (lhstype) == BOOLEAN_TYPE
|| TREE_CODE (lhstype) == REAL_TYPE
|| TREE_CODE (lhstype) == ENUMERAL_TYPE))
lhstype = TREE_TYPE (get_unwidened (lhs, 0));
@@ -4083,9 +4096,11 @@ convert_for_assignment (type, rhs, errty
}
/* Arithmetic types all interconvert, and enum is treated like int. */
else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
- || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE)
+ || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
+ || codel == BOOLEAN_TYPE)
&& (coder == INTEGER_TYPE || coder == REAL_TYPE
- || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE))
+ || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
+ || coder == BOOLEAN_TYPE))
return convert_and_check (type, rhs);
/* Conversion to a transparent union from its member types.
@@ -4265,6 +4280,8 @@ convert_for_assignment (type, rhs, errty
errtype, funname, parmnum);
return convert (type, rhs);
}
+ else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
+ return convert (type, rhs);
if (!errtype)
{
--- ginclude/stdbool.h.orig Tue Jan 4 10:12:22 2000
+++ ginclude/stdbool.h Tue Oct 31 22:49:53 2000
@@ -32,20 +32,10 @@
#define _STDBOOL_H
#ifndef __cplusplus
-/* The type `_Bool' must promote to `int' or `unsigned int'. The constants
- `true' and `false' must have the value 0 and 1 respectively. */
-typedef enum
- {
- false = 0,
- true = 1
- } _Bool;
-/* The names `true' and `false' must also be made available as macros. */
-#define false false
-#define true true
-
-/* The macro `bool', which may be undefined, expands to _Bool. */
-#define bool _Bool
+#define bool _Bool
+#define true 1
+#define false 0
#else /* __cplusplus */
--- cp/typeck.c.orig Sun Oct 22 22:34:59 2000
+++ cp/typeck.c Tue Oct 31 22:07:11 2000
@@ -4580,18 +4580,7 @@ build_unary_op (code, xarg, noconvert)
my patch to expand_increment. (jason) */
val = build (code, TREE_TYPE (arg), arg, inc);
#else
- if (code == POSTINCREMENT_EXPR)
- {
- arg = stabilize_reference (arg);
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
- boolean_true_node);
- arg = save_expr (arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
- }
- else
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
- boolean_true_node);
+ val = boolean_increment (code, arg);
#endif
}
else
--- testsuite/gcc.dg/c99-bool-1.c.orig Fri Sep 11 11:31:59 1998
+++ testsuite/gcc.dg/c99-bool-1.c Wed Nov 1 01:39:00 2000
@@ -0,0 +1,262 @@
+/* Test for _Bool and <stdbool.h> in C99. */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do run } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+/* _Bool must be a builtin type. */
+
+_Bool foo;
+
+#include <stdbool.h>
+
+/* Three macros must be integer constant expressions suitable for use
+ in #if.
+*/
+
+#if !defined(true) || (true != 1)
+#error "bad stdbool true" /* { dg-bogus "#error" "bad stdbool.h" } */
+#endif
+
+#if !defined(false) || (false != 0)
+#error "bad stdbool false" /* { dg-bogus "#error" "bad stdbool.h" } */
+#endif
+
+#if !defined(__bool_true_false_are_defined) || (__bool_true_false_are_defined != 1)
+#error "bad stdbool __bool_true_false_are_defined" /* { dg-bogus "#error" "bad stdbool.h" } */
+#endif
+
+int a = true;
+int b = false;
+int c = __bool_true_false_are_defined;
+
+struct foo
+{
+ _Bool a : 1;
+ _Bool b : 2;
+ _Bool c : 7;
+} sf;
+
+#define str(x) xstr(x)
+#define xstr(x) #x
+
+
+extern void abort (void);
+extern void exit (int);
+extern int strcmp (const char *, const char *);
+
+int
+main (void)
+{
+ /* The macro `bool' must expand to _Bool. */
+ const char *t = str (bool);
+ _Bool u, v;
+ if (strcmp (t, "_Bool"))
+ abort ();
+ if (a != 1 || b != 0 || c != 1)
+ abort ();
+ /* Casts to _Bool have a specified behaviour. */
+ if ((int)(_Bool)2 != 1)
+ abort ();
+ if ((int)(_Bool)0.2 != 1)
+ abort ();
+ /* Pointers may be assigned to _Bool. */
+ if ((u = t) != 1)
+ abort ();
+ /* _Bool may be used to subscript arrays. */
+ u = 0;
+ if (t[u] != '_')
+ abort ();
+ if (u[t] != '_')
+ abort ();
+ u = 1;
+ if (t[u] != 'B')
+ abort ();
+ if (u[t] != 'B')
+ abort ();
+ /* Test increment and decrement operators. */
+ u = 0;
+ if (u++ != 0)
+ abort ();
+ if (u != 1)
+ abort ();
+ if (u++ != 1)
+ abort ();
+ if (u != 1)
+ abort ();
+ u = 0;
+ if (++u != 1)
+ abort ();
+ if (u != 1)
+ abort ();
+ if (++u != 1)
+ abort ();
+ if (u != 1)
+ abort ();
+ u = 0;
+ if (u-- != 0)
+ abort ();
+ if (u != 1)
+ abort ();
+ if (u-- != 1)
+ abort ();
+ if (u != 0)
+ abort ();
+ u = 0;
+ if (--u != 1)
+ abort ();
+ if (u != 1)
+ abort ();
+ if (--u != 0)
+ abort ();
+ if (u != 0)
+ abort ();
+ /* Test unary + - ~ !. */
+ u = 0;
+ if (+u != 0)
+ abort ();
+ if (-u != 0)
+ abort ();
+ u = 1;
+ if (+u != 1)
+ abort ();
+ if (-u != -1)
+ abort ();
+ u = 2;
+ if (+u != 1)
+ abort ();
+ if (-u != -1)
+ abort ();
+ u = 0;
+ if (~u != ~(int)0)
+ abort ();
+ u = 1;
+ if (~u != ~(int)1)
+ abort ();
+ u = 0;
+ if (!u != 1)
+ abort ();
+ u = 1;
+ if (!u != 0)
+ abort ();
+ /* Test arithmetic * / % + - (which all apply promotions). */
+ u = 0;
+ if (u + 2 != 2)
+ abort ();
+ u = 1;
+ if (u * 4 != 4)
+ abort ();
+ if (u % 3 != 1)
+ abort ();
+ if (u / 1 != 1)
+ abort ();
+ if (4 / u != 4)
+ abort ();
+ if (u - 7 != -6)
+ abort ();
+ /* Test bitwise shift << >>. */
+ u = 1;
+ if (u << 1 != 2)
+ abort ();
+ if (u >> 1 != 0)
+ abort ();
+ /* Test relational and equality operators < > <= >= == !=. */
+ u = 0;
+ v = 0;
+ if (u < v || u > v || !(u <= v) || !(u >= v) || !(u == v) || u != v)
+ abort ();
+ u = 0;
+ v = 1;
+ if (!(u < v) || u > v || !(u <= v) || u >= v || u == v || !(u != v))
+ abort ();
+ /* Test bitwise operators & ^ |. */
+ u = 1;
+ if ((u | 2) != 3)
+ abort ();
+ if ((u ^ 3) != 2)
+ abort ();
+ if ((u & 1) != 1)
+ abort ();
+ if ((u & 0) != 0)
+ abort ();
+ /* Test logical && ||. */
+ u = 0;
+ v = 1;
+ if (!(u || v))
+ abort ();
+ if (!(v || u))
+ abort ();
+ if (u && v)
+ abort ();
+ if (v && u)
+ abort ();
+ u = 1;
+ v = 1;
+ if (!(u && v))
+ abort ();
+ /* Test conditional ? :. */
+ u = 0;
+ if ((u ? 4 : 7) != 7)
+ abort ();
+ u = 1;
+ v = 0;
+ if ((1 ? u : v) != 1)
+ abort ();
+ if ((1 ? 4 : u) != 4)
+ abort ();
+ /* Test assignment operators = *= /= %= += -= <<= >>= &= ^= |=. */
+ if ((u = 2) != 1)
+ abort ();
+ if (u != 1)
+ abort ();
+ if ((u *= -1) != 1)
+ abort ();
+ if (u != 1)
+ abort ();
+ if ((u /= 2) != 0)
+ abort ();
+ if ((u += 3) != 1)
+ abort ();
+ if ((u -= 1) != 0)
+ abort ();
+ u = 1;
+ if ((u <<= 4) != 1)
+ abort ();
+ if ((u >>= 1) != 0)
+ abort ();
+ u = 1;
+ if ((u &= 0) != 0)
+ abort ();
+ if ((u |= 2) != 1)
+ abort ();
+ if ((u ^= 3) != 1)
+ abort ();
+ /* Test comma expressions. */
+ u = 1;
+ if ((4, u) != 1)
+ abort ();
+ /* Test bitfields. */
+ {
+ int i;
+ for (i = 0; i < sizeof (struct foo); i++)
+ *((unsigned char *)&sf + i) = (unsigned char) -1;
+ sf.a = 1;
+ if (sf.a != 1)
+ abort ();
+ sf.b = 1;
+ if (sf.b != 1)
+ abort ();
+ sf.c = 1;
+ if (sf.c != 1)
+ abort ();
+ sf.a = 0;
+ if (sf.a != 0)
+ abort ();
+ sf.b = 0;
+ if (sf.b != 0)
+ abort ();
+ sf.c = 0;
+ if (sf.c != 0)
+ abort ();
+ }
+ exit (0);
+}
--
Joseph S. Myers
jsm28@cam.ac.uk