Initial revision
authorRichard Stallman <rms@gnu.org>
Tue, 4 Feb 1992 19:51:11 +0000 (19:51 +0000)
committerRichard Stallman <rms@gnu.org>
Tue, 4 Feb 1992 19:51:11 +0000 (19:51 +0000)
From-SVN: r278

gcc/c-common.c [new file with mode: 0644]

diff --git a/gcc/c-common.c b/gcc/c-common.c
new file mode 100644 (file)
index 0000000..a65a49c
--- /dev/null
@@ -0,0 +1,894 @@
+/* Subroutines shared by all languages that are variants of C.
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "config.h"
+#include "tree.h"
+#include "c-lex.h"
+#include "c-tree.h"
+#include "flags.h"
+#include <stdio.h>
+
+#undef NULL
+#define NULL 0
+
+/* Given a chain of STRING_CST nodes,
+   concatenate them into one STRING_CST
+   and give it a suitable array-of-chars data type.  */
+
+tree
+combine_strings (strings)
+     tree strings;
+{
+  register tree value, t;
+  register int length = 1;
+  int wide_length = 0;
+  int wide_flag = 0;
+  int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+  int nchars;
+
+  if (TREE_CHAIN (strings))
+    {
+      /* More than one in the chain, so concatenate.  */
+      register char *p, *q;
+
+      /* Don't include the \0 at the end of each substring,
+        except for the last one.
+        Count wide strings and ordinary strings separately.  */
+      for (t = strings; t; t = TREE_CHAIN (t))
+       {
+         if (TREE_TYPE (t) == wchar_array_type_node)
+           {
+             wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
+             wide_flag = 1;
+           }
+         else
+           length += (TREE_STRING_LENGTH (t) - 1);
+       }
+
+      /* If anything is wide, the non-wides will be converted,
+        which makes them take more space.  */
+      if (wide_flag)
+       length = length * wchar_bytes + wide_length;
+
+      p = savealloc (length);
+
+      /* Copy the individual strings into the new combined string.
+        If the combined string is wide, convert the chars to ints
+        for any individual strings that are not wide.  */
+
+      q = p;
+      for (t = strings; t; t = TREE_CHAIN (t))
+       {
+         int len = (TREE_STRING_LENGTH (t)
+                    - ((TREE_TYPE (t) == wchar_array_type_node)
+                       ? wchar_bytes : 1));
+         if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
+           {
+             bcopy (TREE_STRING_POINTER (t), q, len);
+             q += len;
+           }
+         else
+           {
+             int i;
+             for (i = 0; i < len; i++)
+               ((int *) q)[i] = TREE_STRING_POINTER (t)[i];
+             q += len * wchar_bytes;
+           }
+       }
+      if (wide_flag)
+       {
+         int i;
+         for (i = 0; i < wchar_bytes; i++)
+           *q++ = 0;
+       }
+      else
+       *q = 0;
+
+      value = make_node (STRING_CST);
+      TREE_STRING_POINTER (value) = p;
+      TREE_STRING_LENGTH (value) = length;
+      TREE_CONSTANT (value) = 1;
+    }
+  else
+    {
+      value = strings;
+      length = TREE_STRING_LENGTH (value);
+      if (TREE_TYPE (value) == wchar_array_type_node)
+       wide_flag = 1;
+    }
+
+  /* Compute the number of elements, for the array type.  */ 
+  nchars = wide_flag ? length / wchar_bytes : length;
+
+  /* Create the array type for the string constant.
+     -Wwrite-strings says make the string constant an array of const char
+     so that copying it to a non-const pointer will get a warning.  */
+  if (warn_write_strings
+      && (! flag_traditional  && ! flag_writable_strings))
+    {
+      tree elements
+       = build_type_variant (wide_flag ? wchar_type_node : char_type_node,
+                             1, 0);
+      TREE_TYPE (value)
+       = build_array_type (elements,
+                           build_index_type (build_int_2 (nchars - 1, 0)));
+    }
+  else
+    TREE_TYPE (value)
+      = build_array_type (wide_flag ? wchar_type_node : char_type_node,
+                         build_index_type (build_int_2 (nchars - 1, 0)));
+  TREE_CONSTANT (value) = 1;
+  TREE_STATIC (value) = 1;
+  return value;
+}
+\f
+/* Process the attributes listed in ATTRIBUTES
+   and install them in DECL.  */
+
+void
+decl_attributes (decl, attributes)
+     tree decl, attributes;
+{
+  tree a;
+  for (a = attributes; a; a = TREE_CHAIN (a))
+    if (TREE_VALUE (a) != 0
+       && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
+       && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("aligned"))
+      {
+       int align = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (a)))
+                   * BITS_PER_UNIT;
+       
+       if (exact_log2 (align) == -1)
+         warning_with_decl (decl,
+                       "requested alignment of `%s' is not a power of 2");
+       else if (TREE_CODE (decl) != VAR_DECL
+                && TREE_CODE (decl) != FIELD_DECL)
+         warning_with_decl (decl,
+               "alignment specified for `%s' which is not a variable");
+
+       /* ??? The maximum alignment gcc can currently handle is 16 bytes!
+          We should change the representation to be the log of the
+          actual alignment since we only handle powers of 2 anyway.  */
+       else if (align > 255)
+         warning_with_decl (decl,
+               "requested alignment of `%s' exceeds compiler limits");
+       else
+         DECL_ALIGN (decl) = align;
+      }
+    else if (TREE_VALUE (a) != 0
+            && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
+            && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("packed"))
+      {
+       if (TREE_CODE (decl) == FIELD_DECL)
+         DECL_PACKED (decl) = 1;
+      }
+    else if (TREE_VALUE (a) != 0
+       && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
+       && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("format"))
+      {
+        tree list = TREE_VALUE (TREE_VALUE (a));
+        tree format_type = TREE_PURPOSE (list);
+       int format_num = TREE_INT_CST_LOW (TREE_PURPOSE (TREE_VALUE (list)));
+       int first_arg_num = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list)));
+       int is_scan;
+       
+       if (TREE_CODE (decl) != FUNCTION_DECL)
+         {
+           warning_with_decl (decl,
+               "argument format specified for non-function `%s'");
+           return;
+         }
+       
+       if (format_type == get_identifier ("printf"))
+         is_scan = 0;
+       else if (format_type == get_identifier ("scanf"))
+         is_scan = 1;
+       else
+         {
+           warning_with_decl (decl,"unrecognized format specifier for `%s'");
+           return;
+         }
+       
+       if (first_arg_num != 0 && first_arg_num <= format_num)
+         {
+           warning_with_decl (decl,
+               "format string arg follows the args to be formatted, for `%s'");
+           return;
+         }
+       
+       record_format_info (DECL_NAME (decl), is_scan, format_num,
+                           first_arg_num);
+      }
+}
+\f
+void
+c_expand_expr_stmt (expr)
+     tree expr;
+{
+  /* Do default conversion if safe and possibly important,
+     in case within ({...}).  */
+  if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr))
+      || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
+    expr = default_conversion (expr);
+
+  if (TREE_TYPE (expr) != error_mark_node
+      && TYPE_SIZE (TREE_TYPE (expr)) == 0
+      && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
+    error ("expression statement has incomplete type");
+
+  expand_expr_stmt (expr);
+}
+\f
+/* Validate the expression after `case' and apply default promotions.  */
+
+tree
+check_case_value (value)
+     tree value;
+{
+  if (value == NULL_TREE)
+    return value;
+
+  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
+  if (TREE_CODE (value) == NON_LVALUE_EXPR)
+    value = TREE_OPERAND (value, 0);
+
+  if (TREE_CODE (value) != INTEGER_CST
+      && value != error_mark_node)
+    {
+      error ("case label does not reduce to an integer constant");
+      value = error_mark_node;
+    }
+  else
+    /* Promote char or short to int.  */
+    value = default_conversion (value);
+
+  return value;
+}
+\f
+/* Return an integer type with BITS bits of precision,
+   that is unsigned if UNSIGNEDP is nonzero, otherwise signed.  */
+
+tree
+type_for_size (bits, unsignedp)
+     unsigned bits;
+     int unsignedp;
+{
+  if (bits <= TYPE_PRECISION (signed_char_type_node))
+    return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+  if (bits <= TYPE_PRECISION (short_integer_type_node))
+    return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+  if (bits <= TYPE_PRECISION (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
+  if (bits <= TYPE_PRECISION (long_integer_type_node))
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+  if (bits <= TYPE_PRECISION (long_long_integer_type_node))
+    return (unsignedp ? long_long_unsigned_type_node
+           : long_long_integer_type_node);
+
+  return 0;
+}
+
+/* Return a data type that has machine mode MODE.
+   If the mode is an integer,
+   then UNSIGNEDP selects between signed and unsigned types.  */
+
+tree
+type_for_mode (mode, unsignedp)
+     enum machine_mode mode;
+     int unsignedp;
+{
+  if (mode == TYPE_MODE (signed_char_type_node))
+    return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+  if (mode == TYPE_MODE (short_integer_type_node))
+    return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+  if (mode == TYPE_MODE (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
+  if (mode == TYPE_MODE (long_integer_type_node))
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+  if (mode == TYPE_MODE (long_long_integer_type_node))
+    return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node;
+
+  if (mode == TYPE_MODE (float_type_node))
+    return float_type_node;
+
+  if (mode == TYPE_MODE (double_type_node))
+    return double_type_node;
+
+  if (mode == TYPE_MODE (long_double_type_node))
+    return long_double_type_node;
+
+  if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
+    return build_pointer_type (char_type_node);
+
+  if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
+    return build_pointer_type (integer_type_node);
+
+  return 0;
+}
+\f
+/* Print an error message for invalid operands to arith operation CODE.
+   NOP_EXPR is used as a special case (see truthvalue_conversion).  */
+
+void
+binary_op_error (code)
+     enum tree_code code;
+{
+  register char *opname;
+  switch (code)
+    {
+    case NOP_EXPR:
+      error ("invalid truth-value expression");
+      return;
+
+    case PLUS_EXPR:
+      opname = "+"; break;
+    case MINUS_EXPR:
+      opname = "-"; break;
+    case MULT_EXPR:
+      opname = "*"; break;
+    case MAX_EXPR:
+      opname = "max"; break;
+    case MIN_EXPR:
+      opname = "min"; break;
+    case EQ_EXPR:
+      opname = "=="; break;
+    case NE_EXPR:
+      opname = "!="; break;
+    case LE_EXPR:
+      opname = "<="; break;
+    case GE_EXPR:
+      opname = ">="; break;
+    case LT_EXPR:
+      opname = "<"; break;
+    case GT_EXPR:
+      opname = ">"; break;
+    case LSHIFT_EXPR:
+      opname = "<<"; break;
+    case RSHIFT_EXPR:
+      opname = ">>"; break;
+    case TRUNC_MOD_EXPR:
+      opname = "%"; break;
+    case TRUNC_DIV_EXPR:
+      opname = "/"; break;
+    case BIT_AND_EXPR:
+      opname = "&"; break;
+    case BIT_IOR_EXPR:
+      opname = "|"; break;
+    case TRUTH_ANDIF_EXPR:
+      opname = "&&"; break;
+    case TRUTH_ORIF_EXPR:
+      opname = "||"; break;
+    case BIT_XOR_EXPR:
+      opname = "^"; break;
+    }
+  error ("invalid operands to binary %s", opname);
+}
+\f
+/* Subroutine of build_binary_op, used for comparison operations.
+   See if the operands have both been converted from subword integer types
+   and, if so, perhaps change them both back to their original type.
+
+   The arguments of this function are all pointers to local variables
+   of build_binary_op: OP0_PTR is &OP0, OP1_PTR is &OP1,
+   RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE.
+
+   If this function returns nonzero, it means that the comparison has
+   a constant value.  What this function returns is an expression for
+   that value.  */
+
+tree
+shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
+     tree *op0_ptr, *op1_ptr;
+     tree *restype_ptr;
+     enum tree_code *rescode_ptr;
+{
+  register tree type;
+  tree op0 = *op0_ptr;
+  tree op1 = *op1_ptr;
+  int unsignedp0, unsignedp1;
+  int real1, real2;
+  tree primop0, primop1;
+  enum tree_code code = *rescode_ptr;
+
+  /* Throw away any conversions to wider types
+     already present in the operands.  */
+
+  primop0 = get_narrower (op0, &unsignedp0);
+  primop1 = get_narrower (op1, &unsignedp1);
+
+  /* Handle the case that OP0 does not *contain* a conversion
+     but it *requires* conversion to FINAL_TYPE.  */
+
+  if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr)
+    unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0));
+  if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr)
+    unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1));
+
+  /* If one of the operands must be floated, we cannot optimize.  */
+  real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE;
+  real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
+
+  /* If first arg is constant, swap the args (changing operation
+     so value is preserved), for canonicalization.  */
+
+  if (TREE_CONSTANT (primop0))
+    {
+      register tree tem = primop0;
+      register int temi = unsignedp0;
+      primop0 = primop1;
+      primop1 = tem;
+      tem = op0;
+      op0 = op1;
+      op1 = tem;
+      *op0_ptr = op0;
+      *op1_ptr = op1;
+      unsignedp0 = unsignedp1;
+      unsignedp1 = temi;
+      temi = real1;
+      real1 = real2;
+      real2 = temi;
+
+      switch (code)
+       {
+       case LT_EXPR:
+         code = GT_EXPR;
+         break;
+       case GT_EXPR:
+         code = LT_EXPR;
+         break;
+       case LE_EXPR:
+         code = GE_EXPR;
+         break;
+       case GE_EXPR:
+         code = LE_EXPR;
+         break;
+       }
+      *rescode_ptr = code;
+    }
+
+  /* If comparing an integer against a constant more bits wide,
+     maybe we can deduce a value of 1 or 0 independent of the data.
+     Or else truncate the constant now
+     rather than extend the variable at run time.
+
+     This is only interesting if the constant is the wider arg.
+     Also, it is not safe if the constant is unsigned and the
+     variable arg is signed, since in this case the variable
+     would be sign-extended and then regarded as unsigned.
+     Our technique fails in this case because the lowest/highest
+     possible unsigned results don't follow naturally from the
+     lowest/highest possible values of the variable operand.
+     For just EQ_EXPR and NE_EXPR there is another technique that
+     could be used: see if the constant can be faithfully represented
+     in the other operand's type, by truncating it and reextending it
+     and see if that preserves the constant's value.  */
+
+  if (!real1 && !real2
+      && TREE_CODE (primop1) == INTEGER_CST
+      && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
+    {
+      int min_gt, max_gt, min_lt, max_lt;
+      tree maxval, minval;
+      /* 1 if comparison is nominally unsigned.  */
+      int unsignedp = TREE_UNSIGNED (*restype_ptr);
+      tree val;
+
+      type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
+
+      maxval = TYPE_MAX_VALUE (type);
+      minval = TYPE_MIN_VALUE (type);
+
+      if (unsignedp && !unsignedp0)
+       *restype_ptr = signed_type (*restype_ptr);
+
+      if (TREE_TYPE (primop1) != *restype_ptr)
+       primop1 = convert (*restype_ptr, primop1);
+      if (type != *restype_ptr)
+       {
+         minval = convert (*restype_ptr, minval);
+         maxval = convert (*restype_ptr, maxval);
+       }
+
+      if (unsignedp && unsignedp0)
+       {
+         min_gt = INT_CST_LT_UNSIGNED (primop1, minval);
+         max_gt = INT_CST_LT_UNSIGNED (primop1, maxval);
+         min_lt = INT_CST_LT_UNSIGNED (minval, primop1);
+         max_lt = INT_CST_LT_UNSIGNED (maxval, primop1);
+       }
+      else
+       {
+         min_gt = INT_CST_LT (primop1, minval);
+         max_gt = INT_CST_LT (primop1, maxval);
+         min_lt = INT_CST_LT (minval, primop1);
+         max_lt = INT_CST_LT (maxval, primop1);
+       }
+
+      val = 0;
+      /* This used to be a switch, but Genix compiler can't handle that.  */
+      if (code == NE_EXPR)
+       {
+         if (max_lt || min_gt)
+           val = integer_one_node;
+       }
+      else if (code == EQ_EXPR)
+       {
+         if (max_lt || min_gt)
+           val = integer_zero_node;
+       }
+      else if (code == LT_EXPR)
+       {
+         if (max_lt)
+           val = integer_one_node;
+         if (!min_lt)
+           val = integer_zero_node;
+       }
+      else if (code == GT_EXPR)
+       {
+         if (min_gt)
+           val = integer_one_node;
+         if (!max_gt)
+           val = integer_zero_node;
+       }
+      else if (code == LE_EXPR)
+       {
+         if (!max_gt)
+           val = integer_one_node;
+         if (min_gt)
+           val = integer_zero_node;
+       }
+      else if (code == GE_EXPR)
+       {
+         if (!min_lt)
+           val = integer_one_node;
+         if (max_lt)
+           val = integer_zero_node;
+       }
+
+      /* If primop0 was sign-extended and unsigned comparison specd,
+        we did a signed comparison above using the signed type bounds.
+        But the comparison we output must be unsigned.
+
+        Also, for inequalities, VAL is no good; but if the signed
+        comparison had *any* fixed result, it follows that the
+        unsigned comparison just tests the sign in reverse
+        (positive values are LE, negative ones GE).
+        So we can generate an unsigned comparison
+        against an extreme value of the signed type.  */
+
+      if (unsignedp && !unsignedp0)
+       {
+         if (val != 0)
+           switch (code)
+             {
+             case LT_EXPR:
+             case GE_EXPR:
+               primop1 = TYPE_MIN_VALUE (type);
+               val = 0;
+               break;
+
+             case LE_EXPR:
+             case GT_EXPR:
+               primop1 = TYPE_MAX_VALUE (type);
+               val = 0;
+               break;
+             }
+         type = unsigned_type (type);
+       }
+
+      if (max_lt && !unsignedp0)
+       {
+         /* This is the case of (char)x >?< 0x80, which people used to use
+            expecting old C compilers to change the 0x80 into -0x80.  */
+         if (val == integer_zero_node)
+           warning ("comparison is always 0 due to limited range of data type");
+         if (val == integer_one_node)
+           warning ("comparison is always 1 due to limited range of data type");
+       }
+
+      if (min_gt && unsignedp0)
+       {
+         /* This is the case of (unsigned char)x >?< -1.  */
+         if (val == integer_zero_node)
+           warning ("comparison is always 0 due to limited range of data type");
+         if (val == integer_one_node)
+           warning ("comparison is always 1 due to limited range of data type");
+       }
+
+      if (val != 0)
+       {
+         /* Don't forget to evaluate PRIMOP0 if it has side effects.  */
+         if (TREE_SIDE_EFFECTS (primop0))
+           return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
+         return val;
+       }
+
+      /* Value is not predetermined, but do the comparison
+        in the type of the operand that is not constant.
+        TYPE is already properly set.  */
+    }
+  else if (real1 && real2
+          && TYPE_PRECISION (TREE_TYPE (primop0)) == TYPE_PRECISION (TREE_TYPE (primop1)))
+    type = TREE_TYPE (primop0);
+
+  /* If args' natural types are both narrower than nominal type
+     and both extend in the same manner, compare them
+     in the type of the wider arg.
+     Otherwise must actually extend both to the nominal
+     common type lest different ways of extending
+     alter the result.
+     (eg, (short)-1 == (unsigned short)-1  should be 0.)  */
+
+  else if (unsignedp0 == unsignedp1 && real1 == real2
+          && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
+          && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
+    {
+      type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
+      type = signed_or_unsigned_type (unsignedp0
+                                     || TREE_UNSIGNED (*restype_ptr),
+                                     type);
+      /* Make sure shorter operand is extended the right way
+        to match the longer operand.  */
+      primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)),
+                        primop0);
+      primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)),
+                        primop1);
+    }
+  else
+    {
+      /* Here we must do the comparison on the nominal type
+        using the args exactly as we received them.  */
+      type = *restype_ptr;
+      primop0 = op0;
+      primop1 = op1;
+
+      if (!real1 && !real2 && integer_zerop (primop1)
+         && TREE_UNSIGNED (TREE_TYPE (primop0)))
+       {
+         tree value = 0;
+         switch (code)
+           {
+           case GE_EXPR:
+             if (extra_warnings)
+               warning ("unsigned value >= 0 is always 1");
+             value = integer_one_node;
+             break;
+
+           case LT_EXPR:
+             if (extra_warnings)
+               warning ("unsigned value < 0 is always 0");
+             value = integer_zero_node;
+           }
+
+         if (value != 0)
+           {
+             /* Don't forget to evaluate PRIMOP0 if it has side effects.  */
+             if (TREE_SIDE_EFFECTS (primop0))
+               return build (COMPOUND_EXPR, TREE_TYPE (value),
+                             primop0, value);
+             return value;
+           }
+       }
+    }
+
+  *op0_ptr = convert (type, primop0);
+  *op1_ptr = convert (type, primop1);
+
+  *restype_ptr = integer_type_node;
+
+  return 0;
+}
+\f
+/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
+   or validate its data type for an `if' or `while' statement or ?..: exp.
+
+   This preparation consists of taking the ordinary
+   representation of an expression expr and producing a valid tree
+   boolean expression describing whether expr is nonzero.  We could
+   simply always do build_binary_op (NE_EXPR, expr, integer_zero_node, 1),
+   but we optimize comparisons, &&, ||, and !.
+
+   The resulting type should always be `integer_type_node'.  */
+
+tree
+truthvalue_conversion (expr)
+     tree expr;
+{
+  register enum tree_code code;
+
+  switch (TREE_CODE (expr))
+    {
+      /* It is simpler and generates better code to have only TRUTH_*_EXPR
+        or comparison expressions as truth values at this level.  */
+#if 0
+    case COMPONENT_REF:
+      /* A one-bit unsigned bit-field is already acceptable.  */
+      if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1)))
+         && TREE_UNSIGNED (TREE_OPERAND (expr, 1)))
+       return expr;
+      break;
+#endif
+
+    case EQ_EXPR:
+      /* It is simpler and generates better code to have only TRUTH_*_EXPR
+        or comparison expressions as truth values at this level.  */
+#if 0
+      if (integer_zerop (TREE_OPERAND (expr, 1)))
+       return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0);
+#endif
+    case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case ERROR_MARK:
+      return expr;
+
+    case INTEGER_CST:
+      return integer_zerop (expr) ? integer_zero_node : integer_one_node;
+
+    case REAL_CST:
+      return real_zerop (expr) ? integer_zero_node : integer_one_node;
+
+    case ADDR_EXPR:
+      if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
+       return build (COMPOUND_EXPR, integer_type_node,
+                     TREE_OPERAND (expr, 0), integer_one_node);
+      else
+       return integer_one_node;
+
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case FLOAT_EXPR:
+    case FFS_EXPR:
+      /* These don't change whether an object is non-zero or zero.  */
+      return truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      /* These don't change whether an object is zero or non-zero, but
+        we can't ignore them if their second arg has side-effects.  */
+      if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+       return build (COMPOUND_EXPR, integer_type_node, TREE_OPERAND (expr, 1),
+                     truthvalue_conversion (TREE_OPERAND (expr, 0)));
+      else
+       return truthvalue_conversion (TREE_OPERAND (expr, 0));
+      
+    case COND_EXPR:
+      /* Distribute the conversion into the arms of a COND_EXPR.  */
+      return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0),
+                         truthvalue_conversion (TREE_OPERAND (expr, 1)),
+                         truthvalue_conversion (TREE_OPERAND (expr, 2))));
+
+    case CONVERT_EXPR:
+      /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
+        since that affects how `default_conversion' will behave.  */
+      if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
+         || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
+       break;
+      /* fall through... */
+    case NOP_EXPR:
+      /* If this is widening the argument, we can ignore it.  */
+      if (TYPE_PRECISION (TREE_TYPE (expr))
+         >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
+       return truthvalue_conversion (TREE_OPERAND (expr, 0));
+      break;
+
+    case BIT_XOR_EXPR:
+    case MINUS_EXPR:
+      /* These can be changed into a comparison of the two objects.  */
+      if (TREE_TYPE (TREE_OPERAND (expr, 0))
+         == TREE_TYPE (TREE_OPERAND (expr, 1)))
+       return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
+                               TREE_OPERAND (expr, 1), 1);
+      return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
+                             fold (build1 (NOP_EXPR,
+                                           TREE_TYPE (TREE_OPERAND (expr, 0)),
+                                           TREE_OPERAND (expr, 1))), 1);
+    }
+
+  return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
+}
+\f
+/* Read the rest of a #-directive from input stream FINPUT.
+   In normal use, the directive name and the white space after it
+   have already been read, so they won't be included in the result.
+   We allow for the fact that the directive line may contain
+   a newline embedded within a character or string literal which forms
+   a part of the directive.
+
+   The value is a string in a reusable buffer.  It remains valid
+   only until the next time this function is called.  */
+
+char *
+get_directive_line (finput)
+     register FILE *finput;
+{
+  static char *directive_buffer = NULL;
+  static unsigned buffer_length = 0;
+  register char *p;
+  register char *buffer_limit;
+  register int looking_for = 0;
+  register int char_escaped = 0;
+
+  if (buffer_length == 0)
+    {
+      directive_buffer = (char *)xmalloc (128);
+      buffer_length = 128;
+    }
+
+  buffer_limit = &directive_buffer[buffer_length];
+
+  for (p = directive_buffer; ; )
+    {
+      int c;
+
+      /* Make buffer bigger if it is full.  */
+      if (p >= buffer_limit)
+        {
+         register unsigned bytes_used = (p - directive_buffer);
+
+         buffer_length *= 2;
+         directive_buffer
+           = (char *)xrealloc (directive_buffer, buffer_length);
+         p = &directive_buffer[bytes_used];
+         buffer_limit = &directive_buffer[buffer_length];
+        }
+
+      c = getc (finput);
+
+      /* Discard initial whitespace.  */
+      if ((c == ' ' || c == '\t') && p == directive_buffer)
+       continue;
+
+      /* Detect the end of the directive.  */
+      if (c == '\n' && looking_for == 0)
+       {
+          ungetc (c, finput);
+         c = '\0';
+       }
+
+      *p++ = c;
+
+      if (c == 0)
+       return directive_buffer;
+
+      /* Handle string and character constant syntax.  */
+      if (looking_for)
+       {
+         if (looking_for == c && !char_escaped)
+           looking_for = 0;    /* Found terminator... stop looking.  */
+       }
+      else
+        if (c == '\'' || c == '"')
+         looking_for = c;      /* Don't stop buffering until we see another
+                                  another one of these (or an EOF).  */
+
+      /* Handle backslash.  */
+      char_escaped = (c == '\\' && ! char_escaped);
+    }
+}