OSDN Git Service

fix compile time warnings about unused epilogue instructions
[pf3gnuchains/gcc-fork.git] / gcc / cpplib.c
index 06b1717..90f6c80 100644 (file)
@@ -25,8 +25,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "cpphash.h"
 #include "intl.h"
 
-#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
-#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
+#define SKIP_WHITE_SPACE(p) do { while (is_hspace(*p)) p++; } while (0)
 
 #define PEEKN(N) (CPP_BUFFER (pfile)->rlimit - CPP_BUFFER (pfile)->cur >= (N) ? CPP_BUFFER (pfile)->cur[N] : EOF)
 #define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
@@ -38,8 +37,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* Forward declarations.  */
 
-static char *my_strerror               PROTO ((int));
-static void validate_else              PROTO ((cpp_reader *, char *));
+static const char *my_strerror         PROTO ((int));
+static void validate_else              PROTO ((cpp_reader *, const char *));
 static HOST_WIDEST_INT eval_if_expression      PROTO ((cpp_reader *));
 
 static void conditional_skip           PROTO ((cpp_reader *, int,
@@ -49,6 +48,8 @@ static void skip_if_group             PROTO ((cpp_reader *));
 static void parse_name                 PARAMS ((cpp_reader *, int));
 static void parse_string               PARAMS ((cpp_reader *, int));
 static int parse_assertion             PARAMS ((cpp_reader *));
+static const char *if_directive_name   PARAMS ((cpp_reader *,
+                                                struct if_stack *));
 
 /* External declarations.  */
 
@@ -59,8 +60,8 @@ extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *));
 struct directive {
   int length;                  /* Length of name */
   int (*func)                  /* Function to handle directive */
-    PARAMS ((cpp_reader *, struct directive *));
-  char *name;                  /* Name of directive */
+    PARAMS ((cpp_reader *, const struct directive *));
+  const char *name;            /* Name of directive */
   enum node_type type;         /* Code which describes which directive.  */
 };
 
