Wolfgang Thallergcc16 merge934c3885 months agoHistory
3385 lines · 97.8 KB · C++
RawDownload
/* CPP Library. (Directive handling.)   Copyright (C) 1986-2026 Free Software Foundation, Inc.   Contributed by Per Bothner, 1994-95.   Based on CCCP program by Paul Rubin, June 1986   Adapted to ANSI C, Richard Stallman, Jan 1987 This program is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 3, or (at your option) anylater version. This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details. You should have received a copy of the GNU General Public Licensealong with this program; see the file COPYING3.  If not see<http://www.gnu.org/licenses/>.  */ #include "config.h"#include "system.h"#include "cpplib.h"#include "internal.h"#include "mkdeps.h"#include "obstack.h" /* Stack of conditionals currently in progress   (including both successful and failing conditionals).  */struct if_stack{  struct if_stack *next;  location_t line;		/* Line where condition started.  */  location_t def_loc;		/* Locus of the following #define if any.  */  const cpp_hashnode *mi_cmacro;/* Macro name for #ifndef around entire				   file.  */  const cpp_hashnode *mi_def_cmacro;  /* Macro name in the following					 #define.  */  bool skip_elses;		/* Can future #else / #elif be skipped?  */  bool was_skipping;		/* If were skipping on entry.  */  int type;			/* Most recent conditional for diagnostics.  */}; /* Contains a registered pragma or pragma namespace.  */typedef void (*pragma_cb) (cpp_reader *);struct pragma_entry{  struct pragma_entry *next;  const cpp_hashnode *pragma;	/* Name and length.  */  bool is_nspace;  bool is_internal;  bool is_deferred;  bool allow_expansion;  union {    pragma_cb handler;    struct pragma_entry *space;    unsigned int ident;  } u;}; /* Values for the origin field of struct directive.  KANDR directives   come from traditional (K&R) C.  STDC89 directives come from the   1989 C standard.  STDC23 directives come from the C23 standard.  EXTENSION   directives are extensions.  */#define KANDR		0#define STDC89		1#define STDC23		2#define EXTENSION	3 /* Values for the flags field of struct directive.  COND indicates a   conditional; IF_COND an opening conditional.  INCL means to treat   "..." and <...> as q-char and h-char sequences respectively.  IN_I   means this directive should be handled even if -fpreprocessed is in   effect (these are the directives with callback hooks).    EXPAND is set on directives that are always macro-expanded.    ELIFDEF is set on directives that are only handled for standards with the   #elifdef / #elifndef feature.  */#define COND		(1 << 0)#define IF_COND		(1 << 1)#define INCL		(1 << 2)#define IN_I		(1 << 3)#define EXPAND		(1 << 4)#define DEPRECATED	(1 << 5)#define ELIFDEF		(1 << 6) /* Defines one #-directive, including how to handle it.  */typedef void (*directive_handler) (cpp_reader *);typedef struct directive directive;struct directive{  directive_handler handler;	/* Function to handle directive.  */  const uchar *name;		/* Name of directive.  */  unsigned short length;	/* Length of name.  */  unsigned char origin;		/* Origin of directive.  */  unsigned char flags;	        /* Flags describing this directive.  */}; /* Forward declarations.  */ static void skip_rest_of_line (cpp_reader *);static void check_eol (cpp_reader *, bool);static void start_directive (cpp_reader *);static void prepare_directive_trad (cpp_reader *);static void end_directive (cpp_reader *, int);static void directive_diagnostics (cpp_reader *, const directive *, int);static void run_directive (cpp_reader *, int, const char *, size_t);static char *glue_header_name (cpp_reader *);static const char *parse_include (cpp_reader *, int *, const cpp_token ***,				  location_t *);static void push_conditional (cpp_reader *, int, int, const cpp_hashnode *);static unsigned int read_flag (cpp_reader *, unsigned int);static bool strtolinenum (const uchar *, size_t, linenum_type *, bool *);static void do_diagnostic (cpp_reader *, enum cpp_diagnostic_level code,			   enum cpp_warning_reason reason, int);static cpp_hashnode *lex_macro_node (cpp_reader *, bool);static int undefine_macros (cpp_reader *, cpp_hashnode *, void *);static void do_include_common (cpp_reader *, enum include_type);static struct pragma_entry *lookup_pragma_entry (struct pragma_entry *,                                                 const cpp_hashnode *);static int count_registered_pragmas (struct pragma_entry *);static char ** save_registered_pragmas (struct pragma_entry *, char **);static char ** restore_registered_pragmas (cpp_reader *, struct pragma_entry *,                                           char **);static void do_pragma_once (cpp_reader *);static void do_pragma_poison (cpp_reader *);static void do_pragma_system_header (cpp_reader *);static void do_pragma_dependency (cpp_reader *);static void do_pragma_warning_or_error (cpp_reader *, bool error);static void do_pragma_warning (cpp_reader *);static void do_pragma_error (cpp_reader *);static void do_linemarker (cpp_reader *);static const cpp_token *get_token_no_padding (cpp_reader *);static const cpp_token *get__Pragma_string (cpp_reader *);static void destringize_and_run (cpp_reader *, const cpp_string *,				 location_t);static bool parse_answer (cpp_reader *, int, location_t, cpp_macro **);static cpp_hashnode *parse_assertion (cpp_reader *, int, cpp_macro **);static cpp_macro **find_answer (cpp_hashnode *, const cpp_macro *);static void handle_assertion (cpp_reader *, const char *, int);static void do_pragma_push_macro (cpp_reader *);static void do_pragma_pop_macro (cpp_reader *);static void cpp_pop_definition (cpp_reader *, def_pragma_macro *,				cpp_hashnode *); /* This is the table of directive handlers.  All extensions other than   #warning, #include_next, and #import are deprecated.  The name is   where the extension appears to have come from.  */ #define DIRECTIVE_TABLE							\  D(define,	T_DEFINE = 0,	KANDR,     IN_I | IF_COND)		\  D(include,	T_INCLUDE,	KANDR,     INCL | EXPAND)		\  D(endif,	T_ENDIF,	KANDR,     COND)			\  D(ifdef,	T_IFDEF,	KANDR,     COND | IF_COND)		\  D(if,		T_IF,		KANDR, 	   COND | IF_COND | EXPAND) 	\  D(else,	T_ELSE,		KANDR,     COND)	   		\  D(ifndef,	T_IFNDEF,	KANDR,     COND | IF_COND)		\  D(undef,	T_UNDEF,	KANDR,     IN_I)			\  D(line,	T_LINE,		KANDR,     EXPAND)			\  D(elif,	T_ELIF,		STDC89,    COND | EXPAND)		\  D(elifdef,	T_ELIFDEF,	STDC23,    COND | ELIFDEF)		\  D(elifndef,	T_ELIFNDEF,	STDC23,    COND | ELIFDEF)		\  D(error,	T_ERROR,	STDC89,    0)				\  D(pragma,	T_PRAGMA,	STDC89,    IN_I)			\  D(warning,	T_WARNING,	STDC23,    0)				\  D(embed,	T_EMBED,	STDC23,    IN_I | INCL | EXPAND)	\  D(include_next, T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND)		\  D(ident,	T_IDENT,	EXTENSION, IN_I)			\  D(import,	T_IMPORT,	EXTENSION, INCL | EXPAND)  /* ObjC */	\  D(assert,	T_ASSERT,	EXTENSION, DEPRECATED)	   /* SVR4 */	\  D(unassert,	T_UNASSERT,	EXTENSION, DEPRECATED)	   /* SVR4 */	\  D(sccs,	T_SCCS,		EXTENSION, IN_I)   	   /*  SVR4? */ /* #sccs is synonymous with #ident.  */#define do_sccs do_ident /* Use the table to generate a series of prototypes, an enum for the   directive names, and an array of directive handlers.  */ #define D(name, t, o, f) static void do_##name (cpp_reader *);DIRECTIVE_TABLE#undef D #define D(n, tag, o, f) tag,enum{  DIRECTIVE_TABLE  N_DIRECTIVES};#undef D #define D(name, t, origin, flags) \{ do_##name, (const uchar *) #name, \  sizeof #name - 1, origin, flags },static const directive dtable[] ={DIRECTIVE_TABLE};#undef D /* A NULL-terminated array of directive names for use   when suggesting corrections for misspelled directives.  */#define D(name, t, origin, flags) #name,static const char * const directive_names[] = {DIRECTIVE_TABLE  NULL};#undef D #undef DIRECTIVE_TABLE /* Wrapper struct directive for linemarkers.   The origin is more or less true - the original K+R cpp   did use this notation in its preprocessed output.  */static const directive linemarker_dir ={  do_linemarker, UC"#", 1, KANDR, IN_I}; /* Skip any remaining tokens in a directive.  */static voidskip_rest_of_line (cpp_reader *pfile){  /* Discard all stacked contexts.  */  while (pfile->context->prev)    _cpp_pop_context (pfile);   /* Sweep up all tokens remaining on the line.  */  if (! SEEN_EOL ())    while (_cpp_lex_token (pfile)->type != CPP_EOF)      ;} /* Helper function for check_oel.  */ static voidcheck_eol_1 (cpp_reader *pfile, bool expand, enum cpp_warning_reason reason){  if (! SEEN_EOL () && (expand			? cpp_get_token (pfile)			: _cpp_lex_token (pfile))->type != CPP_EOF)    cpp_pedwarning (pfile, reason, "extra tokens at end of %<#%s%> directive",		    pfile->directive->name);} /* Variant of check_eol used for Wendif-labels warnings.  */ static voidcheck_eol_endif_labels (cpp_reader *pfile){  check_eol_1 (pfile, false, CPP_W_ENDIF_LABELS);} /* Ensure there are no stray tokens at the end of a directive.  If   EXPAND is true, tokens macro-expanding to nothing are allowed.  */ static voidcheck_eol (cpp_reader *pfile, bool expand){  check_eol_1 (pfile, expand, CPP_W_NONE);} /* Ensure there are no stray tokens other than comments at the end of   a directive, and gather the comments.  */static const cpp_token **check_eol_return_comments (cpp_reader *pfile){  size_t c;  size_t capacity = 8;  const cpp_token **buf;   buf = XNEWVEC (const cpp_token *, capacity);  c = 0;  if (! SEEN_EOL ())    {      while (1)	{	  const cpp_token *tok; 	  tok = _cpp_lex_token (pfile);	  if (tok->type == CPP_EOF)	    break;	  if (tok->type != CPP_COMMENT)	    cpp_error (pfile, CPP_DL_PEDWARN,		       "extra tokens at end of #%s directive",		       pfile->directive->name);	  else	    {	      if (c + 1 >= capacity)		{		  capacity *= 2;		  buf = XRESIZEVEC (const cpp_token *, buf, capacity);		}	      buf[c] = tok;	      ++c;	    }	}    }  buf[c] = NULL;  return buf;} /* Called when entering a directive, _Pragma or command-line directive.  */static voidstart_directive (cpp_reader *pfile){  /* Setup in-directive state.  */  pfile->state.in_directive = 1;  pfile->state.save_comments = 0;  pfile->directive_result.type = CPP_PADDING;   /* Some handlers need the position of the # for diagnostics.  */  pfile->directive_line = pfile->line_table->highest_line;} /* Called when leaving a directive, _Pragma or command-line directive.  */static voidend_directive (cpp_reader *pfile, int skip_line){  if (CPP_OPTION (pfile, traditional))    {      /* Revert change of prepare_directive_trad.  */      if (!pfile->state.in_deferred_pragma)	pfile->state.prevent_expansion--;       if (pfile->directive != &dtable[T_DEFINE])	_cpp_remove_overlay (pfile);    }  else if (pfile->state.in_deferred_pragma)    ;  /* We don't skip for an assembler #.  */  else if (skip_line)    {      if (pfile->directive != &dtable[T_EMBED])	skip_rest_of_line (pfile);      if (!pfile->keep_tokens)	{	  pfile->cur_run = &pfile->base_run;	  pfile->cur_token = pfile->base_run.base;	}    }   /* Restore state.  */  pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);  pfile->state.in_directive = 0;  pfile->state.in_expression = 0;  pfile->state.angled_headers = 0;  pfile->directive = 0;} /* Prepare to handle the directive in pfile->directive.  */static voidprepare_directive_trad (cpp_reader *pfile){  if (pfile->directive != &dtable[T_DEFINE])    {      bool no_expand = (pfile->directive			&& ! (pfile->directive->flags & EXPAND));      bool was_skipping = pfile->state.skipping;       pfile->state.in_expression = (pfile->directive == &dtable[T_IF]				    || pfile->directive == &dtable[T_ELIF]);      if (pfile->state.in_expression)	pfile->state.skipping = false;       if (no_expand)	pfile->state.prevent_expansion++;      _cpp_scan_out_logical_line (pfile, NULL, false);      if (no_expand)	pfile->state.prevent_expansion--;       pfile->state.skipping = was_skipping;      _cpp_overlay_buffer (pfile, pfile->out.base,			   pfile->out.cur - pfile->out.base);    }   /* Stop ISO C from expanding anything.  */  pfile->state.prevent_expansion++;} /* Output diagnostics for a directive DIR.  INDENTED is nonzero if   the '#' was indented.  */static voiddirective_diagnostics (cpp_reader *pfile, const directive *dir, int indented){  /* Issue -pedantic or deprecated warnings for extensions.  We let     -pedantic take precedence if both are applicable.  */  if (! pfile->state.skipping)    {      bool warned = false;      if (dir->origin == EXTENSION	  && !(dir == &dtable[T_IMPORT] && CPP_OPTION (pfile, objc)))	warned	  = cpp_pedwarning (pfile, CPP_W_PEDANTIC,			    "%<#%s%> is a GCC extension", dir->name);      if (!warned && dir == &dtable[T_WARNING])	{	  if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, warning_directive))	    {	      if (CPP_OPTION (pfile, cplusplus))		warned		  = cpp_pedwarning (pfile, CPP_W_CXX23_EXTENSIONS,				    "%<#%s%> before C++23 is a GCC extension",				    dir->name);	      else		warned		  = cpp_pedwarning (pfile, CPP_W_PEDANTIC,				    "%<#%s%> before C23 is a GCC extension",				    dir->name);	    } 	  if (!warned && CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0)	    warned = cpp_warning (pfile, CPP_W_C11_C23_COMPAT,				  "%<#%s%> before C23 is a GCC extension",				  dir->name);	}       if (((dir->flags & DEPRECATED) != 0	   || (dir == &dtable[T_IMPORT] && !CPP_OPTION (pfile, objc)))	  && !warned)	cpp_warning (pfile, CPP_W_DEPRECATED,                     "%<#%s%> is a deprecated GCC extension", dir->name);    }   /* Traditionally, a directive is ignored unless its # is in     column 1.  Therefore in code intended to work with K+R     compilers, directives added by C89 must have their #     indented, and directives present in traditional C must not.     This is true even of directives in skipped conditional     blocks.  #elif cannot be used at all.  */  if (CPP_WTRADITIONAL (pfile))    {      if (dir == &dtable[T_ELIF])	cpp_warning (pfile, CPP_W_TRADITIONAL,		     "suggest not using %<#elif%> in traditional C");      else if (indented && dir->origin == KANDR)	cpp_warning (pfile, CPP_W_TRADITIONAL,		     "traditional C ignores %<#%s%> with the %<#%> indented",		     dir->name);      else if (!indented && dir->origin != KANDR)	cpp_warning (pfile, CPP_W_TRADITIONAL,		     "suggest hiding %<#%s%> from traditional C with an "		     "indented %<#%>", dir->name);    }} /* Check if we have a known directive.  INDENTED is true if the   '#' of the directive was indented.  This function is in this file   to save unnecessarily exporting dtable etc. to lex.cc.  Returns   nonzero if the line of tokens has been handled, zero if we should   continue processing the line.  */int_cpp_handle_directive (cpp_reader *pfile, bool indented){  const directive *dir = 0;  const cpp_token *dname;  bool was_parsing_args = pfile->state.parsing_args;  bool was_discarding_output = pfile->state.discarding_output;  int skip = 1;   if (was_discarding_output)    pfile->state.prevent_expansion = 0;   if (was_parsing_args)    {      cpp_pedwarning (pfile, CPP_W_PEDANTIC,		      "embedding a directive within macro arguments is not "		      "portable");      pfile->state.parsing_args = 0;      pfile->state.prevent_expansion = 0;    }  start_directive (pfile);  dname = _cpp_lex_token (pfile);   if (dname->type == CPP_NAME)    {      if (dname->val.node.node->is_directive)	{	  dir = &dtable[dname->val.node.node->directive_index];	  if ((dir->flags & ELIFDEF)	      && !CPP_OPTION (pfile, elifdef)	      /* For -std=gnu* modes elifdef is supported with		 a pedwarn if pedantic.  */	      && CPP_OPTION (pfile, std))	    dir = 0;	}    }  /* We do not recognize the # followed by a number extension in     assembler code.  */  else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM)    {      dir = &linemarker_dir;      if (! CPP_OPTION (pfile, preprocessed)	  && ! pfile->state.skipping)	cpp_pedwarning (pfile, CPP_W_PEDANTIC,			"style of line directive is a GCC extension");    }   if (dir)

Lines 1–500 of 3385.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t