/* Type Analyzer for GNU C++.
- Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Hacked... nay, bludgeoned... by Mark Eichin (eichin@cygnus.com)
This file is part of GNU CC.
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. */
-
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This file is the type analyzer for GNU C++. To debug it, define SPEW_DEBUG
when compiling parse.c and spew.c. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "input.h"
#include "tree.h"
+#include "cp-tree.h"
+#include "cpplib.h"
+#include "c-pragma.h"
#include "lex.h"
#include "parse.h"
-#include "cp-tree.h"
#include "flags.h"
#include "obstack.h"
+#include "toplev.h"
+#include "ggc.h"
+#include "intl.h"
+#include "timevar.h"
+
+#ifdef SPEW_DEBUG
+#define SPEW_INLINE
+#else
+#define SPEW_INLINE inline
+#endif
/* This takes a token stream that hasn't decided much about types and
tries to figure out as much as it can, with excessive lookahead and
- backtracking. */
+ backtracking. */
-/* fifo of tokens recognized and available to parser. */
-struct token {
+/* fifo of tokens recognized and available to parser. */
+struct token GTY(())
+{
/* The values for YYCHAR will fit in a short. */
short yychar;
- short end_of_file;
- YYSTYPE yylval;
+ unsigned int lineno;
+ YYSTYPE GTY ((desc ("%1.yychar"))) yylval;
+};
+
+/* Since inline methods can refer to text which has not yet been seen,
+ we store the text of the method in a structure which is placed in the
+ DECL_PENDING_INLINE_INFO field of the FUNCTION_DECL.
+ After parsing the body of the class definition, the FUNCTION_DECL's are
+ scanned to see which ones have this field set. Those are then digested
+ one at a time.
+
+ This function's FUNCTION_DECL will have a bit set in its common so
+ that we know to watch out for it. */
+
+#define TOKEN_CHUNK_SIZE 20
+struct token_chunk GTY(())
+{
+ struct token_chunk *next;
+ struct token toks[TOKEN_CHUNK_SIZE];
+};
+
+struct unparsed_text GTY(())
+{
+ struct unparsed_text *next; /* process this one next */
+ tree decl; /* associated declaration */
+ location_t locus; /* location we got the text from */
+ int interface; /* remembering interface_unknown and interface_only */
+
+ struct token_chunk * tokens; /* Start of the token list. */
+
+ struct token_chunk *last_chunk; /* End of the token list. */
+ short last_pos; /* Number of tokens used in the last chunk of
+ TOKENS. */
+
+ short cur_pos; /* Current token in 'cur_chunk', when rescanning. */
+ struct token_chunk *cur_chunk; /* Current chunk, when rescanning. */
+};
+
+/* Stack of state saved off when we return to an inline method or
+ default argument that has been stored for later parsing. */
+struct feed GTY(())
+{
+ struct unparsed_text *input;
+ location_t locus;
+ int yychar;
+ YYSTYPE GTY ((desc ("%1.yychar"))) yylval;
+ int first_token;
+ struct obstack GTY ((skip (""))) token_obstack;
+ struct feed *next;
};
-static int do_aggr ();
+static GTY(()) struct feed *feed;
+
+static SPEW_INLINE void do_aggr PARAMS ((void));
+static SPEW_INLINE int identifier_type PARAMS ((tree));
+static void scan_tokens PARAMS ((int));
+static void feed_defarg PARAMS ((tree));
+static void finish_defarg PARAMS ((void));
+static void yylexstring PARAMS ((struct token *));
+static int read_token PARAMS ((struct token *));
+
+static SPEW_INLINE int num_tokens PARAMS ((void));
+static SPEW_INLINE struct token *nth_token PARAMS ((int));
+static SPEW_INLINE int next_token PARAMS ((struct token *));
+static SPEW_INLINE int shift_token PARAMS ((void));
+static SPEW_INLINE void push_token PARAMS ((struct token *));
+static SPEW_INLINE void consume_token PARAMS ((void));
+static SPEW_INLINE int read_process_identifier PARAMS ((YYSTYPE *));
+
+static SPEW_INLINE void feed_input PARAMS ((struct unparsed_text *));
+static SPEW_INLINE struct token * space_for_token
+ PARAMS ((struct unparsed_text *t));
+static SPEW_INLINE struct token * remove_last_token
+ PARAMS ((struct unparsed_text *t));
+static struct unparsed_text * alloc_unparsed_text
+ PARAMS ((const location_t *, tree decl, int interface));
+
+static void snarf_block PARAMS ((struct unparsed_text *t));
+static tree snarf_defarg PARAMS ((void));
+static int frob_id PARAMS ((int, int, tree *));
+
+/* The list of inline functions being held off until we reach the end of
+ the current class declaration. */
+static GTY(()) struct unparsed_text *pending_inlines;
+static GTY(()) struct unparsed_text *pending_inlines_tail;
+
+/* The list of previously-deferred inline functions currently being parsed.
+ This exists solely to be a GC root. */
+static GTY(()) struct unparsed_text *processing_these_inlines;
+
+static void begin_parsing_inclass_inline PARAMS ((struct unparsed_text *));
+
+#ifdef SPEW_DEBUG
+int spew_debug = 0;
+static unsigned int yylex_ctr = 0;
+
+static void debug_yychar PARAMS ((int));
+
+/* In parse.y: */
+extern char *debug_yytranslate PARAMS ((int));
+#endif
+static enum cpp_ttype last_token;
+static tree last_token_id;
/* From lex.c: */
-/* the declaration found for the last IDENTIFIER token read in.
- yylex must look this up to detect typedefs, which get token type TYPENAME,
- so it is left around in case the identifier is not a typedef but is
- used in a context which makes it a reference to a variable. */
+/* the declaration found for the last IDENTIFIER token read in. yylex
+ must look this up to detect typedefs, which get token type
+ tTYPENAME, so it is left around in case the identifier is not a
+ typedef but is used in a context which makes it a reference to a
+ variable. */
extern tree lastiddecl; /* let our brains leak out here too */
extern int yychar; /* the lookahead symbol */
extern YYSTYPE yylval; /* the semantic value of the */
/* lookahead symbol */
-extern int end_of_file;
+/* The token fifo lives in this obstack. */
+static struct obstack token_obstack;
+static int first_token;
-struct obstack token_obstack;
-int first_token;
-
-#ifdef SPEW_DEBUG
-int spew_debug = 0;
-static unsigned int yylex_ctr = 0;
-static int debug_yychar ();
-#endif
+/* When we see a default argument in a method declaration, we snarf it as
+ text using snarf_defarg. When we get up to namespace scope, we then go
+ through and parse all of them using do_pending_defargs. Since yacc
+ parsers are not reentrant, we retain defargs state in these two
+ variables so that subsequent calls to do_pending_defargs can resume
+ where the previous call left off. DEFARG_FNS is a tree_list where
+ the TREE_TYPE is the current_class_type, TREE_VALUE is the FUNCTION_DECL,
+ and TREE_PURPOSE is the list unprocessed dependent functions. */
+
+/* list of functions with unprocessed defargs */
+static GTY(()) tree defarg_fns;
+/* current default parameter */
+static GTY(()) tree defarg_parm;
+/* list of unprocessed fns met during current fn. */
+static GTY(()) tree defarg_depfns;
+/* list of fns with circular defargs */
+static GTY(()) tree defarg_fnsdone;
+
+/* Initialize obstacks. Called once, from cxx_init. */
-/* Initialize token_obstack. Called once, from init_lex. */
void
init_spew ()
{
- gcc_obstack_init(&token_obstack);
+ gcc_obstack_init (&token_obstack);
}
-#ifdef SPEW_DEBUG
-/* Use functions for debugging... */
+/* Subroutine of read_token. */
+static SPEW_INLINE int
+read_process_identifier (pyylval)
+ YYSTYPE *pyylval;
+{
+ tree id = pyylval->ttype;
+
+ if (C_IS_RESERVED_WORD (id))
+ {
+ pyylval->ttype = ridpointers[C_RID_CODE (id)];
+ return C_RID_YYCODE (id);
+ }
+
+ /* Make sure that user does not collide with our internal naming
+ scheme. This is not necessary if '.' is used to remove them from
+ the user's namespace, but is if '$' or double underscores are. */
+
+#if !defined(JOINER) || JOINER == '$'
+ if (VPTR_NAME_P (id)
+ || VTABLE_NAME_P (id)
+ || TEMP_NAME_P (id)
+ || ANON_AGGRNAME_P (id))
+ warning (
+"identifier name `%s' conflicts with GNU C++ internal naming strategy",
+ IDENTIFIER_POINTER (id));
+#endif
+ return IDENTIFIER;
+}
+
+/* Concatenate strings before returning them to the parser. This isn't quite
+ as good as having it done in the lexer, but it's better than nothing. */
+
+static void
+yylexstring (t)
+ struct token *t;
+{
+ enum cpp_ttype next_type;
+ tree next;
+
+ next_type = c_lex (&next);
+ if (next_type == CPP_STRING || next_type == CPP_WSTRING)
+ {
+ varray_type strings;
+
+ VARRAY_TREE_INIT (strings, 32, "strings");
+ VARRAY_PUSH_TREE (strings, t->yylval.ttype);
+
+ do
+ {
+ VARRAY_PUSH_TREE (strings, next);
+ next_type = c_lex (&next);
+ }
+ while (next_type == CPP_STRING || next_type == CPP_WSTRING);
+
+ t->yylval.ttype = combine_strings (strings);
+ last_token_id = t->yylval.ttype;
+ }
-/* Return the number of tokens available on the fifo. */
+ /* We will have always read one token too many. */
+ _cpp_backup_tokens (parse_in, 1);
+
+ t->yychar = STRING;
+}
+
+/* Read the next token from the input file. The token is written into
+ T, and its type number is returned. */
static int
+read_token (t)
+ struct token *t;
+{
+ retry:
+
+ last_token = c_lex (&last_token_id);
+ t->yylval.ttype = last_token_id;
+
+ switch (last_token)
+ {
+#define YYCHAR(YY) t->yychar = (YY); break;
+#define YYCODE(C) t->yylval.code = (C);
+
+ case CPP_EQ: YYCHAR('=');
+ case CPP_NOT: YYCHAR('!');
+ case CPP_GREATER: YYCODE(GT_EXPR); YYCHAR('>');
+ case CPP_LESS: YYCODE(LT_EXPR); YYCHAR('<');
+ case CPP_PLUS: YYCODE(PLUS_EXPR); YYCHAR('+');
+ case CPP_MINUS: YYCODE(MINUS_EXPR); YYCHAR('-');
+ case CPP_MULT: YYCODE(MULT_EXPR); YYCHAR('*');
+ case CPP_DIV: YYCODE(TRUNC_DIV_EXPR); YYCHAR('/');
+ case CPP_MOD: YYCODE(TRUNC_MOD_EXPR); YYCHAR('%');
+ case CPP_AND: YYCODE(BIT_AND_EXPR); YYCHAR('&');
+ case CPP_OR: YYCODE(BIT_IOR_EXPR); YYCHAR('|');
+ case CPP_XOR: YYCODE(BIT_XOR_EXPR); YYCHAR('^');
+ case CPP_RSHIFT: YYCODE(RSHIFT_EXPR); YYCHAR(RSHIFT);
+ case CPP_LSHIFT: YYCODE(LSHIFT_EXPR); YYCHAR(LSHIFT);
+
+ case CPP_COMPL: YYCHAR('~');
+ case CPP_AND_AND: YYCHAR(ANDAND);
+ case CPP_OR_OR: YYCHAR(OROR);
+ case CPP_QUERY: YYCHAR('?');
+ case CPP_COLON: YYCHAR(':');
+ case CPP_COMMA: YYCHAR(',');
+ case CPP_OPEN_PAREN: YYCHAR('(');
+ case CPP_CLOSE_PAREN: YYCHAR(')');
+ case CPP_EQ_EQ: YYCODE(EQ_EXPR); YYCHAR(EQCOMPARE);
+ case CPP_NOT_EQ: YYCODE(NE_EXPR); YYCHAR(EQCOMPARE);
+ case CPP_GREATER_EQ:YYCODE(GE_EXPR); YYCHAR(ARITHCOMPARE);
+ case CPP_LESS_EQ: YYCODE(LE_EXPR); YYCHAR(ARITHCOMPARE);
+
+ case CPP_PLUS_EQ: YYCODE(PLUS_EXPR); YYCHAR(ASSIGN);
+ case CPP_MINUS_EQ: YYCODE(MINUS_EXPR); YYCHAR(ASSIGN);
+ case CPP_MULT_EQ: YYCODE(MULT_EXPR); YYCHAR(ASSIGN);
+ case CPP_DIV_EQ: YYCODE(TRUNC_DIV_EXPR); YYCHAR(ASSIGN);
+ case CPP_MOD_EQ: YYCODE(TRUNC_MOD_EXPR); YYCHAR(ASSIGN);
+ case CPP_AND_EQ: YYCODE(BIT_AND_EXPR); YYCHAR(ASSIGN);
+ case CPP_OR_EQ: YYCODE(BIT_IOR_EXPR); YYCHAR(ASSIGN);
+ case CPP_XOR_EQ: YYCODE(BIT_XOR_EXPR); YYCHAR(ASSIGN);
+ case CPP_RSHIFT_EQ: YYCODE(RSHIFT_EXPR); YYCHAR(ASSIGN);
+ case CPP_LSHIFT_EQ: YYCODE(LSHIFT_EXPR); YYCHAR(ASSIGN);
+
+ case CPP_OPEN_SQUARE: YYCHAR('[');
+ case CPP_CLOSE_SQUARE: YYCHAR(']');
+ case CPP_OPEN_BRACE: YYCHAR('{');
+ case CPP_CLOSE_BRACE: YYCHAR('}');
+ case CPP_SEMICOLON: YYCHAR(';');
+ case CPP_ELLIPSIS: YYCHAR(ELLIPSIS);
+
+ case CPP_PLUS_PLUS: YYCHAR(PLUSPLUS);
+ case CPP_MINUS_MINUS: YYCHAR(MINUSMINUS);
+ case CPP_DEREF: YYCHAR(POINTSAT);
+ case CPP_DOT: YYCHAR('.');
+
+ /* These tokens are C++ specific. */
+ case CPP_SCOPE: YYCHAR(SCOPE);
+ case CPP_DEREF_STAR: YYCHAR(POINTSAT_STAR);
+ case CPP_DOT_STAR: YYCHAR(DOT_STAR);
+ case CPP_MIN_EQ: YYCODE(MIN_EXPR); YYCHAR(ASSIGN);
+ case CPP_MAX_EQ: YYCODE(MAX_EXPR); YYCHAR(ASSIGN);
+ case CPP_MIN: YYCODE(MIN_EXPR); YYCHAR(MIN_MAX);
+ case CPP_MAX: YYCODE(MAX_EXPR); YYCHAR(MIN_MAX);
+#undef YYCHAR
+#undef YYCODE
+
+ case CPP_EOF:
+ t->yychar = 0;
+ break;
+
+ case CPP_NAME:
+ t->yychar = read_process_identifier (&t->yylval);
+ break;
+
+ case CPP_NUMBER:
+ case CPP_CHAR:
+ case CPP_WCHAR:
+ t->yychar = CONSTANT;
+ break;
+
+ case CPP_STRING:
+ case CPP_WSTRING:
+ yylexstring (t);
+ break;
+
+ default:
+ yyerror ("parse error");
+ goto retry;
+ }
+
+ t->lineno = lineno;
+ return t->yychar;
+}
+
+static void
+feed_input (input)
+ struct unparsed_text *input;
+{
+ struct feed *f;
+#if 0
+ if (feed)
+ abort ();
+#endif
+
+ f = ggc_alloc (sizeof (struct feed));
+
+ input->cur_chunk = input->tokens;
+ input->cur_pos = 0;
+
+#ifdef SPEW_DEBUG
+ if (spew_debug)
+ fprintf (stderr, "\tfeeding %s:%d [%d tokens]\n",
+ input->locus.file, input->locus.line, input->limit - input->pos);
+#endif
+
+ f->input = input;
+ f->locus.file = input_filename;
+ f->locus.line = lineno;
+ f->yychar = yychar;
+ f->yylval = yylval;
+ f->first_token = first_token;
+ f->token_obstack = token_obstack;
+ f->next = feed;
+
+ input_filename = input->locus.file;
+ lineno = input->locus.line;
+ yychar = YYEMPTY;
+ yylval.ttype = NULL_TREE;
+ first_token = 0;
+ gcc_obstack_init (&token_obstack);
+ feed = f;
+}
+
+void
+end_input ()
+{
+ struct feed *f = feed;
+
+ input_filename = f->locus.file;
+ lineno = f->locus.line;
+ yychar = f->yychar;
+ yylval = f->yylval;
+ first_token = f->first_token;
+ obstack_free (&token_obstack, 0);
+ token_obstack = f->token_obstack;
+ feed = f->next;
+
+#ifdef SPEW_DEBUG
+ if (spew_debug)
+ fprintf (stderr, "\treturning to %s:%d\n", input_filename, lineno);
+#endif
+}
+
+/* Token queue management. */
+
+/* Return the number of tokens available on the fifo. */
+static SPEW_INLINE int
num_tokens ()
{
- return (obstack_object_size(&token_obstack)/sizeof(struct token))
+ return (obstack_object_size (&token_obstack) / sizeof (struct token))
- first_token;
}
-/* Fetch the token N down the line from the head of the fifo. */
-static struct token*
+/* Fetch the token N down the line from the head of the fifo. */
+
+static SPEW_INLINE struct token*
nth_token (n)
int n;
{
+#ifdef ENABLE_CHECKING
/* could just have this do slurp_ implicitly, but this way is easier
- * to debug... */
- my_friendly_assert (n < num_tokens(), 298);
- return ((struct token*)obstack_base(&token_obstack))+n+first_token;
+ to debug... */
+ my_friendly_assert (n >= 0 && n < num_tokens (), 298);
+#endif
+ return ((struct token*)obstack_base (&token_obstack)) + n + first_token;
}
-/* Add a token to the token fifo. */
-static void
-add_token (t)
- struct token* t;
+static const struct token Teosi = { END_OF_SAVED_INPUT, 0 UNION_INIT_ZERO };
+static const struct token Tpad = { EMPTY, 0 UNION_INIT_ZERO };
+
+/* Copy the next token into T and return its value. */
+static SPEW_INLINE int
+next_token (t)
+ struct token *t;
{
- obstack_grow(&token_obstack,t,sizeof (struct token));
+ if (!feed)
+ return read_token (t);
+
+ if (feed->input->cur_chunk != feed->input->last_chunk
+ || feed->input->cur_pos != feed->input->last_pos)
+ {
+ if (feed->input->cur_pos == TOKEN_CHUNK_SIZE)
+ {
+ feed->input->cur_chunk = feed->input->cur_chunk->next;
+ feed->input->cur_pos = 0;
+ }
+ memcpy (t, feed->input->cur_chunk->toks + feed->input->cur_pos,
+ sizeof (struct token));
+ feed->input->cur_pos++;
+ return t->yychar;
+ }
+
+ memcpy (t, &Teosi, sizeof (struct token));
+ return END_OF_SAVED_INPUT;
+}
+
+/* Shift the next token onto the fifo. */
+static SPEW_INLINE int
+shift_token ()
+{
+ size_t point = obstack_object_size (&token_obstack);
+ obstack_blank (&token_obstack, sizeof (struct token));
+ return next_token ((struct token *) (obstack_base (&token_obstack) + point));
}
/* Consume the next token out of the fifo. */
-static void
-consume_token()
+
+static SPEW_INLINE void
+consume_token ()
{
- if (num_tokens() == 1)
+ if (num_tokens () == 1)
{
- obstack_free(&token_obstack, obstack_base (&token_obstack));
+ obstack_free (&token_obstack, obstack_base (&token_obstack));
first_token = 0;
}
else
first_token++;
}
-#else
-/* ...otherwise use macros. */
-
-#define num_tokens() \
- ((obstack_object_size(&token_obstack)/sizeof(struct token)) - first_token)
-
-#define nth_token(N) \
- (((struct token*)obstack_base(&token_obstack))+(N)+first_token)
-
-#define add_token(T) obstack_grow(&token_obstack, (T), sizeof (struct token))
+/* Push a token at the head of the queue; it will be the next token read. */
+static SPEW_INLINE void
+push_token (t)
+ struct token *t;
+{
+ if (first_token == 0) /* We hope this doesn't happen often. */
+ {
+ size_t active = obstack_object_size (&token_obstack);
+ obstack_blank (&token_obstack, sizeof (struct token));
+ if (active)
+ memmove (obstack_base (&token_obstack) + sizeof (struct token),
+ obstack_base (&token_obstack), active);
+ first_token++;
+ }
+ first_token--;
+ memcpy (nth_token (0), t, sizeof (struct token));
+}
-#define consume_token() \
- (num_tokens() == 1 \
- ? (obstack_free (&token_obstack, obstack_base (&token_obstack)), \
- (first_token = 0)) \
- : first_token++)
-#endif
-/* Pull in enough tokens from real_yylex that the queue is N long beyond
- the current token. */
+/* Pull in enough tokens that the queue is N long beyond the current
+ token. */
static void
scan_tokens (n)
int n;
{
int i;
- struct token *tmp;
+ int num = num_tokens ();
+ int yychar;
- /* We cannot read past certain tokens, so make sure we don't. */
- i = num_tokens ();
- if (i > n)
+ /* First, prune any empty tokens at the end. */
+ i = num;
+ while (i > 0 && nth_token (i - 1)->yychar == EMPTY)
+ i--;
+ if (i < num)
+ {
+ obstack_blank (&token_obstack, -((num - i) * sizeof (struct token)));
+ num = i;
+ }
+
+ /* Now, if we already have enough tokens, return. */
+ if (num > n)
return;
- while (i-- > 0)
+
+ /* Never read past these characters: they might separate
+ the current input stream from one we save away later. */
+ for (i = 0; i < num; i++)
{
- tmp = nth_token (i);
- /* Never read past these characters: they might separate
- the current input stream from one we save away later. */
- if (tmp->yychar == '{' || tmp->yychar == ':' || tmp->yychar == ';')
+ yychar = nth_token (i)->yychar;
+ if (yychar == '{' || yychar == ':' || yychar == ';')
goto pad_tokens;
}
- while (num_tokens() <= n)
+ while (num_tokens () <= n)
{
- obstack_blank(&token_obstack,sizeof (struct token));
- tmp = ((struct token *)obstack_next_free (&token_obstack))-1;
- tmp->yychar = real_yylex();
- tmp->end_of_file = end_of_file;
- tmp->yylval = yylval;
- end_of_file = 0;
- if (tmp->yychar == '{'
- || tmp->yychar == ':'
- || tmp->yychar == ';')
- {
- pad_tokens:
- while (num_tokens () <= n)
- {
- obstack_blank(&token_obstack,sizeof (struct token));
- tmp = ((struct token *)obstack_next_free (&token_obstack))-1;
- tmp->yychar = EMPTY;
- tmp->end_of_file = 0;
- }
- }
+ yychar = shift_token ();
+ if (yychar == '{' || yychar == ':' || yychar == ';')
+ goto pad_tokens;
}
+ return;
+
+ pad_tokens:
+ while (num_tokens () <= n)
+ obstack_grow (&token_obstack, &Tpad, sizeof (struct token));
}
-/* Create room for N tokens at the front of the fifo. This is used
- to insert new tokens into the stream ahead of the current token. */
+int looking_for_typename;
+int looking_for_template;
-static void
-shift_tokens (n)
- int n;
+static int after_friend;
+static int after_new;
+static int do_snarf_defarg;
+
+tree got_scope;
+tree got_object;
+
+static SPEW_INLINE int
+identifier_type (decl)
+ tree decl;
{
- if (first_token >= n)
- first_token -= n;
- else
+ tree t;
+
+ if (TREE_CODE (decl) == TEMPLATE_DECL)
+ {
+ if (TREE_CODE (DECL_TEMPLATE_RESULT (decl)) == TYPE_DECL)
+ return PTYPENAME;
+ else if (looking_for_template)
+ return PFUNCNAME;
+ }
+ if (looking_for_template && really_overloaded_fn (decl))
{
- int old_token_count = num_tokens ();
- char *tmp;
+ /* See through a baselink. */
+ if (TREE_CODE (decl) == BASELINK)
+ decl = BASELINK_FUNCTIONS (decl);
- obstack_blank (&token_obstack, (n-first_token) * sizeof (struct token));
- if (old_token_count)
- {
- tmp = (char *)alloca ((num_tokens () + (n-first_token))
- * sizeof (struct token));
- /* This move does not rely on the system being able to handle
- overlapping moves. */
- bcopy ((char *) nth_token (0), tmp,
- old_token_count * sizeof (struct token));
- bcopy (tmp, (char *) nth_token (n),
- old_token_count * sizeof (struct token));
- }
- first_token = 0;
+ for (t = decl; t != NULL_TREE; t = OVL_CHAIN (t))
+ if (DECL_FUNCTION_TEMPLATE_P (OVL_FUNCTION (t)))
+ return PFUNCNAME;
}
+ if (TREE_CODE (decl) == NAMESPACE_DECL)
+ return NSNAME;
+ if (TREE_CODE (decl) != TYPE_DECL)
+ return IDENTIFIER;
+ if (DECL_ARTIFICIAL (decl) && TREE_TYPE (decl) == current_class_type)
+ return SELFNAME;
+
+ /* A constructor declarator for a template type will get here as an
+ implicit typename, a TYPENAME_TYPE with a type. */
+ t = got_scope;
+ if (t && TREE_CODE (t) == TYPENAME_TYPE)
+ t = TREE_TYPE (t);
+ decl = TREE_TYPE (decl);
+ if (TREE_CODE (decl) == TYPENAME_TYPE)
+ decl = TREE_TYPE (decl);
+ if (t && t == decl)
+ return SELFNAME;
+
+ return tTYPENAME;
}
-static int
-probe_obstack (h, obj, nlevels)
- struct obstack *h;
- tree obj;
- unsigned int nlevels;
+/* token[0] == AGGR (struct/union/enum)
+ Thus, token[1] is either a tTYPENAME or a TYPENAME_DEFN.
+ If token[2] == '{' or ':' then it's TYPENAME_DEFN.
+ It's also a definition if it's a forward declaration (as in 'struct Foo;')
+ which we can tell if token[2] == ';' *and* token[-1] != FRIEND or NEW. */
+
+static SPEW_INLINE void
+do_aggr ()
{
- register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
- register struct _obstack_chunk* plp; /* point to previous chunk if any */
+ int yc1, yc2;
- lp = (h)->chunk;
- /* We use >= rather than > since the object cannot be exactly at
- the beginning of the chunk but might be an empty object exactly
- at the end of an adjacent chunk. */
- for (; nlevels != 0 && lp != 0 && ((tree)lp >= obj || (tree)lp->limit < obj);
- nlevels -= 1)
+ scan_tokens (2);
+ yc1 = nth_token (1)->yychar;
+ if (yc1 != tTYPENAME && yc1 != IDENTIFIER && yc1 != PTYPENAME)
+ return;
+ yc2 = nth_token (2)->yychar;
+ if (yc2 == ';')
{
- plp = lp->prev;
- lp = plp;
+ /* It's a forward declaration iff we were not preceded by
+ 'friend' or `new'. */
+ if (after_friend || after_new)
+ return;
}
- return nlevels != 0 && lp != 0;
-}
+ else if (yc2 != '{' && yc2 != ':')
+ return;
-/* from lex.c: */
-/* Value is 1 (or 2) if we should try to make the next identifier look like
- a typename (when it may be a local variable or a class variable).
- Value is 0 if we treat this name in a default fashion. */
-extern int looking_for_typename;
-int looking_for_template;
+ switch (yc1)
+ {
+ case tTYPENAME:
+ nth_token (1)->yychar = TYPENAME_DEFN;
+ break;
+ case PTYPENAME:
+ nth_token (1)->yychar = PTYPENAME_DEFN;
+ break;
+ case IDENTIFIER:
+ nth_token (1)->yychar = IDENTIFIER_DEFN;
+ break;
+ default:
+ abort ();
+ }
+}
-extern struct obstack *current_obstack, *saveable_obstack;
-tree got_scope;
-tree got_object;
+void
+see_typename ()
+{
+ /* Only types expected, not even namespaces. */
+ looking_for_typename = 2;
+ if (yychar < 0)
+ if ((yychar = yylex ()) < 0) yychar = 0;
+ looking_for_typename = 0;
+ if (yychar == IDENTIFIER)
+ {
+ lastiddecl = lookup_name (yylval.ttype, -2);
+ if (lastiddecl)
+ yychar = identifier_type (lastiddecl);
+ }
+}
int
-yylex()
+yylex ()
{
- struct token tmp_token;
- tree trrr;
+ int yychr;
+ int old_looking_for_typename = 0;
+ int just_saw_new = 0;
+ int just_saw_friend = 0;
+
+ timevar_push (TV_LEX);
retry:
#ifdef SPEW_DEBUG
if (spew_debug)
{
yylex_ctr ++;
- fprintf(stderr, "\t\t## %d ##",yylex_ctr);
+ fprintf (stderr, "\t\t## %d @%d ", yylex_ctr, lineno);
}
#endif
- /* if we've got tokens, send them */
- if (num_tokens())
+ if (do_snarf_defarg)
{
- tmp_token= *nth_token(0);
-
- /* TMP_TOKEN.YYLVAL.TTYPE may have been allocated on the wrong obstack.
- If we don't find it in CURRENT_OBSTACK's current or immediately
- previous chunk, assume it was and copy it to the current obstack. */
- if ((tmp_token.yychar == CONSTANT
- || tmp_token.yychar == STRING)
- && ! TREE_PERMANENT (tmp_token.yylval.ttype)
- && ! probe_obstack (current_obstack, tmp_token.yylval.ttype, 2)
- && ! probe_obstack (saveable_obstack, tmp_token.yylval.ttype, 2))
- tmp_token.yylval.ttype = copy_node (tmp_token.yylval.ttype);
+ do_snarf_defarg = 0;
+ yylval.ttype = snarf_defarg ();
+ yychar = DEFARG;
+ got_object = NULL_TREE;
+ timevar_pop (TV_LEX);
+ return DEFARG;
}
+
+ /* if we've got tokens, send them */
+ else if (num_tokens ())
+ yychr = nth_token (0)->yychar;
else
- {
- /* if not, grab the next one and think about it */
- tmp_token.yychar = real_yylex ();
- tmp_token.yylval = yylval;
- tmp_token.end_of_file = end_of_file;
- add_token(&tmp_token);
- }
+ yychr = shift_token ();
/* many tokens just need to be returned. At first glance, all we
- * have to do is send them back up, but some of them are needed to
- * figure out local context. */
- switch(tmp_token.yychar)
+ have to do is send them back up, but some of them are needed to
+ figure out local context. */
+ switch (yychr)
{
case EMPTY:
/* This is a lexical no-op. */
- consume_token ();
-#ifdef SPEW_DEBUG
+#ifdef SPEW_DEBUG
if (spew_debug)
- debug_yychar (tmp_token.yychar);
+ debug_yychar (yychr);
#endif
+ consume_token ();
goto retry;
- case IDENTIFIER:
+ case '(':
scan_tokens (1);
- if (nth_token (1)->yychar == SCOPE)
- /* Don't interfere with the setting from an 'aggr' prefix. */
- looking_for_typename++;
- else if (nth_token (1)->yychar == '<')
- looking_for_template = 1;
-
- trrr = lookup_name (tmp_token.yylval.ttype, -2);
-
- if (trrr)
+ if (nth_token (1)->yychar == ')')
{
- tmp_token.yychar = identifier_type (trrr);
- switch (tmp_token.yychar)
- {
- case TYPENAME:
- lastiddecl = identifier_typedecl_value (tmp_token.yylval.ttype);
- if (lastiddecl != trrr)
- {
- lastiddecl = trrr;
- if (got_scope || got_object)
- tmp_token.yylval.ttype = DECL_NESTED_TYPENAME (trrr);
- }
- break;
- case IDENTIFIER:
- lastiddecl = trrr;
- break;
- case PTYPENAME:
- lastiddecl = NULL_TREE;
- break;
- default:
- my_friendly_abort (101);
- }
+ consume_token ();
+ yychr = LEFT_RIGHT;
}
- else
- lastiddecl = trrr;
- got_scope = NULL_TREE;
- /* and fall through to... */
+ break;
+
+ case IDENTIFIER:
+ {
+ int peek;
+
+ scan_tokens (1);
+ peek = nth_token (1)->yychar;
+ yychr = frob_id (yychr, peek, &nth_token (0)->yylval.ttype);
+ break;
+ }
case IDENTIFIER_DEFN:
- case TYPENAME:
+ case tTYPENAME:
case TYPENAME_DEFN:
case PTYPENAME:
case PTYPENAME_DEFN:
- consume_token ();
- if (looking_for_typename > 0)
- looking_for_typename--;
+ /* If we see a SCOPE next, restore the old value.
+ Otherwise, we got what we want. */
+ looking_for_typename = old_looking_for_typename;
looking_for_template = 0;
break;
case SCSPEC:
- /* do_aggr needs to check if the previous token was RID_FRIEND,
- so just increment first_token instead of calling consume_token. */
- first_token++;
+ if (nth_token (0)->yylval.ttype == ridpointers[RID_EXTERN])
+ {
+ scan_tokens (1);
+ if (nth_token (1)->yychar == STRING)
+ {
+ yychr = EXTERN_LANG_STRING;
+ nth_token (1)->yylval.ttype = get_identifier
+ (TREE_STRING_POINTER (nth_token (1)->yylval.ttype));
+ consume_token ();
+ }
+ }
+ /* do_aggr needs to know if the previous token was `friend'. */
+ else if (nth_token (0)->yylval.ttype == ridpointers[RID_FRIEND])
+ just_saw_friend = 1;
+
+ break;
+
+ case NEW:
+ /* do_aggr needs to know if the previous token was `new'. */
+ just_saw_new = 1;
break;
+
case TYPESPEC:
- consume_token ();
+ case '{':
+ case ':':
+ case ';':
+ /* If this provides a type for us, then revert lexical
+ state to standard state. */
+ looking_for_typename = 0;
break;
case AGGR:
- *nth_token(0) = tmp_token;
do_aggr ();
- /* fall through to output... */
+ break;
+
case ENUM:
/* Set this again, in case we are rescanning. */
- looking_for_typename = 1;
- /* fall through... */
+ looking_for_typename = 2;
+ break;
+
default:
- consume_token();
+ break;
}
- yylval = tmp_token.yylval;
- yychar = tmp_token.yychar;
- end_of_file = tmp_token.end_of_file;
-#ifdef SPEW_DEBUG
+ after_friend = just_saw_friend;
+ after_new = just_saw_new;
+
+ /* class member lookup only applies to the first token after the object
+ expression, except for explicit destructor calls. */
+ if (yychr != '~')
+ got_object = NULL_TREE;
+
+ yychar = yychr;
+ {
+ struct token *tok = nth_token (0);
+
+ yylval = tok->yylval;
+ if (tok->lineno)
+ lineno = tok->lineno;
+ }
+
+#ifdef SPEW_DEBUG
if (spew_debug)
- debug_yychar(yychar);
+ debug_yychar (yychr);
#endif
- return yychar;
+ consume_token ();
+
+ timevar_pop (TV_LEX);
+ return yychr;
}
-/* token[0] == AGGR (struct/union/enum)
- * Thus, token[1] is either a TYPENAME or a TYPENAME_DEFN.
- * If token[2] == '{' or ':' then it's TYPENAME_DEFN.
- * It's also a definition if it's a forward declaration (as in 'struct Foo;')
- * which we can tell lf token[2] == ';' *and* token[-1] != FRIEND.
- */
+/* Unget character CH from the input stream.
+ If RESCAN is non-zero, then we want to `see' this
+ character as the next input token. */
+
+void
+yyungetc (ch, rescan)
+ int ch;
+ int rescan;
+{
+ /* Unget a character from the input stream. */
+ if (yychar == YYEMPTY || rescan == 0)
+ {
+ struct token fake;
+
+ fake.yychar = ch;
+ fake.yylval.ttype = 0;
+ fake.lineno = lineno;
+
+ push_token (&fake);
+ }
+ else
+ {
+ yychar = ch;
+ }
+}
+
+/* Lexer hackery to determine what *IDP really is. */
+
static int
-do_aggr ()
+frob_id (yyc, peek, idp)
+ int yyc;
+ int peek;
+ tree *idp;
{
- int yc1, yc2;
-
- scan_tokens (2);
- yc1 = nth_token (1)->yychar;
- if (yc1 != TYPENAME && yc1 != IDENTIFIER && yc1 != PTYPENAME)
- return 0;
- yc2 = nth_token (2)->yychar;
- if (yc2 == ';')
+ tree trrr;
+ int old_looking_for_typename = 0;
+
+ if (peek == SCOPE)
{
- /* It's a forward declaration iff we were not preceded by 'friend'. */
- if (first_token > 0 && nth_token (-1)->yychar == SCSPEC
- && nth_token (-1)->yylval.ttype == ridpointers[(int) RID_FRIEND])
- return 0;
+ /* Don't interfere with the setting from an 'aggr' prefix. */
+ old_looking_for_typename = looking_for_typename;
+ looking_for_typename = 1;
}
- else if (yc2 != '{' && yc2 != ':')
- return 0;
+ else if (peek == '<')
+ looking_for_template = 1;
+ trrr = lookup_name (*idp, -2);
+ if (trrr)
+ {
+ yyc = identifier_type (trrr);
+ switch(yyc)
+ {
+ case tTYPENAME:
+ case SELFNAME:
+ case NSNAME:
+ case PTYPENAME:
+ /* If this got special lookup, remember it. In these
+ cases, we know it can't be a declarator-id. */
+ if (got_scope || got_object)
+ *idp = trrr;
+ /* FALLTHROUGH */
+ case PFUNCNAME:
+ case IDENTIFIER:
+ lastiddecl = trrr;
+ break;
+ default:
+ abort ();
+ }
+ }
+ else
+ lastiddecl = NULL_TREE;
+ got_scope = NULL_TREE;
+ looking_for_typename = old_looking_for_typename;
+ looking_for_template = 0;
+ return yyc;
+}
- switch (yc1)
+/* ID is an operator name. Duplicate the hackery in yylex to determine what
+ it really is. */
+
+tree frob_opname (id)
+ tree id;
+{
+ scan_tokens (0);
+ frob_id (0, nth_token (0)->yychar, &id);
+ got_object = NULL_TREE;
+ return id;
+}
+
+/* Set up the state required to correctly handle the definition of the
+ inline function whose preparsed state has been saved in PI. */
+
+static void
+begin_parsing_inclass_inline (pi)
+ struct unparsed_text *pi;
+{
+ tree context;
+
+ /* Record that we are processing the chain of inlines starting at
+ PI for GC. */
+ if (cfun)
+ cp_function_chain->unparsed_inlines = pi;
+ else
+ processing_these_inlines = pi;
+
+ ggc_collect ();
+
+ /* If this is an inline function in a local class, we must make sure
+ that we save all pertinent information about the function
+ surrounding the local class. */
+ context = decl_function_context (pi->decl);
+ if (context)
+ push_function_context_to (context);
+
+ feed_input (pi);
+ interface_unknown = pi->interface == 1;
+ interface_only = pi->interface == 0;
+ DECL_PENDING_INLINE_P (pi->decl) = 0;
+ DECL_PENDING_INLINE_INFO (pi->decl) = 0;
+
+ /* Pass back a handle to the rest of the inline functions, so that they
+ can be processed later. */
+ yychar = PRE_PARSED_FUNCTION_DECL;
+ yylval.pi = pi;
+
+ start_function (NULL_TREE, pi->decl, NULL_TREE,
+ (SF_DEFAULT | SF_PRE_PARSED | SF_INCLASS_INLINE));
+}
+
+/* Called from the top level: if there are any pending inlines to
+ do, set up to process them now. This function sets up the first function
+ to be parsed; after it has been, the rule for fndef in parse.y will
+ call process_next_inline to start working on the next one. */
+
+void
+do_pending_inlines ()
+{
+ /* Oops, we're still dealing with the last batch. */
+ if (yychar == PRE_PARSED_FUNCTION_DECL)
+ return;
+
+ if (pending_inlines)
{
- case TYPENAME:
- nth_token (1)->yychar = TYPENAME_DEFN;
- break;
- case PTYPENAME:
- nth_token (1)->yychar = PTYPENAME_DEFN;
- break;
- case IDENTIFIER:
- nth_token (1)->yychar = IDENTIFIER_DEFN;
- break;
- default:
- my_friendly_abort (102);
+ /* Clear the chain, so that any inlines nested inside the batch
+ we're to process now don't refer to this batch. See e.g.
+ g++.other/lookup6.C. */
+ struct unparsed_text *first = pending_inlines;
+ pending_inlines = pending_inlines_tail = 0;
+
+ begin_parsing_inclass_inline (first);
}
- return 0;
-}
-
-#ifdef SPEW_DEBUG
-/* debug_yychar takes a yychar (token number) value and prints its name. */
-static int
+}
+
+/* Called from the fndecl rule in the parser when the function just parsed
+ was declared using a PRE_PARSED_FUNCTION_DECL (i.e. came from
+ do_pending_inlines). */
+
+void
+process_next_inline (i)
+ struct unparsed_text *i;
+{
+ tree decl = i->decl;
+ tree context = decl_function_context (decl);
+
+ if (context)
+ pop_function_context_from (context);
+ if (yychar == YYEMPTY)
+ yychar = yylex ();
+ if (yychar != END_OF_SAVED_INPUT)
+ error ("parse error at end of saved function text");
+ end_input ();
+
+ i = i->next;
+ if (i)
+ begin_parsing_inclass_inline (i);
+ else
+ {
+ if (cfun)
+ cp_function_chain->unparsed_inlines = 0;
+ else
+ processing_these_inlines = 0;
+ extract_interface_info ();
+ }
+}
+\f
+/* Create a new token at the end of the token list in T. */
+static SPEW_INLINE struct token *
+space_for_token (t)
+ struct unparsed_text *t;
+{
+ if (t->last_pos != TOKEN_CHUNK_SIZE)
+ return t->last_chunk->toks + (t->last_pos++);
+
+ t->last_chunk->next = ggc_alloc_cleared (sizeof (*t->last_chunk->next));
+ t->last_chunk = t->last_chunk->next;
+ t->last_chunk->next = NULL;
+
+ t->last_pos = 1;
+ return t->last_chunk->toks;
+}
+
+/* Shrink the token list in T by one token. */
+static SPEW_INLINE struct token *
+remove_last_token (t)
+ struct unparsed_text *t;
+{
+ struct token *result = t->last_chunk->toks + t->last_pos - 1;
+ if (t->last_pos == 0)
+ abort ();
+ t->last_pos--;
+ if (t->last_pos == 0 && t->last_chunk != t->tokens)
+ {
+ struct token_chunk **tc;
+ for (tc = &t->tokens; (*tc)->next != NULL; tc = &(*tc)->next)
+ ;
+ *tc = NULL;
+ t->last_pos = ARRAY_SIZE ((*tc)->toks);
+ }
+ return result;
+}
+
+/* Allocate an 'unparsed_text' structure, ready to use space_for_token. */
+static struct unparsed_text *
+alloc_unparsed_text (locus, decl, interface)
+ const location_t *locus;
+ tree decl;
+ int interface;
+{
+ struct unparsed_text *r;
+ r = ggc_alloc_cleared (sizeof (*r));
+ r->decl = decl;
+ r->locus = *locus;
+ r->interface = interface;
+ r->tokens = r->last_chunk = ggc_alloc_cleared (sizeof (*r->tokens));
+ return r;
+}
+
+/* Subroutine of snarf_method, deals with actual absorption of the block. */
+
+static void
+snarf_block (t)
+ struct unparsed_text *t;
+{
+ int blev = 1;
+ int look_for_semicolon = 0;
+ int look_for_lbrac = 0;
+ int look_for_catch = 0;
+ int yyc;
+ struct token *current;
+
+ if (yychar == '{')
+ ;
+ else if (yychar == '=')
+ look_for_semicolon = 1;
+ else if (yychar == ':' || yychar == RETURN_KEYWORD || yychar == TRY)
+ {
+ if (yychar == TRY)
+ look_for_catch = 1;
+ look_for_lbrac = 1;
+ blev = 0;
+ }
+ else
+ yyerror ("parse error in method specification");
+
+ /* The current token is the first one to be recorded. */
+ current = space_for_token (t);
+ current->yychar = yychar;
+ current->yylval = yylval;
+ current->lineno = lineno;
+
+ for (;;)
+ {
+ yyc = next_token (space_for_token (t));
+
+ if (yyc == '{')
+ {
+ look_for_lbrac = 0;
+ blev++;
+ }
+ else if (yyc == '}')
+ {
+ blev--;
+ if (blev == 0 && !look_for_semicolon)
+ {
+ if (!look_for_catch)
+ break;
+
+ if (next_token (space_for_token (t)) != CATCH)
+ {
+ push_token (remove_last_token (t));
+ break;
+ }
+
+ look_for_lbrac = 1;
+ }
+ }
+ else if (yyc == ';')
+ {
+ if (look_for_lbrac)
+ {
+ struct token *fake;
+
+ error ("function body for constructor missing");
+ /* fake a { } to avoid further errors */
+ fake = space_for_token (t);
+ fake->yylval.ttype = 0;
+ fake->yychar = '{';
+ fake = space_for_token (t);
+ fake->yylval.ttype = 0;
+ fake->yychar = '}';
+ break;
+ }
+ else if (look_for_semicolon && blev == 0)
+ break;
+ }
+ else if (yyc == 0)
+ {
+ error ("%Hend of file read inside definition", &t->locus);
+ break;
+ }
+ }
+}
+
+/* This function stores away the text for an inline function that should
+ be processed later (by do_pending_inlines). */
+void
+snarf_method (decl)
+ tree decl;
+{
+ struct unparsed_text *meth;
+ location_t starting;
+ starting.file = input_filename;
+ starting.line = lineno;
+
+ meth = alloc_unparsed_text (&starting, decl, (interface_unknown ? 1
+ : (interface_only ? 0 : 2)));
+
+ snarf_block (meth);
+
+ /* Happens when we get two declarations of the same function in the
+ same scope. */
+ if (decl == void_type_node
+ || (current_class_type && TYPE_REDEFINED (current_class_type)))
+ return;
+
+#ifdef SPEW_DEBUG
+ if (spew_debug)
+ fprintf (stderr, "\tsaved method of %d tokens from %s:%d\n",
+ meth->limit, starting.file, starting.line);
+#endif
+
+ DECL_PENDING_INLINE_INFO (decl) = meth;
+ DECL_PENDING_INLINE_P (decl) = 1;
+
+ if (pending_inlines_tail)
+ pending_inlines_tail->next = meth;
+ else
+ pending_inlines = meth;
+ pending_inlines_tail = meth;
+}
+
+/* Consume a no-commas expression - a default argument - and return
+ a DEFAULT_ARG tree node. */
+
+static tree
+snarf_defarg ()
+{
+ int yyc;
+ int plev = 0;
+ struct unparsed_text *buf;
+ tree arg;
+ location_t starting;
+ starting.file = input_filename;
+ starting.line = lineno;
+
+ buf = alloc_unparsed_text (&starting, 0, 0);
+
+ for (;;)
+ {
+ yyc = next_token (space_for_token (buf));
+
+ if (plev <= 0 && (yyc == ')' || yyc == ','))
+ break;
+ else if (yyc == '(' || yyc == '[')
+ ++plev;
+ else if (yyc == ']' || yyc == ')')
+ --plev;
+ else if (yyc == 0)
+ {
+ error ("%Hend of file read inside default argument", &starting);
+ goto done;
+ }
+ }
+
+ /* Unget the last token. */
+ push_token (remove_last_token (buf));
+
+ done:
+#ifdef SPEW_DEBUG
+ if (spew_debug)
+ fprintf (stderr, "\tsaved defarg of %d tokens from %s:%d\n",
+ buf->limit, starting.file, starting.line);
+#endif
+
+ arg = make_node (DEFAULT_ARG);
+ DEFARG_POINTER (arg) = (char *)buf;
+
+ return arg;
+}
+
+/* Decide whether the default argument we are about to see should be
+ gobbled up as text for later parsing. */
+
+void
+maybe_snarf_defarg ()
+{
+ if (current_class_type && TYPE_BEING_DEFINED (current_class_type))
+ do_snarf_defarg = 1;
+}
+
+/* Called from grokfndecl to note a function decl with unparsed default
+ arguments for later processing. Also called from grokdeclarator
+ for function types with unparsed defargs; the call from grokfndecl
+ will always come second, so we can overwrite the entry from the type. */
+
+void
+add_defarg_fn (decl)
+ tree decl;
+{
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ TREE_VALUE (defarg_fns) = decl;
+ else
+ {
+ defarg_fns = tree_cons (NULL_TREE, decl, defarg_fns);
+ TREE_TYPE (defarg_fns) = current_class_type;
+ }
+}
+
+/* Helper for do_pending_defargs. Starts the parsing of a default arg. */
+
+static void
+feed_defarg (p)
+ tree p;
+{
+ tree d = TREE_PURPOSE (p);
+
+ feed_input ((struct unparsed_text *)DEFARG_POINTER (d));
+ yychar = DEFARG_MARKER;
+ yylval.ttype = p;
+}
+
+/* Helper for do_pending_defargs. Ends the parsing of a default arg. */
+
+static void
+finish_defarg ()
+{
+ if (yychar == YYEMPTY)
+ yychar = yylex ();
+ if (yychar != END_OF_SAVED_INPUT)
+ error ("parse error at end of saved function text");
+
+ end_input ();
+}
+
+/* Main function for deferred parsing of default arguments. Called from
+ the parser. */
+
+void
+do_pending_defargs ()
+{
+ if (defarg_parm)
+ finish_defarg ();
+
+ for (; defarg_fns;)
+ {
+ tree current = defarg_fns;
+
+ tree defarg_fn = TREE_VALUE (defarg_fns);
+ if (defarg_parm == NULL_TREE)
+ {
+ push_nested_class (TREE_TYPE (defarg_fns), 1);
+ pushlevel (0);
+ if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+ maybe_begin_member_template_processing (defarg_fn);
+
+ if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+ defarg_parm = TYPE_ARG_TYPES (TREE_TYPE (defarg_fn));
+ else
+ defarg_parm = TYPE_ARG_TYPES (defarg_fn);
+ }
+ else
+ defarg_parm = TREE_CHAIN (defarg_parm);
+
+ for (; defarg_parm; defarg_parm = TREE_CHAIN (defarg_parm))
+ if (!TREE_PURPOSE (defarg_parm)
+ || TREE_CODE (TREE_PURPOSE (defarg_parm)) != DEFAULT_ARG)
+ ;/* OK */
+ else if (TREE_PURPOSE (current) == error_mark_node)
+ DEFARG_POINTER (TREE_PURPOSE (defarg_parm)) = NULL;
+ else
+ {
+ feed_defarg (defarg_parm);
+
+ /* Return to the parser, which will process this defarg
+ and call us again. */
+ return;
+ }
+
+ if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+ {
+ maybe_end_member_template_processing ();
+ check_default_args (defarg_fn);
+ }
+
+ poplevel (0, 0, 0);
+ pop_nested_class ();
+
+ defarg_fns = TREE_CHAIN (defarg_fns);
+ if (defarg_depfns)
+ {
+ /* This function's default args depend on unprocessed default args
+ of defarg_fns. We will need to reprocess this function, and
+ check for circular dependencies. */
+ tree a, b;
+
+ for (a = defarg_depfns, b = TREE_PURPOSE (current); a && b;
+ a = TREE_CHAIN (a), b = TREE_CHAIN (b))
+ if (TREE_VALUE (a) != TREE_VALUE (b))
+ goto different;
+ if (a || b)
+ {
+ different:;
+ TREE_CHAIN (current) = NULL_TREE;
+ defarg_fns = chainon (defarg_fns, current);
+ TREE_PURPOSE (current) = defarg_depfns;
+ }
+ else
+ {
+ cp_warning_at ("circular dependency in default args of `%#D'", defarg_fn);
+ /* No need to say what else is dependent, as they will be
+ picked up in another pass. */
+
+ /* Immediately repeat, but marked so that we break the loop. */
+ defarg_fns = current;
+ TREE_PURPOSE (current) = error_mark_node;
+ }
+ defarg_depfns = NULL_TREE;
+ }
+ else if (TREE_PURPOSE (current) == error_mark_node)
+ defarg_fnsdone = tree_cons (NULL_TREE, defarg_fn, defarg_fnsdone);
+ }
+}
+
+/* After parsing all the default arguments, we must clear any that remain,
+ which will be part of a circular dependency. */
+void
+done_pending_defargs ()
+{
+ for (; defarg_fnsdone; defarg_fnsdone = TREE_CHAIN (defarg_fnsdone))
+ {
+ tree fn = TREE_VALUE (defarg_fnsdone);
+ tree parms;
+
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ else
+ parms = TYPE_ARG_TYPES (fn);
+ for (; parms; parms = TREE_CHAIN (parms))
+ if (TREE_PURPOSE (parms)
+ && TREE_CODE (TREE_PURPOSE (parms)) == DEFAULT_ARG)
+ {
+ my_friendly_assert (!DEFARG_POINTER (TREE_PURPOSE (parms)), 20010107);
+ TREE_PURPOSE (parms) = NULL_TREE;
+ }
+ }
+}
+
+/* In processing the current default arg, we called FN, but that call
+ required a default argument of FN, and that had not yet been processed.
+ Remember FN. */
+
+void
+unprocessed_defarg_fn (fn)
+ tree fn;
+{
+ defarg_depfns = tree_cons (NULL_TREE, fn, defarg_depfns);
+}
+
+/* Called from the parser to update an element of TYPE_ARG_TYPES for some
+ FUNCTION_TYPE with the newly parsed version of its default argument, which
+ was previously digested as text. */
+
+void
+replace_defarg (arg, init)
+ tree arg, init;
+{
+ if (init == error_mark_node)
+ TREE_PURPOSE (arg) = error_mark_node;
+ else
+ {
+ if (! processing_template_decl
+ && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init))
+ pedwarn ("invalid type `%T' for default argument to `%T'",
+ TREE_TYPE (init), TREE_VALUE (arg));
+ if (!defarg_depfns)
+ TREE_PURPOSE (arg) = init;
+ }
+}
+
+#ifdef SPEW_DEBUG
+/* debug_yychar takes a yychar (token number) value and prints its name. */
+
+static void
debug_yychar (yy)
int yy;
{
- /* In parse.y: */
- extern char *debug_yytranslate ();
-
- int i;
-
- if(yy<256) {
- fprintf (stderr, "<%d: %c >\n", yy, yy);
- return 0;
- }
- fprintf (stderr, "<%d:%s>\n", yy, debug_yytranslate (yy));
- return 1;
+ if (yy<256)
+ fprintf (stderr, "->%d < %c >\n", lineno, yy);
+ else if (yy == IDENTIFIER || yy == tTYPENAME)
+ {
+ const char *id;
+ if (TREE_CODE (yylval.ttype) == IDENTIFIER_NODE)
+ id = IDENTIFIER_POINTER (yylval.ttype);
+ else if (TREE_CODE_CLASS (TREE_CODE (yylval.ttype)) == 'd')
+ id = IDENTIFIER_POINTER (DECL_NAME (yylval.ttype));
+ else
+ id = "";
+ fprintf (stderr, "->%d <%s `%s'>\n", lineno, debug_yytranslate (yy), id);
+ }
+ else
+ fprintf (stderr, "->%d <%s>\n", lineno, debug_yytranslate (yy));
}
#endif
+
+#define NAME(TYPE) cpp_type2name (TYPE)
+
+void
+yyerror (msgid)
+ const char *msgid;
+{
+ const char *string = _(msgid);
+
+ if (last_token == CPP_EOF)
+ error ("%s at end of input", string);
+ else if (last_token == CPP_CHAR || last_token == CPP_WCHAR)
+ {
+ unsigned int val = TREE_INT_CST_LOW (yylval.ttype);
+ const char *const ell = (last_token == CPP_CHAR) ? "" : "L";
+ if (val <= UCHAR_MAX && ISGRAPH (val))
+ error ("%s before %s'%c'", string, ell, val);
+ else
+ error ("%s before %s'\\x%x'", string, ell, val);
+ }
+ else if (last_token == CPP_STRING
+ || last_token == CPP_WSTRING)
+ error ("%s before string constant", string);
+ else if (last_token == CPP_NUMBER)
+ error ("%s before numeric constant", string);
+ else if (last_token == CPP_NAME)
+ {
+ if (TREE_CODE (last_token_id) == IDENTIFIER_NODE)
+ error ("%s before `%s'", string, IDENTIFIER_POINTER (last_token_id));
+ else if (ISGRAPH (yychar))
+ error ("%s before `%c'", string, yychar);
+ else
+ error ("%s before `\%o'", string, yychar);
+ }
+ else
+ error ("%s before `%s' token", string, NAME (last_token));
+}
+
+#include "gt-cp-spew.h"