@@ -68,53 +69,74 @@ struct directive {
    are going to be placed in a table and some old compilers have trouble with
    pointers to functions returning void.  */
 
-static int do_define PARAMS ((cpp_reader *, struct directive *));
-static int do_line PARAMS ((cpp_reader *, struct directive *));
-static int do_include PARAMS ((cpp_reader *, struct directive *));
-static int do_undef PARAMS ((cpp_reader *, struct directive *));
-static int do_error PARAMS ((cpp_reader *, struct directive *));
-static int do_pragma PARAMS ((cpp_reader *, struct directive *));
-static int do_ident PARAMS ((cpp_reader *, struct directive *));
-static int do_if PARAMS ((cpp_reader *, struct directive *));
-static int do_xifdef PARAMS ((cpp_reader *, struct directive *));
-static int do_else PARAMS ((cpp_reader *, struct directive *));
-static int do_elif PARAMS ((cpp_reader *, struct directive *));
-static int do_endif PARAMS ((cpp_reader *, struct directive *));
+static int do_define PARAMS ((cpp_reader *, const struct directive *));
+static int do_line PARAMS ((cpp_reader *, const struct directive *));
+static int do_include PARAMS ((cpp_reader *, const struct directive *));
+static int do_undef PARAMS ((cpp_reader *, const struct directive *));
+static int do_error PARAMS ((cpp_reader *, const struct directive *));
+static int do_pragma PARAMS ((cpp_reader *, const struct directive *));
+static int do_ident PARAMS ((cpp_reader *, const struct directive *));
+static int do_if PARAMS ((cpp_reader *, const struct directive *));
+static int do_xifdef PARAMS ((cpp_reader *, const struct directive *));
+static int do_else PARAMS ((cpp_reader *, const struct directive *));
+static int do_elif PARAMS ((cpp_reader *, const struct directive *));
+static int do_endif PARAMS ((cpp_reader *, const struct directive *));
 #ifdef SCCS_DIRECTIVE
-static int do_sccs PARAMS ((cpp_reader *, struct directive *));
+static int do_sccs PARAMS ((cpp_reader *, const struct directive *));
 #endif
-static int do_assert PARAMS ((cpp_reader *, struct directive *));
-static int do_unassert PARAMS ((cpp_reader *, struct directive *));
-static int do_warning PARAMS ((cpp_reader *, struct directive *));
-
-#define IS_INCLUDE_DIRECTIVE_TYPE(t) \
-((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT)
-
-/* Here is the actual list of #-directives, most-often-used first.
-   The initialize_builtins function assumes #define is the very first.  */
-
-static struct directive directive_table[] = {
-  {  6, do_define,   "define",       T_DEFINE },
-  {  5, do_xifdef,   "ifdef",        T_IFDEF },
-  {  6, do_xifdef,   "ifndef",       T_IFNDEF },
-  {  7, do_include,  "include",      T_INCLUDE },
-  { 12, do_include,  "include_next", T_INCLUDE_NEXT },
-  {  6, do_include,  "import",       T_IMPORT },
-  {  5, do_endif,    "endif",        T_ENDIF },
-  {  4, do_else,     "else",         T_ELSE },
-  {  2, do_if,       "if",           T_IF },
-  {  4, do_elif,     "elif",         T_ELIF },
-  {  5, do_undef,    "undef",        T_UNDEF },
-  {  5, do_error,    "error",        T_ERROR },
-  {  7, do_warning,  "warning",      T_WARNING },
-  {  6, do_pragma,   "pragma",       T_PRAGMA },
-  {  4, do_line,     "line",         T_LINE },
-  {  5, do_ident,    "ident",        T_IDENT },
+static int do_assert PARAMS ((cpp_reader *, const struct directive *));
+static int do_unassert PARAMS ((cpp_reader *, const struct directive *));
+static int do_warning PARAMS ((cpp_reader *, const struct directive *));
+static enum cpp_token null_underflow PARAMS ((cpp_reader *));
+static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
+static int skip_comment PARAMS ((cpp_reader *, int));
+static int copy_comment PARAMS ((cpp_reader *, int));
+static void copy_rest_of_line PARAMS ((cpp_reader *));
+static int handle_directive PARAMS ((cpp_reader *));
+static void pass_thru_directive PARAMS ((const U_CHAR *, size_t, cpp_reader *,
+                                        const struct directive *));
+static enum cpp_token get_directive_token PARAMS ((cpp_reader *));
+static int read_line_number PARAMS ((cpp_reader *, int *));
+static void cpp_print_file_and_line PARAMS ((cpp_reader *));
+static void v_cpp_error PARAMS ((cpp_reader *, const char *, va_list));
+static void v_cpp_warning PARAMS ((cpp_reader *, const char *, va_list));
+static void v_cpp_error_with_line PARAMS ((cpp_reader *, int, int,
+                                          const char *, va_list));
+static void v_cpp_warning_with_line PARAMS ((cpp_reader *, int, int, const char *, va_list));
+static U_CHAR *detect_if_not_defined PARAMS ((cpp_reader *));
+static int consider_directive_while_skipping PARAMS ((cpp_reader *, IF_STACK_FRAME *));
+
+/* Here is the actual list of #-directives.
+   This table is ordered by frequency of occurrence; the numbers
+   at the end are directive counts from all the source code I have
+   lying around (egcs and libc CVS as of 1999-05-18, plus grub-0.5.91,
+   linux-2.2.9, and pcmcia-cs-3.0.9).  */
+
+static const struct directive directive_table[] = {
+  /* In C89 */
+  {  6, do_define,   "define",       T_DEFINE },       /* 270554 */
+  {  7, do_include,  "include",      T_INCLUDE },      /*  52262 */
+  {  5, do_endif,    "endif",        T_ENDIF },                /*  45855 */
+  {  5, do_xifdef,   "ifdef",        T_IFDEF },                /*  22000 */
+  {  2, do_if,       "if",           T_IF },           /*  18162 */
+  {  4, do_else,     "else",         T_ELSE },         /*   9863 */
+  {  6, do_xifdef,   "ifndef",       T_IFNDEF },       /*   9675 */
+  {  5, do_undef,    "undef",        T_UNDEF },                /*   4837 */
+  {  4, do_line,     "line",         T_LINE },         /*   2465 */
+  {  4, do_elif,     "elif",         T_ELIF },         /*    610 */
+  {  5, do_error,    "error",        T_ERROR },                /*    475 */
+  {  6, do_pragma,   "pragma",       T_PRAGMA },       /*    195 */
+
+  /* Extensions.  All deprecated except #warning and #include_next.  */
+  {  7, do_warning,  "warning",      T_WARNING },      /*     22 - GNU   */
+  { 12, do_include,  "include_next", T_INCLUDE_NEXT }, /*     19 - GNU   */
+  {  5, do_ident,    "ident",        T_IDENT },                /*     11 - SVR4  */
+  {  6, do_include,  "import",       T_IMPORT },       /*      0 - ObjC  */
+  {  6, do_assert,   "assert",       T_ASSERT },       /*      0 - SVR4  */
+  {  8, do_unassert, "unassert",     T_UNASSERT },     /*      0 - SVR4  */
 #ifdef SCCS_DIRECTIVE
-  {  4, do_sccs,     "sccs",         T_SCCS },
+  {  4, do_sccs,     "sccs",         T_SCCS },         /*      0 - SVR2? */
 #endif
-  {  6, do_assert,   "assert",       T_ASSERT },
-  {  8, do_unassert, "unassert",     T_UNASSERT },
   {  -1, 0, "", T_UNUSED }
 };
 
@@ -388,7 +410,7 @@ cpp_skip_hspace (pfile)
       c = GETC();
       if (c == EOF)
        return;
-      else if (is_hor_space[c])
+      else if (is_hspace(c))
        {
          if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile))
            cpp_pedwarn (pfile, "%s in preprocessing directive",
@@ -497,7 +519,7 @@ handle_directive (pfile)
      cpp_reader *pfile;
 {
   int c;
-  register struct directive *kt;
+  register const struct directive *kt;
   int ident_length;
   U_CHAR *ident;
   long old_written = CPP_WRITTEN (pfile);
@@ -505,15 +527,31 @@ handle_directive (pfile)
   cpp_skip_hspace (pfile);
 
   c = PEEKC ();
+  /* # followed by a number is equivalent to #line.  Do not recognize
+     this form in assembly language source files.  Complain about this
+     form if we're being pedantic, but not if this is regurgitated
+     input (preprocessed or fed back in by the C++ frontend).  */
   if (c >= '0' && c <= '9')
     {
-      /* Handle # followed by a line number.  */
-      if (CPP_PEDANTIC (pfile))
+      if (CPP_OPTIONS (pfile)->lang_asm)
+       {
+         skip_rest_of_line (pfile);
+         return 1;
+       }
+
+      if (CPP_PEDANTIC (pfile)
+         && ! CPP_PREPROCESSED (pfile)
+         && ! CPP_BUFFER (pfile)->manual_pop)
        cpp_pedwarn (pfile, "`#' followed by integer");
       do_line (pfile, NULL);
       return 1;
     }
 
+  /* If we are rescanning preprocessed input, don't obey any directives
+     other than # nnn.  */
+  if (CPP_PREPROCESSED (pfile))
+    return 0;
+
   /* Now find the directive name.  */
   CPP_PUTC (pfile, '#');
   parse_name (pfile, GETC());
@@ -554,10 +592,10 @@ handle_directive (pfile)
 
 static void
 pass_thru_directive (buf, len, pfile, keyword)
-     U_CHAR *buf;
+     const U_CHAR *buf;
      size_t len;
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   register unsigned keyword_length = keyword->length;
 
@@ -569,58 +607,58 @@ pass_thru_directive (buf, len, pfile, keyword)
   CPP_PUTS_Q (pfile, buf, len);
 }
 
-/* Check a purported macro name SYMNAME, and yield its length.
-   ASSERTION is nonzero if this is really for an assertion name.  */
+/* Check a purported macro name SYMNAME, and yield its length.  */
 
 int
-check_macro_name (pfile, symname, assertion)
+check_macro_name (pfile, symname)
      cpp_reader *pfile;
-     U_CHAR *symname;
-     int assertion;
+     const U_CHAR *symname;
 {
-  U_CHAR *p;
+  const U_CHAR *p;
   int sym_length;
 
-  for (p = symname; is_idchar[*p]; p++)
+  for (p = symname; is_idchar(*p); p++)
     ;
   sym_length = p - symname;
   if (sym_length == 0
       || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
-    cpp_error (pfile,
-              assertion ? "invalid assertion name" : "invalid macro name");
-  else if (!is_idstart[*symname]
+    cpp_error (pfile, "invalid macro name");
+  else if (!is_idstart(*symname)
           || (! strncmp (symname, "defined", 7) && sym_length == 7)) {
     U_CHAR *msg;                       /* what pain...  */
     msg = (U_CHAR *) alloca (sym_length + 1);
     bcopy (symname, msg, sym_length);
     msg[sym_length] = 0;
-    cpp_error (pfile,
-              (assertion
-               ? "invalid assertion name `%s'"
-               : "invalid macro name `%s'"),
-              msg);
+    cpp_error (pfile, "invalid macro name `%s'", msg);
   }
   return sym_length;
 }
 
 /* Process a #define command.
-KEYWORD is the keyword-table entry for #define,
-or NULL for a "predefined" macro.  */
+   KEYWORD is the keyword-table entry for #define,
+   or NULL for a "predefined" macro,
+   or the keyword-table entry for #pragma in the case of a #pragma poison.  */
 
 static int
 do_define (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   int hashcode;
   MACRODEF mdef;
   HASHNODE *hp;
   long here;
   U_CHAR *macro, *buf, *end;
+  enum node_type new_type;
 
   here = CPP_WRITTEN (pfile);
   copy_rest_of_line (pfile);
 
+  if (keyword == NULL || keyword->type == T_DEFINE)
+    new_type = T_MACRO;
+  else
+    new_type = T_POISON;
+
   /* Copy out the line so we can pop the token buffer. */
   buf = pfile->token_buffer + here;
   end = CPP_PWRITTEN (pfile);
@@ -642,30 +680,40 @@ do_define (pfile, keyword)
       /* Redefining a precompiled key is ok.  */
       if (hp->type == T_PCSTRING)
        ok = 1;
+      /* Redefining a poisoned identifier is even worse than `not ok'.  */
+      else if (hp->type == T_POISON)
+       ok = -1;
       /* Redefining a macro is ok if the definitions are the same.  */
       else if (hp->type == T_MACRO)
        ok = ! compare_defs (pfile, mdef.defn, hp->value.defn);
       /* Redefining a constant is ok with -D.  */
       else if (hp->type == T_CONST || hp->type == T_STDC)
         ok = ! CPP_OPTIONS (pfile)->done_initializing;
-      /* Print the warning if it's not ok.  */
-      if (!ok)
+      /* Print the warning or error if it's not ok.  */
+      if (ok <= 0)
        {
-         cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
+         if (hp->type == T_POISON)
+           cpp_error (pfile, "redefining poisoned `%.*s'", 
+                      mdef.symlen, mdef.symnam);
+         else
+           cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
          if (hp->type == T_MACRO)
            cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file,
                                            hp->value.defn->line,
                        "this is the location of the previous definition");
        }
-      /* Replace the old definition.  */
-      hp->type = T_MACRO;
-      hp->value.defn = mdef.defn;
+      if (hp->type != T_POISON)
+       {
+         /* Replace the old definition.  */
+         hp->type = new_type;
+         hp->value.defn = mdef.defn;
+       }
     }
   else
-    cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO,
+    cpp_install (pfile, mdef.symnam, mdef.symlen, new_type,
                 (char *) mdef.defn, hashcode);
 
-  if (keyword)
+  if (keyword != NULL && keyword->type == T_DEFINE)
     {
       if (CPP_OPTIONS (pfile)->debug_output
          || CPP_OPTIONS (pfile)->dump_macros == dump_definitions)
@@ -697,7 +745,7 @@ cpp_push_buffer (pfile, buffer, length)
       return NULL;
     }
 
-  new = (cpp_buffer *) xcalloc (sizeof (cpp_buffer), 1);
+  new = (cpp_buffer *) xcalloc (1, sizeof (cpp_buffer));
 
   new->if_stack = pfile->if_stack;
   new->cleanup = null_cleanup;
@@ -783,7 +831,7 @@ cpp_scan_buffer (pfile)
 void
 cpp_expand_to_buffer (pfile, buf, length)
      cpp_reader *pfile;
-     U_CHAR *buf;
+     const U_CHAR *buf;
      int length;
 {
   register cpp_buffer *ip;
@@ -968,7 +1016,7 @@ get_directive_token (pfile)
 static int
 do_include (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   int importing = (keyword->type == T_IMPORT);
   int skip_dirs = (keyword->type == T_INCLUDE_NEXT);
@@ -1243,7 +1291,7 @@ read_line_number (pfile, num)
 static int
 do_line (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
   int new_lineno;
@@ -1310,7 +1358,7 @@ do_line (pfile, keyword)
       
       if (strcmp (fname, ip->nominal_fname))
        {
-         char *newname, *oldname;
+         const char *newname, *oldname;
          if (!strcmp (fname, ip->fname))
            newname = ip->fname;
          else if (ip->last_nominal_fname
@@ -1326,7 +1374,7 @@ do_line (pfile, keyword)
              && ip->last_nominal_fname != oldname
              && ip->last_nominal_fname != newname
              && ip->last_nominal_fname != ip->fname)
-           free (ip->last_nominal_fname);
+           free ((void *) ip->last_nominal_fname);
 
          if (newname == ip->fname)
            ip->last_nominal_fname = NULL;
@@ -1360,7 +1408,7 @@ do_line (pfile, keyword)
 static int
 do_undef (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   int sym_length;
   HASHNODE *hp;
@@ -1371,7 +1419,7 @@ do_undef (pfile, keyword)
 
   cpp_skip_hspace (pfile);
   c = GETC();
-  if (! is_idstart[c])
+  if (! is_idstart(c))
   {
       cpp_error (pfile, "token after #undef is not an identifier");
       skip_rest_of_line (pfile);
@@ -1396,7 +1444,7 @@ do_undef (pfile, keyword)
 
   CPP_SET_WRITTEN (pfile, here);
 
-  sym_length = check_macro_name (pfile, buf, 0);
+  sym_length = check_macro_name (pfile, buf);
 
   while ((hp = cpp_lookup (pfile, name, sym_length, -1)) != NULL)
     {
@@ -1404,9 +1452,14 @@ do_undef (pfile, keyword)
         need to pass through all effective #undef commands.  */
       if (CPP_OPTIONS (pfile)->debug_output && keyword)
        pass_thru_directive (name, sym_length, pfile, keyword);
-      if (hp->type != T_MACRO)
-       cpp_warning (pfile, "undefining `%s'", hp->name);
-      delete_macro (hp);
+      if (hp->type == T_POISON)
+       cpp_error (pfile, "cannot undefine poisoned `%s'", hp->name);
+      else 
+       {
+         if (hp->type != T_MACRO)
+           cpp_warning (pfile, "undefining `%s'", hp->name);
+         delete_macro (hp);
+       }
     }
 
   return 0;
@@ -1435,7 +1488,7 @@ cpp_undef (pfile, macro)
 static int
 do_error (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   long here = CPP_WRITTEN (pfile);
   U_CHAR *text;
@@ -1456,7 +1509,7 @@ do_error (pfile, keyword)
 static int
 do_warning (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   U_CHAR *text;
   long here = CPP_WRITTEN(pfile);
@@ -1482,7 +1535,7 @@ do_warning (pfile, keyword)
 static int
 do_ident (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   /* Allow #ident in system headers, since that's not user's fault.  */
   if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p)
@@ -1501,7 +1554,7 @@ do_ident (pfile, keyword)
 static int
 do_pragma (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   long here;
   U_CHAR *buf;
@@ -1558,6 +1611,65 @@ do_pragma (pfile, keyword)
          "`#pragma implementation' for `%s' appears after file is included",
                     fcopy);
     }
+  else if (!strncmp (buf, "poison", 6))
+    {
+      /* Poison these symbols so that all subsequent usage produces an
+        error message.  */
+      U_CHAR *p = buf + 6;
+      size_t plen;
+      U_CHAR *syms;
+      int writeit;
+
+      SKIP_WHITE_SPACE (p);
+      plen = strlen(p) + 1;
+
+      syms = (U_CHAR *) alloca (plen);
+      memcpy (syms, p, plen);
+
+      /* As a rule, don't include #pragma poison commands in output,  
+         unless the user asks for them.  */
+      writeit = (CPP_OPTIONS (pfile)->debug_output
+                || CPP_OPTIONS (pfile)->dump_macros == dump_definitions
+                || CPP_OPTIONS (pfile)->dump_macros == dump_names);
+
+      if (writeit)
+       CPP_SET_WRITTEN (pfile, here);
+      else
+       CPP_SET_WRITTEN (pfile, here-8);
+
+      if (writeit)
+       {
+         CPP_RESERVE (pfile, plen + 7);
+         CPP_PUTS_Q (pfile, "poison", 7);
+       }
+
+      while (*syms != '\0')
+       {
+         U_CHAR *end = syms;
+         
+         while (is_idchar(*end))
+           end++;
+
+         if (!is_hspace(*end) && *end != '\0')
+           {
+             cpp_error (pfile, "invalid #pragma poison directive");
+             return 1;
+           }
+
+         if (cpp_push_buffer (pfile, syms, end - syms) != NULL)
+           {
+             do_define (pfile, keyword);
+             cpp_pop_buffer (pfile);
+           }
+         if (writeit)
+           {
+             CPP_PUTC_Q (pfile, ' ');
+             CPP_PUTS_Q (pfile, syms, end - syms);
+           }
+         syms = end;
+         SKIP_WHITE_SPACE (syms);
+       }
+    }
 
   return 0;
 }
@@ -1568,7 +1680,7 @@ do_pragma (pfile, keyword)
 static int
 do_sccs (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   if (CPP_PEDANTIC (pfile))
     cpp_pedwarn (pfile, "ANSI C does not allow `#sccs'");
@@ -1577,6 +1689,81 @@ do_sccs (pfile, keyword)
 }
 #endif
 \f
+
+/* We've found an `#if' directive.  If the only thing before it in
+   this file is white space, and if it is of the form
+   `#if ! defined SYMBOL', then SYMBOL is a possible controlling macro
+   for inclusion of this file.  (See redundant_include_p in cppfiles.c
+   for an explanation of controlling macros.)  If so, return a
+   malloc'd copy of SYMBOL.  Otherwise, return NULL.  */
+
+static U_CHAR *
+detect_if_not_defined (pfile)
+     cpp_reader *pfile;
+{
+  U_CHAR *control_macro = 0;
+
+  if (pfile->only_seen_white == 2)
+    {
+      char *ident;
+      enum cpp_token token;
+      int base_offset;
+      int token_offset;
+      int need_rparen = 0;
+
+      /* Save state required for restore.  */
+      pfile->no_macro_expand++;
+      parse_set_mark (pfile);
+      base_offset = CPP_WRITTEN (pfile);
+
+      /* Look for `!', */
+      if (get_directive_token (pfile) != CPP_OTHER
+         || CPP_WRITTEN (pfile) != (size_t) base_offset + 1
+         || CPP_PWRITTEN (pfile)[-1] != '!')
+       goto restore;
+
+      /* ...then `defined', */
+      token_offset = CPP_WRITTEN (pfile);
+      token = get_directive_token (pfile);
+      if (token != CPP_NAME)
+       goto restore;
+      ident = pfile->token_buffer + token_offset;
+      CPP_NUL_TERMINATE (pfile);
+      if (strcmp (ident, "defined"))
+       goto restore;
+
+      /* ...then an optional '(' and the name, */
+      token_offset = CPP_WRITTEN (pfile);
+      token = get_directive_token (pfile);
+      if (token == CPP_LPAREN)
+       {
+         token_offset = CPP_WRITTEN (pfile);
+         token = get_directive_token (pfile);
+         if (token != CPP_NAME)
+           goto restore;
+         need_rparen = 1;
+       }
+      else if (token != CPP_NAME)
+       goto restore;
+
+      ident = pfile->token_buffer + token_offset;
+      CPP_NUL_TERMINATE (pfile);
+
+      /* ...then the ')', if necessary, */
+      if ((!need_rparen || get_directive_token (pfile) == CPP_RPAREN)
+         /* ...and make sure there's nothing else on the line.  */
+         && get_directive_token (pfile) == CPP_VSPACE)
+       control_macro = xstrdup (ident);
+
+    restore:
+      CPP_SET_WRITTEN (pfile, base_offset);
+      pfile->no_macro_expand--;
+      parse_goto_mark (pfile);
+    }
+
+  return control_macro;
+}
+
 /*
  * handle #if command by
  *   1) inserting special `defined' keyword into the hash table
@@ -1593,10 +1780,11 @@ do_sccs (pfile, keyword)
 static int
 do_if (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
+  U_CHAR *control_macro = detect_if_not_defined (pfile);
   HOST_WIDEST_INT value = eval_if_expression (pfile);
-  conditional_skip (pfile, value == 0, T_IF, NULL_PTR);
+  conditional_skip (pfile, value == 0, T_IF, control_macro);
   return 0;
 }
 
@@ -1608,7 +1796,7 @@ do_if (pfile, keyword)
 static int
 do_elif (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) {
     cpp_error (pfile, "`#elif' not within a conditional");
@@ -1672,7 +1860,7 @@ eval_if_expression (pfile)
 static int
 do_xifdef (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   int skip;
   cpp_buffer *ip = CPP_BUFFER (pfile);
@@ -1710,6 +1898,11 @@ do_xifdef (pfile, keyword)
          control_macro = (U_CHAR *) xmalloc (ident_length + 1);
          bcopy (ident, control_macro, ident_length + 1);
        }
+      if (hp != NULL && hp->type == T_POISON)
+       {
+         cpp_error (pfile, "attempt to use poisoned `%s'", hp->name);
+         skip = !skip;
+       }
     }
   else
     {
@@ -1735,7 +1928,7 @@ do_xifdef (pfile, keyword)
       else {
        U_CHAR *cp = buf;
        fprintf (pcp_outfile, "#undef ");
-       while (is_idchar[*cp]) /* Ick! */
+       while (is_idchar(*cp)) /* Ick! */
          fputc (*cp++, pcp_outfile);
        putc ('\n', pcp_outfile);
       }
@@ -1761,9 +1954,7 @@ conditional_skip (pfile, skip, type, control_macro)
 
   temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
   temp->fname = CPP_BUFFER (pfile)->nominal_fname;
-#if 0
   temp->lineno = CPP_BUFFER (pfile)->lineno;
-#endif
   temp->next = pfile->if_stack;
   temp->control_macro = control_macro;
   pfile->if_stack = temp;
@@ -1790,7 +1981,7 @@ consider_directive_while_skipping (pfile, stack)
     IF_STACK_FRAME *stack; 
 {
   long ident_len, ident;
-  struct directive *kt;
+  const struct directive *kt;
   IF_STACK_FRAME *temp;
     
   cpp_skip_hspace (pfile);
@@ -1945,7 +2136,7 @@ skip_if_group (pfile)
 static int
 do_else (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
 
@@ -1987,14 +2178,14 @@ do_else (pfile, keyword)
 static int
 do_endif (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   if (CPP_PEDANTIC (pfile))
     validate_else (pfile, "#endif");
   skip_rest_of_line (pfile);
 
   if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
-    cpp_error (pfile, "unbalanced `#endif'");
+    cpp_error (pfile, "`#endif' not within a conditional");
   else
     {
       IF_STACK_FRAME *temp = pfile->if_stack;
@@ -2042,7 +2233,7 @@ do_endif (pfile, keyword)
 static void
 validate_else (pfile, directive)
      cpp_reader *pfile;
-     char *directive;
+     const char *directive;
 {
   int c;
   cpp_skip_hspace (pfile);
@@ -2052,6 +2243,25 @@ validate_else (pfile, directive)
                 "text following `%s' violates ANSI standard", directive);
 }
 
+/* Convert T_IF, etc. to a string.   Used in error messages.  */
+static const char *
+if_directive_name (pfile, ifs)
+     cpp_reader *pfile;
+     struct if_stack *ifs;
+{
+  switch (ifs->type)
+    {
+    case T_IF:     return "#if";
+    case T_IFDEF:   return "#ifdef";
+    case T_IFNDEF:  return "#ifndef";
+    case T_ELIF:    return "#elif";
+    case T_ELSE:    return "#else";
+    default:
+      cpp_fatal (pfile, "impossible if_stack->type value %d", ifs->type);
+      return "unknown";
+    }
+}
+
 /* Get the next token, and add it to the text in pfile->token_buffer.
    Return the kind of token we got.  */
   
@@ -2082,9 +2292,23 @@ cpp_get_token (pfile)
        }
       else
        {
-         cpp_buffer *next_buf
-           = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
-         CPP_BUFFER (pfile)->seen_eof = 1;
+         cpp_buffer *next_buf = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
+         struct if_stack *ifs, *nifs;
+
+         /* Unwind the conditional stack and generate error messages.  */
+         for (ifs = pfile->if_stack;
+              ifs != CPP_BUFFER (pfile)->if_stack;
+              ifs = nifs)
+           {
+             cpp_error_with_line (pfile, ifs->lineno, -1,
+                                  "unterminated `%s' conditional",
+                                  if_directive_name (pfile, ifs));
+
+             nifs = ifs->next;
+             free (ifs);
+           }
+         pfile->if_stack = ifs;
+
          if (CPP_BUFFER (pfile)->nominal_fname
              && next_buf != CPP_NULL_BUFFER (pfile))
            {
@@ -2097,6 +2321,8 @@ cpp_get_token (pfile)
              output_line_command (pfile, leave_file);
              CPP_BUFFER (pfile) = cur_buffer;
            }
+
+         CPP_BUFFER (pfile)->seen_eof = 1;
          return CPP_POP;
        }
     }
@@ -2174,6 +2400,12 @@ cpp_get_token (pfile)
 
          if (!pfile->only_seen_white)
            goto randomchar;
+         /* -traditional directives are recognized only with the # in
+            column 1.
+            XXX Layering violation.  */
+         if (CPP_TRADITIONAL (pfile)
+             && CPP_BUFFER (pfile)->cur - CPP_BUFFER (pfile)->line_base != 1)
+           goto randomchar;
          if (handle_directive (pfile))
            return CPP_DIRECTIVE;
          pfile->only_seen_white = 0;
@@ -2351,7 +2583,7 @@ cpp_get_token (pfile)
              c = PEEKC ();
              if (c == EOF)
                break;
-             if (!is_idchar[c] && c != '.'
+             if (!is_idchar(c) && c != '.'
                  && ((c2 != 'e' && c2 != 'E'
                       && ((c2 != 'p' && c2 != 'P') || CPP_C89 (pfile)))
                      || (c != '+' && c != '-')))
@@ -2376,7 +2608,7 @@ cpp_get_token (pfile)
                  c = GETC();
                  if (c == EOF)
                    goto chill_number_eof;
-                 if (!is_idchar[c])
+                 if (!is_idchar(c))
                    break;
                  CPP_PUTC (pfile, c);
                }
@@ -2498,7 +2730,7 @@ cpp_get_token (pfile)
            {
              CPP_PUTC (pfile, c);
              c = PEEKC ();
-             if (c == EOF || !is_hor_space[c])
+             if (c == EOF || !is_hspace(c))
                break;
              FORWARD(1);
            }
@@ -2594,7 +2826,7 @@ parse_name (pfile, c)
 {
   for (;;)
   {
-      if (! is_idchar[c])
+      if (! is_idchar(c))
       {
          FORWARD (-1);
          break;
@@ -2641,17 +2873,15 @@ parse_string (pfile, c)
              cpp_pop_buffer (pfile);
              continue;
            }
-         if (!CPP_TRADITIONAL (pfile))
-           {
-             cpp_error_with_line (pfile, start_line, start_column,
-                                "unterminated string or character constant");
-             if (pfile->multiline_string_line != start_line
-                 && pfile->multiline_string_line != 0)
-               cpp_error_with_line (pfile,
-                                    pfile->multiline_string_line, -1,
-                              "possible real start of unterminated constant");
-             pfile->multiline_string_line = 0;
-           }
+
+         cpp_error_with_line (pfile, start_line, start_column,
+                              "unterminated string or character constant");
+         if (pfile->multiline_string_line != start_line
+             && pfile->multiline_string_line != 0)
+           cpp_error_with_line (pfile,
+                                pfile->multiline_string_line, -1,
+                        "possible real start of unterminated constant");
+         pfile->multiline_string_line = 0;
          break;
        }
       CPP_PUTC (pfile, cc);
@@ -2660,11 +2890,17 @@ parse_string (pfile, c)
        case '\n':
          CPP_BUMP_LINE (pfile);
          pfile->lineno++;
-         /* Traditionally, end of line ends a string constant with
-            no error.  */
-         if (CPP_TRADITIONAL (pfile))
+
+         /* In Fortran and assembly language, silently terminate
+            strings of either variety at end of line.  This is a
+            kludge around not knowing where comments are in these
+            languages.  */
+         if (CPP_OPTIONS (pfile)->lang_fortran
+             || CPP_OPTIONS (pfile)->lang_asm)
            return;
-         /* Character constants may not extend over multiple lines.  */
+         /* Character constants may not extend over multiple lines.
+            In Standard C, neither may strings.  We accept multiline
+            strings as an extension.  */
          if (c == '\'')
            {
              cpp_error_with_line (pfile, start_line, start_column,
@@ -2672,10 +2908,8 @@ parse_string (pfile, c)
              return;
            }
          if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
-           {
-             cpp_pedwarn_with_line (pfile, start_line, start_column,
-                                    "string constant runs past end of line");
-           }
+           cpp_pedwarn_with_line (pfile, start_line, start_column,
+                                  "string constant runs past end of line");
          if (pfile->multiline_string_line == 0)
            pfile->multiline_string_line = start_line;
          break;
@@ -2721,7 +2955,7 @@ parse_assertion (pfile)
   int c, dropwhite;
   cpp_skip_hspace (pfile);
   c = PEEKC();
-  if (! is_idstart[c])
+  if (! is_idstart(c))
     {
       cpp_error (pfile, "assertion predicate is not an identifier");
       return 0;
@@ -2733,7 +2967,7 @@ parse_assertion (pfile)
   c = PEEKC();
   if (c != '(')
     {
-      if (is_hor_space[c] || c == '\r')
+      if (is_hspace(c) || c == '\r')
        cpp_skip_hspace (pfile);
       c = PEEKC();
     }
@@ -2745,7 +2979,7 @@ parse_assertion (pfile)
   dropwhite = 1;
   while ((c = GETC()) != ')')
     {
-      if (is_hor_space[c])
+      if (is_space(c))
        {
          if (! dropwhite)
            {
@@ -2786,7 +3020,7 @@ parse_assertion (pfile)
 static int
 do_assert (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   char *sym;
   int ret, c;
@@ -2852,7 +3086,7 @@ do_assert (pfile, keyword)
 static int
 do_unassert (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   int c, ret;
   char *sym;
@@ -2997,7 +3231,7 @@ parse_goto_mark (pfile)
   ip->mark = -1;
 }
 
-void
+static void
 cpp_print_file_and_line (pfile)
      cpp_reader *pfile;
 {
@@ -3233,12 +3467,12 @@ cpp_pedwarn_with_line VPROTO ((cpp_reader * pfile, int line, int column,
    giving specified file name and line number, not current.  */
 
 void
-cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line,
-                                       const char *msgid, ...))
+cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, const char *file,
+                                       int line, const char *msgid, ...))
 {
 #ifndef ANSI_PROTOTYPES
   cpp_reader *pfile;
-  char *file;
+  const char *file;
   int line;
   const char *msgid;
 #endif
@@ -3248,7 +3482,7 @@ cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line,
 
 #ifndef ANSI_PROTOTYPES
   pfile = va_arg (ap, cpp_reader *);
-  file = va_arg (ap, char *);
+  file = va_arg (ap, const char *);
   line = va_arg (ap, int);
   msgid = va_arg (ap, const char *);
 #endif
@@ -3265,11 +3499,11 @@ cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line,
 /* my_strerror - return the descriptive text associated with an
    `errno' code.  */
 
-static char *
+static const char *
 my_strerror (errnum)
      int errnum;
 {
-  char *result;
+  const char *result;
 
 #ifndef VMS
 #ifndef HAVE_STRERROR