blob: 1feb5752ecb3d9d8a13318ebe53948516f17524f [file] [log] [blame]
/* C++ Parser.
Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "dyn-string.h"
#include "varray.h"
#include "cpplib.h"
#include "tree.h"
#include "cp-tree.h"
#include "c-pragma.h"
#include "decl.h"
#include "flags.h"
#include "diagnostic.h"
#include "toplev.h"
#include "output.h"
/* The lexer. */
/* Overview
--------
A cp_lexer represents a stream of cp_tokens. It allows arbitrary
look-ahead.
Methodology
-----------
We use a circular buffer to store incoming tokens.
Some artifacts of the C++ language (such as the
expression/declaration ambiguity) require arbitrary look-ahead.
The strategy we adopt for dealing with these problems is to attempt
to parse one construct (e.g., the declaration) and fall back to the
other (e.g., the expression) if that attempt does not succeed.
Therefore, we must sometimes store an arbitrary number of tokens.
The parser routinely peeks at the next token, and then consumes it
later. That also requires a buffer in which to store the tokens.
In order to easily permit adding tokens to the end of the buffer,
while removing them from the beginning of the buffer, we use a
circular buffer. */
/* A C++ token. */
typedef struct cp_token GTY (())
{
/* The kind of token. */
ENUM_BITFIELD (cpp_ttype) type : 8;
/* If this token is a keyword, this value indicates which keyword.
Otherwise, this value is RID_MAX. */
ENUM_BITFIELD (rid) keyword : 8;
/* Token flags. */
unsigned char flags;
/* The value associated with this token, if any. */
tree value;
/* The location at which this token was found. */
location_t location;
} cp_token;
/* The number of tokens in a single token block.
Computed so that cp_token_block fits in a 512B allocation unit. */
#define CP_TOKEN_BLOCK_NUM_TOKENS ((512 - 3*sizeof (char*))/sizeof (cp_token))
/* A group of tokens. These groups are chained together to store
large numbers of tokens. (For example, a token block is created
when the body of an inline member function is first encountered;
the tokens are processed later after the class definition is
complete.)
This somewhat ungainly data structure (as opposed to, say, a
variable-length array), is used due to constraints imposed by the
current garbage-collection methodology. If it is made more
flexible, we could perhaps simplify the data structures involved. */
typedef struct cp_token_block GTY (())
{
/* The tokens. */
cp_token tokens[CP_TOKEN_BLOCK_NUM_TOKENS];
/* The number of tokens in this block. */
size_t num_tokens;
/* The next token block in the chain. */
struct cp_token_block *next;
/* The previous block in the chain. */
struct cp_token_block *prev;
} cp_token_block;
typedef struct cp_token_cache GTY (())
{
/* The first block in the cache. NULL if there are no tokens in the
cache. */
cp_token_block *first;
/* The last block in the cache. NULL If there are no tokens in the
cache. */
cp_token_block *last;
} cp_token_cache;
/* Prototypes. */
static cp_token_cache *cp_token_cache_new
(void);
static void cp_token_cache_push_token
(cp_token_cache *, cp_token *);
/* Create a new cp_token_cache. */
static cp_token_cache *
cp_token_cache_new (void)
{
return ggc_alloc_cleared (sizeof (cp_token_cache));
}
/* Add *TOKEN to *CACHE. */
static void
cp_token_cache_push_token (cp_token_cache *cache,
cp_token *token)
{
cp_token_block *b = cache->last;
/* See if we need to allocate a new token block. */
if (!b || b->num_tokens == CP_TOKEN_BLOCK_NUM_TOKENS)
{
b = ggc_alloc_cleared (sizeof (cp_token_block));
b->prev = cache->last;
if (cache->last)
{
cache->last->next = b;
cache->last = b;
}
else
cache->first = cache->last = b;
}
/* Add this token to the current token block. */
b->tokens[b->num_tokens++] = *token;
}
/* The cp_lexer structure represents the C++ lexer. It is responsible
for managing the token stream from the preprocessor and supplying
it to the parser. */
typedef struct cp_lexer GTY (())
{
/* The memory allocated for the buffer. Never NULL. */
cp_token * GTY ((length ("(%h.buffer_end - %h.buffer)"))) buffer;
/* A pointer just past the end of the memory allocated for the buffer. */
cp_token * GTY ((skip (""))) buffer_end;
/* The first valid token in the buffer, or NULL if none. */
cp_token * GTY ((skip (""))) first_token;
/* The next available token. If NEXT_TOKEN is NULL, then there are
no more available tokens. */
cp_token * GTY ((skip (""))) next_token;
/* A pointer just past the last available token. If FIRST_TOKEN is
NULL, however, there are no available tokens, and then this
location is simply the place in which the next token read will be
placed. If LAST_TOKEN == FIRST_TOKEN, then the buffer is full.
When the LAST_TOKEN == BUFFER, then the last token is at the
highest memory address in the BUFFER. */
cp_token * GTY ((skip (""))) last_token;
/* A stack indicating positions at which cp_lexer_save_tokens was
called. The top entry is the most recent position at which we
began saving tokens. The entries are differences in token
position between FIRST_TOKEN and the first saved token.
If the stack is non-empty, we are saving tokens. When a token is
consumed, the NEXT_TOKEN pointer will move, but the FIRST_TOKEN
pointer will not. The token stream will be preserved so that it
can be reexamined later.
If the stack is empty, then we are not saving tokens. Whenever a
token is consumed, the FIRST_TOKEN pointer will be moved, and the
consumed token will be gone forever. */
varray_type saved_tokens;
/* The STRING_CST tokens encountered while processing the current
string literal. */
varray_type string_tokens;
/* True if we should obtain more tokens from the preprocessor; false
if we are processing a saved token cache. */
bool main_lexer_p;
/* True if we should output debugging information. */
bool debugging_p;
/* The next lexer in a linked list of lexers. */
struct cp_lexer *next;
} cp_lexer;
/* Prototypes. */
static cp_lexer *cp_lexer_new_main
(void);
static cp_lexer *cp_lexer_new_from_tokens
(struct cp_token_cache *);
static int cp_lexer_saving_tokens
(const cp_lexer *);
static cp_token *cp_lexer_next_token
(cp_lexer *, cp_token *);
static cp_token *cp_lexer_prev_token
(cp_lexer *, cp_token *);
static ptrdiff_t cp_lexer_token_difference
(cp_lexer *, cp_token *, cp_token *);
static cp_token *cp_lexer_read_token
(cp_lexer *);
static void cp_lexer_maybe_grow_buffer
(cp_lexer *);
static void cp_lexer_get_preprocessor_token
(cp_lexer *, cp_token *);
static cp_token *cp_lexer_peek_token
(cp_lexer *);
static cp_token *cp_lexer_peek_nth_token
(cp_lexer *, size_t);
static inline bool cp_lexer_next_token_is
(cp_lexer *, enum cpp_ttype);
static bool cp_lexer_next_token_is_not
(cp_lexer *, enum cpp_ttype);
static bool cp_lexer_next_token_is_keyword
(cp_lexer *, enum rid);
static cp_token *cp_lexer_consume_token
(cp_lexer *);
static void cp_lexer_purge_token
(cp_lexer *);
static void cp_lexer_purge_tokens_after
(cp_lexer *, cp_token *);
static void cp_lexer_save_tokens
(cp_lexer *);
static void cp_lexer_commit_tokens
(cp_lexer *);
static void cp_lexer_rollback_tokens
(cp_lexer *);
static inline void cp_lexer_set_source_position_from_token
(cp_lexer *, const cp_token *);
static void cp_lexer_print_token
(FILE *, cp_token *);
static inline bool cp_lexer_debugging_p
(cp_lexer *);
static void cp_lexer_start_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
static void cp_lexer_stop_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
/* Manifest constants. */
#define CP_TOKEN_BUFFER_SIZE 5
#define CP_SAVED_TOKENS_SIZE 5
/* A token type for keywords, as opposed to ordinary identifiers. */
#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
/* A token type for template-ids. If a template-id is processed while
parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
the value of the CPP_TEMPLATE_ID is whatever was returned by
cp_parser_template_id. */
#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
/* A token type for nested-name-specifiers. If a
nested-name-specifier is processed while parsing tentatively, it is
replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
CPP_NESTED_NAME_SPECIFIER is whatever was returned by
cp_parser_nested_name_specifier_opt. */
#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
/* A token type for tokens that are not tokens at all; these are used
to mark the end of a token block. */
#define CPP_NONE (CPP_NESTED_NAME_SPECIFIER + 1)
/* Variables. */
/* The stream to which debugging output should be written. */
static FILE *cp_lexer_debug_stream;
/* Create a new main C++ lexer, the lexer that gets tokens from the
preprocessor. */
static cp_lexer *
cp_lexer_new_main (void)
{
cp_lexer *lexer;
cp_token first_token;
/* It's possible that lexing the first token will load a PCH file,
which is a GC collection point. So we have to grab the first
token before allocating any memory. */
cp_lexer_get_preprocessor_token (NULL, &first_token);
c_common_no_more_pch ();
/* Allocate the memory. */
lexer = ggc_alloc_cleared (sizeof (cp_lexer));
/* Create the circular buffer. */
lexer->buffer = ggc_calloc (CP_TOKEN_BUFFER_SIZE, sizeof (cp_token));
lexer->buffer_end = lexer->buffer + CP_TOKEN_BUFFER_SIZE;
/* There is one token in the buffer. */
lexer->last_token = lexer->buffer + 1;
lexer->first_token = lexer->buffer;
lexer->next_token = lexer->buffer;
memcpy (lexer->buffer, &first_token, sizeof (cp_token));
/* This lexer obtains more tokens by calling c_lex. */
lexer->main_lexer_p = true;
/* Create the SAVED_TOKENS stack. */
VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens");
/* Create the STRINGS array. */
VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings");
/* Assume we are not debugging. */
lexer->debugging_p = false;
return lexer;
}
/* Create a new lexer whose token stream is primed with the TOKENS.
When these tokens are exhausted, no new tokens will be read. */
static cp_lexer *
cp_lexer_new_from_tokens (cp_token_cache *tokens)
{
cp_lexer *lexer;
cp_token *token;
cp_token_block *block;
ptrdiff_t num_tokens;
/* Allocate the memory. */
lexer = ggc_alloc_cleared (sizeof (cp_lexer));
/* Create a new buffer, appropriately sized. */
num_tokens = 0;
for (block = tokens->first; block != NULL; block = block->next)
num_tokens += block->num_tokens;
lexer->buffer = ggc_alloc (num_tokens * sizeof (cp_token));
lexer->buffer_end = lexer->buffer + num_tokens;
/* Install the tokens. */
token = lexer->buffer;
for (block = tokens->first; block != NULL; block = block->next)
{
memcpy (token, block->tokens, block->num_tokens * sizeof (cp_token));
token += block->num_tokens;
}
/* The FIRST_TOKEN is the beginning of the buffer. */
lexer->first_token = lexer->buffer;
/* The next available token is also at the beginning of the buffer. */
lexer->next_token = lexer->buffer;
/* The buffer is full. */
lexer->last_token = lexer->first_token;
/* This lexer doesn't obtain more tokens. */
lexer->main_lexer_p = false;
/* Create the SAVED_TOKENS stack. */
VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens");
/* Create the STRINGS array. */
VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings");
/* Assume we are not debugging. */
lexer->debugging_p = false;
return lexer;
}
/* Returns nonzero if debugging information should be output. */
static inline bool
cp_lexer_debugging_p (cp_lexer *lexer)
{
return lexer->debugging_p;
}
/* Set the current source position from the information stored in
TOKEN. */
static inline void
cp_lexer_set_source_position_from_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
const cp_token *token)
{
/* Ideally, the source position information would not be a global
variable, but it is. */
/* Update the line number. */
if (token->type != CPP_EOF)
input_location = token->location;
}
/* TOKEN points into the circular token buffer. Return a pointer to
the next token in the buffer. */
static inline cp_token *
cp_lexer_next_token (cp_lexer* lexer, cp_token* token)
{
token++;
if (token == lexer->buffer_end)
token = lexer->buffer;
return token;
}
/* TOKEN points into the circular token buffer. Return a pointer to
the previous token in the buffer. */
static inline cp_token *
cp_lexer_prev_token (cp_lexer* lexer, cp_token* token)
{
if (token == lexer->buffer)
token = lexer->buffer_end;
return token - 1;
}
/* nonzero if we are presently saving tokens. */
static int
cp_lexer_saving_tokens (const cp_lexer* lexer)
{
return VARRAY_ACTIVE_SIZE (lexer->saved_tokens) != 0;
}
/* Return a pointer to the token that is N tokens beyond TOKEN in the
buffer. */
static cp_token *
cp_lexer_advance_token (cp_lexer *lexer, cp_token *token, ptrdiff_t n)
{
token += n;
if (token >= lexer->buffer_end)
token = lexer->buffer + (token - lexer->buffer_end);
return token;
}
/* Returns the number of times that START would have to be incremented
to reach FINISH. If START and FINISH are the same, returns zero. */
static ptrdiff_t
cp_lexer_token_difference (cp_lexer* lexer, cp_token* start, cp_token* finish)
{
if (finish >= start)
return finish - start;
else
return ((lexer->buffer_end - lexer->buffer)
- (start - finish));
}
/* Obtain another token from the C preprocessor and add it to the
token buffer. Returns the newly read token. */
static cp_token *
cp_lexer_read_token (cp_lexer* lexer)
{
cp_token *token;
/* Make sure there is room in the buffer. */
cp_lexer_maybe_grow_buffer (lexer);
/* If there weren't any tokens, then this one will be the first. */
if (!lexer->first_token)
lexer->first_token = lexer->last_token;
/* Similarly, if there were no available tokens, there is one now. */
if (!lexer->next_token)
lexer->next_token = lexer->last_token;
/* Figure out where we're going to store the new token. */
token = lexer->last_token;
/* Get a new token from the preprocessor. */
cp_lexer_get_preprocessor_token (lexer, token);
/* Increment LAST_TOKEN. */
lexer->last_token = cp_lexer_next_token (lexer, token);
/* Strings should have type `const char []'. Right now, we will
have an ARRAY_TYPE that is constant rather than an array of
constant elements.
FIXME: Make fix_string_type get this right in the first place. */
if ((token->type == CPP_STRING || token->type == CPP_WSTRING)
&& flag_const_strings)
{
tree type;
/* Get the current type. It will be an ARRAY_TYPE. */
type = TREE_TYPE (token->value);
/* Use build_cplus_array_type to rebuild the array, thereby
getting the right type. */
type = build_cplus_array_type (TREE_TYPE (type), TYPE_DOMAIN (type));
/* Reset the type of the token. */
TREE_TYPE (token->value) = type;
}
return token;
}
/* If the circular buffer is full, make it bigger. */
static void
cp_lexer_maybe_grow_buffer (cp_lexer* lexer)
{
/* If the buffer is full, enlarge it. */
if (lexer->last_token == lexer->first_token)
{
cp_token *new_buffer;
cp_token *old_buffer;
cp_token *new_first_token;
ptrdiff_t buffer_length;
size_t num_tokens_to_copy;
/* Remember the current buffer pointer. It will become invalid,
but we will need to do pointer arithmetic involving this
value. */
old_buffer = lexer->buffer;
/* Compute the current buffer size. */
buffer_length = lexer->buffer_end - lexer->buffer;
/* Allocate a buffer twice as big. */
new_buffer = ggc_realloc (lexer->buffer,
2 * buffer_length * sizeof (cp_token));
/* Because the buffer is circular, logically consecutive tokens
are not necessarily placed consecutively in memory.
Therefore, we must keep move the tokens that were before
FIRST_TOKEN to the second half of the newly allocated
buffer. */
num_tokens_to_copy = (lexer->first_token - old_buffer);
memcpy (new_buffer + buffer_length,
new_buffer,
num_tokens_to_copy * sizeof (cp_token));
/* Clear the rest of the buffer. We never look at this storage,
but the garbage collector may. */
memset (new_buffer + buffer_length + num_tokens_to_copy, 0,
(buffer_length - num_tokens_to_copy) * sizeof (cp_token));
/* Now recompute all of the buffer pointers. */
new_first_token
= new_buffer + (lexer->first_token - old_buffer);
if (lexer->next_token != NULL)
{
ptrdiff_t next_token_delta;
if (lexer->next_token > lexer->first_token)
next_token_delta = lexer->next_token - lexer->first_token;
else
next_token_delta =
buffer_length - (lexer->first_token - lexer->next_token);
lexer->next_token = new_first_token + next_token_delta;
}
lexer->last_token = new_first_token + buffer_length;
lexer->buffer = new_buffer;
lexer->buffer_end = new_buffer + buffer_length * 2;
lexer->first_token = new_first_token;
}
}
/* Store the next token from the preprocessor in *TOKEN. */
static void
cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
cp_token *token)
{
bool done;
/* If this not the main lexer, return a terminating CPP_EOF token. */
if (lexer != NULL && !lexer->main_lexer_p)
{
token->type = CPP_EOF;
token->location.line = 0;
token->location.file = NULL;
token->value = NULL_TREE;
token->keyword = RID_MAX;
return;
}
done = false;
/* Keep going until we get a token we like. */
while (!done)
{
/* Get a new token from the preprocessor. */
token->type = c_lex_with_flags (&token->value, &token->flags);
/* Issue messages about tokens we cannot process. */
switch (token->type)
{
case CPP_ATSIGN:
case CPP_HASH:
case CPP_PASTE:
error ("invalid token");
break;
default:
/* This is a good token, so we exit the loop. */
done = true;
break;
}
}
/* Now we've got our token. */
token->location = input_location;
/* Check to see if this token is a keyword. */
if (token->type == CPP_NAME
&& C_IS_RESERVED_WORD (token->value))
{
/* Mark this token as a keyword. */
token->type = CPP_KEYWORD;
/* Record which keyword. */
token->keyword = C_RID_CODE (token->value);
/* Update the value. Some keywords are mapped to particular
entities, rather than simply having the value of the
corresponding IDENTIFIER_NODE. For example, `__const' is
mapped to `const'. */
token->value = ridpointers[token->keyword];
}
else
token->keyword = RID_MAX;
}
/* Return a pointer to the next token in the token stream, but do not
consume it. */
static cp_token *
cp_lexer_peek_token (cp_lexer* lexer)
{
cp_token *token;
/* If there are no tokens, read one now. */
if (!lexer->next_token)
cp_lexer_read_token (lexer);
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
{
fprintf (cp_lexer_debug_stream, "cp_lexer: peeking at token: ");
cp_lexer_print_token (cp_lexer_debug_stream, lexer->next_token);
fprintf (cp_lexer_debug_stream, "\n");
}
token = lexer->next_token;
cp_lexer_set_source_position_from_token (lexer, token);
return token;
}
/* Return true if the next token has the indicated TYPE. */
static bool
cp_lexer_next_token_is (cp_lexer* lexer, enum cpp_ttype type)
{
cp_token *token;
/* Peek at the next token. */
token = cp_lexer_peek_token (lexer);
/* Check to see if it has the indicated TYPE. */
return token->type == type;
}
/* Return true if the next token does not have the indicated TYPE. */
static bool
cp_lexer_next_token_is_not (cp_lexer* lexer, enum cpp_ttype type)
{
return !cp_lexer_next_token_is (lexer, type);
}
/* Return true if the next token is the indicated KEYWORD. */
static bool
cp_lexer_next_token_is_keyword (cp_lexer* lexer, enum rid keyword)
{
cp_token *token;
/* Peek at the next token. */
token = cp_lexer_peek_token (lexer);
/* Check to see if it is the indicated keyword. */
return token->keyword == keyword;
}
/* Return a pointer to the Nth token in the token stream. If N is 1,
then this is precisely equivalent to cp_lexer_peek_token. */
static cp_token *
cp_lexer_peek_nth_token (cp_lexer* lexer, size_t n)
{
cp_token *token;
/* N is 1-based, not zero-based. */
my_friendly_assert (n > 0, 20000224);
/* Skip ahead from NEXT_TOKEN, reading more tokens as necessary. */
token = lexer->next_token;
/* If there are no tokens in the buffer, get one now. */
if (!token)
{
cp_lexer_read_token (lexer);
token = lexer->next_token;
}
/* Now, read tokens until we have enough. */
while (--n > 0)
{
/* Advance to the next token. */
token = cp_lexer_next_token (lexer, token);
/* If that's all the tokens we have, read a new one. */
if (token == lexer->last_token)
token = cp_lexer_read_token (lexer);
}
return token;
}
/* Consume the next token. The pointer returned is valid only until
another token is read. Callers should preserve copy the token
explicitly if they will need its value for a longer period of
time. */
static cp_token *
cp_lexer_consume_token (cp_lexer* lexer)
{
cp_token *token;
/* If there are no tokens, read one now. */
if (!lexer->next_token)
cp_lexer_read_token (lexer);
/* Remember the token we'll be returning. */
token = lexer->next_token;
/* Increment NEXT_TOKEN. */
lexer->next_token = cp_lexer_next_token (lexer,
lexer->next_token);
/* Check to see if we're all out of tokens. */
if (lexer->next_token == lexer->last_token)
lexer->next_token = NULL;
/* If we're not saving tokens, then move FIRST_TOKEN too. */
if (!cp_lexer_saving_tokens (lexer))
{
/* If there are no tokens available, set FIRST_TOKEN to NULL. */
if (!lexer->next_token)
lexer->first_token = NULL;
else
lexer->first_token = lexer->next_token;
}
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
{
fprintf (cp_lexer_debug_stream, "cp_lexer: consuming token: ");
cp_lexer_print_token (cp_lexer_debug_stream, token);
fprintf (cp_lexer_debug_stream, "\n");
}
return token;
}
/* Permanently remove the next token from the token stream. There
must be a valid next token already; this token never reads
additional tokens from the preprocessor. */
static void
cp_lexer_purge_token (cp_lexer *lexer)
{
cp_token *token;
cp_token *next_token;
token = lexer->next_token;
while (true)
{
next_token = cp_lexer_next_token (lexer, token);
if (next_token == lexer->last_token)
break;
*token = *next_token;
token = next_token;
}
lexer->last_token = token;
/* The token purged may have been the only token remaining; if so,
clear NEXT_TOKEN. */
if (lexer->next_token == token)
lexer->next_token = NULL;
}
/* Permanently remove all tokens after TOKEN, up to, but not
including, the token that will be returned next by
cp_lexer_peek_token. */
static void
cp_lexer_purge_tokens_after (cp_lexer *lexer, cp_token *token)
{
cp_token *peek;
cp_token *t1;
cp_token *t2;
if (lexer->next_token)
{
/* Copy the tokens that have not yet been read to the location
immediately following TOKEN. */
t1 = cp_lexer_next_token (lexer, token);
t2 = peek = cp_lexer_peek_token (lexer);
/* Move tokens into the vacant area between TOKEN and PEEK. */
while (t2 != lexer->last_token)
{
*t1 = *t2;
t1 = cp_lexer_next_token (lexer, t1);
t2 = cp_lexer_next_token (lexer, t2);
}
/* Now, the next available token is right after TOKEN. */
lexer->next_token = cp_lexer_next_token (lexer, token);
/* And the last token is wherever we ended up. */
lexer->last_token = t1;
}
else
{
/* There are no tokens in the buffer, so there is nothing to
copy. The last token in the buffer is TOKEN itself. */
lexer->last_token = cp_lexer_next_token (lexer, token);
}
}
/* Begin saving tokens. All tokens consumed after this point will be
preserved. */
static void
cp_lexer_save_tokens (cp_lexer* lexer)
{
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: saving tokens\n");
/* Make sure that LEXER->NEXT_TOKEN is non-NULL so that we can
restore the tokens if required. */
if (!lexer->next_token)
cp_lexer_read_token (lexer);
VARRAY_PUSH_INT (lexer->saved_tokens,
cp_lexer_token_difference (lexer,
lexer->first_token,
lexer->next_token));
}
/* Commit to the portion of the token stream most recently saved. */
static void
cp_lexer_commit_tokens (cp_lexer* lexer)
{
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: committing tokens\n");
VARRAY_POP (lexer->saved_tokens);
}
/* Return all tokens saved since the last call to cp_lexer_save_tokens
to the token stream. Stop saving tokens. */
static void
cp_lexer_rollback_tokens (cp_lexer* lexer)
{
size_t delta;
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: restoring tokens\n");
/* Find the token that was the NEXT_TOKEN when we started saving
tokens. */
delta = VARRAY_TOP_INT(lexer->saved_tokens);
/* Make it the next token again now. */
lexer->next_token = cp_lexer_advance_token (lexer,
lexer->first_token,
delta);
/* It might be the case that there were no tokens when we started
saving tokens, but that there are some tokens now. */
if (!lexer->next_token && lexer->first_token)
lexer->next_token = lexer->first_token;
/* Stop saving tokens. */
VARRAY_POP (lexer->saved_tokens);
}
/* Print a representation of the TOKEN on the STREAM. */
static void
cp_lexer_print_token (FILE * stream, cp_token* token)
{
const char *token_type = NULL;
/* Figure out what kind of token this is. */
switch (token->type)
{
case CPP_EQ:
token_type = "EQ";
break;
case CPP_COMMA:
token_type = "COMMA";
break;
case CPP_OPEN_PAREN:
token_type = "OPEN_PAREN";
break;
case CPP_CLOSE_PAREN:
token_type = "CLOSE_PAREN";
break;
case CPP_OPEN_BRACE:
token_type = "OPEN_BRACE";
break;
case CPP_CLOSE_BRACE:
token_type = "CLOSE_BRACE";
break;
case CPP_SEMICOLON:
token_type = "SEMICOLON";
break;
case CPP_NAME:
token_type = "NAME";
break;
case CPP_EOF:
token_type = "EOF";
break;
case CPP_KEYWORD:
token_type = "keyword";
break;
/* This is not a token that we know how to handle yet. */
default:
break;
}
/* If we have a name for the token, print it out. Otherwise, we
simply give the numeric code. */
if (token_type)
fprintf (stream, "%s", token_type);
else
fprintf (stream, "%d", token->type);
/* And, for an identifier, print the identifier name. */
if (token->type == CPP_NAME
/* Some keywords have a value that is not an IDENTIFIER_NODE.
For example, `struct' is mapped to an INTEGER_CST. */
|| (token->type == CPP_KEYWORD
&& TREE_CODE (token->value) == IDENTIFIER_NODE))
fprintf (stream, " %s", IDENTIFIER_POINTER (token->value));
}
/* Start emitting debugging information. */
static void
cp_lexer_start_debugging (cp_lexer* lexer)
{
++lexer->debugging_p;
}
/* Stop emitting debugging information. */
static void
cp_lexer_stop_debugging (cp_lexer* lexer)
{
--lexer->debugging_p;
}
/* The parser. */
/* Overview
--------
A cp_parser parses the token stream as specified by the C++
grammar. Its job is purely parsing, not semantic analysis. For
example, the parser breaks the token stream into declarators,
expressions, statements, and other similar syntactic constructs.
It does not check that the types of the expressions on either side
of an assignment-statement are compatible, or that a function is
not declared with a parameter of type `void'.
The parser invokes routines elsewhere in the compiler to perform
semantic analysis and to build up the abstract syntax tree for the
code processed.
The parser (and the template instantiation code, which is, in a
way, a close relative of parsing) are the only parts of the
compiler that should be calling push_scope and pop_scope, or
related functions. The parser (and template instantiation code)
keeps track of what scope is presently active; everything else
should simply honor that. (The code that generates static
initializers may also need to set the scope, in order to check
access control correctly when emitting the initializers.)
Methodology
-----------
The parser is of the standard recursive-descent variety. Upcoming
tokens in the token stream are examined in order to determine which
production to use when parsing a non-terminal. Some C++ constructs
require arbitrary look ahead to disambiguate. For example, it is
impossible, in the general case, to tell whether a statement is an
expression or declaration without scanning the entire statement.
Therefore, the parser is capable of "parsing tentatively." When the
parser is not sure what construct comes next, it enters this mode.
Then, while we attempt to parse the construct, the parser queues up
error messages, rather than issuing them immediately, and saves the
tokens it consumes. If the construct is parsed successfully, the
parser "commits", i.e., it issues any queued error messages and
the tokens that were being preserved are permanently discarded.
If, however, the construct is not parsed successfully, the parser
rolls back its state completely so that it can resume parsing using
a different alternative.
Future Improvements
-------------------
The performance of the parser could probably be improved
substantially. Some possible improvements include:
- The expression parser recurses through the various levels of
precedence as specified in the grammar, rather than using an
operator-precedence technique. Therefore, parsing a simple
identifier requires multiple recursive calls.
- We could often eliminate the need to parse tentatively by
looking ahead a little bit. In some places, this approach
might not entirely eliminate the need to parse tentatively, but
it might still speed up the average case. */
/* Flags that are passed to some parsing functions. These values can
be bitwise-ored together. */
typedef enum cp_parser_flags
{
/* No flags. */
CP_PARSER_FLAGS_NONE = 0x0,
/* The construct is optional. If it is not present, then no error
should be issued. */
CP_PARSER_FLAGS_OPTIONAL = 0x1,
/* When parsing a type-specifier, do not allow user-defined types. */
CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2
} cp_parser_flags;
/* The different kinds of declarators we want to parse. */
typedef enum cp_parser_declarator_kind
{
/* We want an abstract declartor. */
CP_PARSER_DECLARATOR_ABSTRACT,
/* We want a named declarator. */
CP_PARSER_DECLARATOR_NAMED,
/* We don't mind, but the name must be an unqualified-id. */
CP_PARSER_DECLARATOR_EITHER
} cp_parser_declarator_kind;
/* A mapping from a token type to a corresponding tree node type. */
typedef struct cp_parser_token_tree_map_node
{
/* The token type. */
ENUM_BITFIELD (cpp_ttype) token_type : 8;
/* The corresponding tree code. */
ENUM_BITFIELD (tree_code) tree_type : 8;
} cp_parser_token_tree_map_node;
/* A complete map consists of several ordinary entries, followed by a
terminator. The terminating entry has a token_type of CPP_EOF. */
typedef cp_parser_token_tree_map_node cp_parser_token_tree_map[];
/* The status of a tentative parse. */
typedef enum cp_parser_status_kind
{
/* No errors have occurred. */
CP_PARSER_STATUS_KIND_NO_ERROR,
/* An error has occurred. */
CP_PARSER_STATUS_KIND_ERROR,
/* We are committed to this tentative parse, whether or not an error
has occurred. */
CP_PARSER_STATUS_KIND_COMMITTED
} cp_parser_status_kind;
/* Context that is saved and restored when parsing tentatively. */
typedef struct cp_parser_context GTY (())
{
/* If this is a tentative parsing context, the status of the
tentative parse. */
enum cp_parser_status_kind status;
/* If non-NULL, we have just seen a `x->' or `x.' expression. Names
that are looked up in this context must be looked up both in the
scope given by OBJECT_TYPE (the type of `x' or `*x') and also in
the context of the containing expression. */
tree object_type;
/* The next parsing context in the stack. */
struct cp_parser_context *next;
} cp_parser_context;
/* Prototypes. */
/* Constructors and destructors. */
static cp_parser_context *cp_parser_context_new
(cp_parser_context *);
/* Class variables. */
static GTY((deletable (""))) cp_parser_context* cp_parser_context_free_list;
/* Constructors and destructors. */
/* Construct a new context. The context below this one on the stack
is given by NEXT. */
static cp_parser_context *
cp_parser_context_new (cp_parser_context* next)
{
cp_parser_context *context;
/* Allocate the storage. */
if (cp_parser_context_free_list != NULL)
{
/* Pull the first entry from the free list. */
context = cp_parser_context_free_list;
cp_parser_context_free_list = context->next;
memset (context, 0, sizeof (*context));
}
else
context = ggc_alloc_cleared (sizeof (cp_parser_context));
/* No errors have occurred yet in this context. */
context->status = CP_PARSER_STATUS_KIND_NO_ERROR;
/* If this is not the bottomost context, copy information that we
need from the previous context. */
if (next)
{
/* If, in the NEXT context, we are parsing an `x->' or `x.'
expression, then we are parsing one in this context, too. */
context->object_type = next->object_type;
/* Thread the stack. */
context->next = next;
}
return context;
}
/* The cp_parser structure represents the C++ parser. */
typedef struct cp_parser GTY(())
{
/* The lexer from which we are obtaining tokens. */
cp_lexer *lexer;
/* The scope in which names should be looked up. If NULL_TREE, then
we look up names in the scope that is currently open in the
source program. If non-NULL, this is either a TYPE or
NAMESPACE_DECL for the scope in which we should look.
This value is not cleared automatically after a name is looked
up, so we must be careful to clear it before starting a new look
up sequence. (If it is not cleared, then `X::Y' followed by `Z'
will look up `Z' in the scope of `X', rather than the current
scope.) Unfortunately, it is difficult to tell when name lookup
is complete, because we sometimes peek at a token, look it up,
and then decide not to consume it. */
tree scope;
/* OBJECT_SCOPE and QUALIFYING_SCOPE give the scopes in which the
last lookup took place. OBJECT_SCOPE is used if an expression
like "x->y" or "x.y" was used; it gives the type of "*x" or "x",
respectively. QUALIFYING_SCOPE is used for an expression of the
form "X::Y"; it refers to X. */
tree object_scope;
tree qualifying_scope;
/* A stack of parsing contexts. All but the bottom entry on the
stack will be tentative contexts.
We parse tentatively in order to determine which construct is in
use in some situations. For example, in order to determine
whether a statement is an expression-statement or a
declaration-statement we parse it tentatively as a
declaration-statement. If that fails, we then reparse the same
token stream as an expression-statement. */
cp_parser_context *context;
/* True if we are parsing GNU C++. If this flag is not set, then
GNU extensions are not recognized. */
bool allow_gnu_extensions_p;
/* TRUE if the `>' token should be interpreted as the greater-than
operator. FALSE if it is the end of a template-id or
template-parameter-list. */
bool greater_than_is_operator_p;
/* TRUE if default arguments are allowed within a parameter list
that starts at this point. FALSE if only a gnu extension makes
them permissible. */
bool default_arg_ok_p;
/* TRUE if we are parsing an integral constant-expression. See
[expr.const] for a precise definition. */
bool integral_constant_expression_p;
/* TRUE if we are parsing an integral constant-expression -- but a
non-constant expression should be permitted as well. This flag
is used when parsing an array bound so that GNU variable-length
arrays are tolerated. */
bool allow_non_integral_constant_expression_p;
/* TRUE if ALLOW_NON_CONSTANT_EXPRESSION_P is TRUE and something has
been seen that makes the expression non-constant. */
bool non_integral_constant_expression_p;
/* TRUE if we are parsing the argument to "__offsetof__". */
bool in_offsetof_p;
/* TRUE if local variable names and `this' are forbidden in the
current context. */
bool local_variables_forbidden_p;
/* TRUE if the declaration we are parsing is part of a
linkage-specification of the form `extern string-literal
declaration'. */
bool in_unbraced_linkage_specification_p;
/* TRUE if we are presently parsing a declarator, after the
direct-declarator. */
bool in_declarator_p;
/* TRUE if we are presently parsing a template-argument-list. */
bool in_template_argument_list_p;
/* TRUE if we are presently parsing the body of an
iteration-statement. */
bool in_iteration_statement_p;
/* TRUE if we are presently parsing the body of a switch
statement. */
bool in_switch_statement_p;
/* TRUE if we are parsing a type-id in an expression context. In
such a situation, both "type (expr)" and "type (type)" are valid
alternatives. */
bool in_type_id_in_expr_p;
/* If non-NULL, then we are parsing a construct where new type
definitions are not permitted. The string stored here will be
issued as an error message if a type is defined. */
const char *type_definition_forbidden_message;
/* A list of lists. The outer list is a stack, used for member
functions of local classes. At each level there are two sub-list,
one on TREE_VALUE and one on TREE_PURPOSE. Each of those
sub-lists has a FUNCTION_DECL or TEMPLATE_DECL on their
TREE_VALUE's. The functions are chained in reverse declaration
order.
The TREE_PURPOSE sublist contains those functions with default
arguments that need post processing, and the TREE_VALUE sublist
contains those functions with definitions that need post
processing.
These lists can only be processed once the outermost class being
defined is complete. */
tree unparsed_functions_queues;
/* The number of classes whose definitions are currently in
progress. */
unsigned num_classes_being_defined;
/* The number of template parameter lists that apply directly to the
current declaration. */
unsigned num_template_parameter_lists;
} cp_parser;
/* The type of a function that parses some kind of expression. */
typedef tree (*cp_parser_expression_fn) (cp_parser *);
/* Prototypes. */
/* Constructors and destructors. */
static cp_parser *cp_parser_new
(void);
/* Routines to parse various constructs.
Those that return `tree' will return the error_mark_node (rather
than NULL_TREE) if a parse error occurs, unless otherwise noted.
Sometimes, they will return an ordinary node if error-recovery was
attempted, even though a parse error occurred. So, to check
whether or not a parse error occurred, you should always use
cp_parser_error_occurred. If the construct is optional (indicated
either by an `_opt' in the name of the function that does the
parsing or via a FLAGS parameter), then NULL_TREE is returned if
the construct is not present. */
/* Lexical conventions [gram.lex] */
static tree cp_parser_identifier
(cp_parser *);
/* Basic concepts [gram.basic] */
static bool cp_parser_translation_unit
(cp_parser *);
/* Expressions [gram.expr] */
static tree cp_parser_primary_expression
(cp_parser *, cp_id_kind *, tree *);
static tree cp_parser_id_expression
(cp_parser *, bool, bool, bool *, bool);
static tree cp_parser_unqualified_id
(cp_parser *, bool, bool, bool);
static tree cp_parser_nested_name_specifier_opt
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_nested_name_specifier
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_class_or_namespace_name
(cp_parser *, bool, bool, bool, bool, bool);
static tree cp_parser_postfix_expression
(cp_parser *, bool);
static tree cp_parser_parenthesized_expression_list
(cp_parser *, bool, bool *);
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree *, tree *);
static tree cp_parser_unary_expression
(cp_parser *, bool);
static enum tree_code cp_parser_unary_operator
(cp_token *);
static tree cp_parser_new_expression
(cp_parser *);
static tree cp_parser_new_placement
(cp_parser *);
static tree cp_parser_new_type_id
(cp_parser *);
static tree cp_parser_new_declarator_opt
(cp_parser *);
static tree cp_parser_direct_new_declarator
(cp_parser *);
static tree cp_parser_new_initializer
(cp_parser *);
static tree cp_parser_delete_expression
(cp_parser *);
static tree cp_parser_cast_expression
(cp_parser *, bool);
static tree cp_parser_pm_expression
(cp_parser *);
static tree cp_parser_multiplicative_expression
(cp_parser *);
static tree cp_parser_additive_expression
(cp_parser *);
static tree cp_parser_shift_expression
(cp_parser *);
static tree cp_parser_relational_expression
(cp_parser *);
static tree cp_parser_equality_expression
(cp_parser *);
static tree cp_parser_and_expression
(cp_parser *);
static tree cp_parser_exclusive_or_expression
(cp_parser *);
static tree cp_parser_inclusive_or_expression
(cp_parser *);
static tree cp_parser_logical_and_expression
(cp_parser *);
static tree cp_parser_logical_or_expression
(cp_parser *);
static tree cp_parser_question_colon_clause
(cp_parser *, tree);
static tree cp_parser_assignment_expression
(cp_parser *);
static enum tree_code cp_parser_assignment_operator_opt
(cp_parser *);
static tree cp_parser_expression
(cp_parser *);
static tree cp_parser_constant_expression
(cp_parser *, bool, bool *);
/* Statements [gram.stmt.stmt] */
static void cp_parser_statement
(cp_parser *, bool);
static tree cp_parser_labeled_statement
(cp_parser *, bool);
static tree cp_parser_expression_statement
(cp_parser *, bool);
static tree cp_parser_compound_statement
(cp_parser *, bool);
static void cp_parser_statement_seq_opt
(cp_parser *, bool);
static tree cp_parser_selection_statement
(cp_parser *);
static tree cp_parser_condition
(cp_parser *);
static tree cp_parser_iteration_statement
(cp_parser *);
static void cp_parser_for_init_statement
(cp_parser *);
static tree cp_parser_jump_statement
(cp_parser *);
static void cp_parser_declaration_statement
(cp_parser *);
static tree cp_parser_implicitly_scoped_statement
(cp_parser *);
static void cp_parser_already_scoped_statement
(cp_parser *);
/* Declarations [gram.dcl.dcl] */
static void cp_parser_declaration_seq_opt
(cp_parser *);
static void cp_parser_declaration
(cp_parser *);
static void cp_parser_block_declaration
(cp_parser *, bool);
static void cp_parser_simple_declaration
(cp_parser *, bool);
static tree cp_parser_decl_specifier_seq
(cp_parser *, cp_parser_flags, tree *, int *);
static tree cp_parser_storage_class_specifier_opt
(cp_parser *);
static tree cp_parser_function_specifier_opt
(cp_parser *);
static tree cp_parser_type_specifier
(cp_parser *, cp_parser_flags, bool, bool, int *, bool *);
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_parser_flags, bool);
static tree cp_parser_type_name
(cp_parser *);
static tree cp_parser_elaborated_type_specifier
(cp_parser *, bool, bool);
static tree cp_parser_enum_specifier
(cp_parser *);
static void cp_parser_enumerator_list
(cp_parser *, tree);
static void cp_parser_enumerator_definition
(cp_parser *, tree);
static tree cp_parser_namespace_name
(cp_parser *);
static void cp_parser_namespace_definition
(cp_parser *);
static void cp_parser_namespace_body
(cp_parser *);
static tree cp_parser_qualified_namespace_specifier
(cp_parser *);
static void cp_parser_namespace_alias_definition
(cp_parser *);
static void cp_parser_using_declaration
(cp_parser *);
static void cp_parser_using_directive
(cp_parser *);
static void cp_parser_asm_definition
(cp_parser *);
static void cp_parser_linkage_specification
(cp_parser *);
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
(cp_parser *, tree, tree, bool, bool, int, bool *);
static tree cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool *);
static tree cp_parser_direct_declarator
(cp_parser *, cp_parser_declarator_kind, int *);
static enum tree_code cp_parser_ptr_operator
(cp_parser *, tree *, tree *);
static tree cp_parser_cv_qualifier_seq_opt
(cp_parser *);
static tree cp_parser_cv_qualifier_opt
(cp_parser *);
static tree cp_parser_declarator_id
(cp_parser *);
static tree cp_parser_type_id
(cp_parser *);
static tree cp_parser_type_specifier_seq
(cp_parser *);
static tree cp_parser_parameter_declaration_clause
(cp_parser *);
static tree cp_parser_parameter_declaration_list
(cp_parser *);
static tree cp_parser_parameter_declaration
(cp_parser *, bool, bool *);
static void cp_parser_function_body
(cp_parser *);
static tree cp_parser_initializer
(cp_parser *, bool *, bool *);
static tree cp_parser_initializer_clause
(cp_parser *, bool *);
static tree cp_parser_initializer_list
(cp_parser *, bool *);
static bool cp_parser_ctor_initializer_opt_and_function_body
(cp_parser *);
/* Classes [gram.class] */
static tree cp_parser_class_name
(cp_parser *, bool, bool, bool, bool, bool, bool);
static tree cp_parser_class_specifier
(cp_parser *);
static tree cp_parser_class_head
(cp_parser *, bool *, tree *);
static enum tag_types cp_parser_class_key
(cp_parser *);
static void cp_parser_member_specification_opt
(cp_parser *);
static void cp_parser_member_declaration
(cp_parser *);
static tree cp_parser_pure_specifier
(cp_parser *);
static tree cp_parser_constant_initializer
(cp_parser *);
/* Derived classes [gram.class.derived] */
static tree cp_parser_base_clause
(cp_parser *);
static tree cp_parser_base_specifier
(cp_parser *);
/* Special member functions [gram.special] */
static tree cp_parser_conversion_function_id
(cp_parser *);
static tree cp_parser_conversion_type_id
(cp_parser *);
static tree cp_parser_conversion_declarator_opt
(cp_parser *);
static bool cp_parser_ctor_initializer_opt
(cp_parser *);
static void cp_parser_mem_initializer_list
(cp_parser *);
static tree cp_parser_mem_initializer
(cp_parser *);
static tree cp_parser_mem_initializer_id
(cp_parser *);
/* Overloading [gram.over] */
static tree cp_parser_operator_function_id
(cp_parser *);
static tree cp_parser_operator
(cp_parser *);
/* Templates [gram.temp] */
static void cp_parser_template_declaration
(cp_parser *, bool);
static tree cp_parser_template_parameter_list
(cp_parser *);
static tree cp_parser_template_parameter
(cp_parser *);
static tree cp_parser_type_parameter
(cp_parser *);
static tree cp_parser_template_id
(cp_parser *, bool, bool, bool);
static tree cp_parser_template_name
(cp_parser *, bool, bool, bool, bool *);
static tree cp_parser_template_argument_list
(cp_parser *);
static tree cp_parser_template_argument
(cp_parser *);
static void cp_parser_explicit_instantiation
(cp_parser *);
static void cp_parser_explicit_specialization
(cp_parser *);
/* Exception handling [gram.exception] */
static tree cp_parser_try_block
(cp_parser *);
static bool cp_parser_function_try_block
(cp_parser *);
static void cp_parser_handler_seq
(cp_parser *);
static void cp_parser_handler
(cp_parser *);
static tree cp_parser_exception_declaration
(cp_parser *);
static tree cp_parser_throw_expression
(cp_parser *);
static tree cp_parser_exception_specification_opt
(cp_parser *);
static tree cp_parser_type_id_list
(cp_parser *);
/* GNU Extensions */
static tree cp_parser_asm_specification_opt
(cp_parser *);
static tree cp_parser_asm_operand_list
(cp_parser *);
static tree cp_parser_asm_clobber_list
(cp_parser *);
static tree cp_parser_attributes_opt
(cp_parser *);
static tree cp_parser_attribute_list
(cp_parser *);
static bool cp_parser_extension_opt
(cp_parser *, int *);
static void cp_parser_label_declaration
(cp_parser *);
/* Utility Routines */
static tree cp_parser_lookup_name
(cp_parser *, tree, bool, bool, bool, bool);
static tree cp_parser_lookup_name_simple
(cp_parser *, tree);
static tree cp_parser_maybe_treat_template_as_class
(tree, bool);
static bool cp_parser_check_declarator_template_parameters
(cp_parser *, tree);
static bool cp_parser_check_template_parameters
(cp_parser *, unsigned);
static tree cp_parser_simple_cast_expression
(cp_parser *);
static tree cp_parser_binary_expression
(cp_parser *, const cp_parser_token_tree_map, cp_parser_expression_fn);
static tree cp_parser_global_scope_opt
(cp_parser *, bool);
static bool cp_parser_constructor_declarator_p
(cp_parser *, bool);
static tree cp_parser_function_definition_from_specifiers_and_declarator
(cp_parser *, tree, tree, tree);
static tree cp_parser_function_definition_after_declarator
(cp_parser *, bool);
static void cp_parser_template_declaration_after_export
(cp_parser *, bool);
static tree cp_parser_single_declaration
(cp_parser *, bool, bool *);
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
(cp_parser *, tree, tree, tree);
static tree cp_parser_enclosed_template_argument_list
(cp_parser *);
static void cp_parser_save_default_args
(cp_parser *, tree);
static void cp_parser_late_parsing_for_member
(cp_parser *, tree);
static void cp_parser_late_parsing_default_args
(cp_parser *, tree);
static tree cp_parser_sizeof_operand
(cp_parser *, enum rid);
static bool cp_parser_declares_only_class_p
(cp_parser *);
static bool cp_parser_friend_p
(tree);
static cp_token *cp_parser_require
(cp_parser *, enum cpp_ttype, const char *);
static cp_token *cp_parser_require_keyword
(cp_parser *, enum rid, const char *);
static bool cp_parser_token_starts_function_definition_p
(cp_token *);
static bool cp_parser_next_token_starts_class_definition_p
(cp_parser *);
static bool cp_parser_next_token_ends_template_argument_p
(cp_parser *);
static bool cp_parser_nth_token_starts_template_argument_list_p
(cp_parser *, size_t);
static enum tag_types cp_parser_token_is_class_key
(cp_token *);
static void cp_parser_check_class_key
(enum tag_types, tree type);
static void cp_parser_check_access_in_redeclaration
(tree type);
static bool cp_parser_optional_template_keyword
(cp_parser *);
static void cp_parser_pre_parsed_nested_name_specifier
(cp_parser *);
static void cp_parser_cache_group
(cp_parser *, cp_token_cache *, enum cpp_ttype, unsigned);
static void cp_parser_parse_tentatively
(cp_parser *);
static void cp_parser_commit_to_tentative_parse
(cp_parser *);
static void cp_parser_abort_tentative_parse
(cp_parser *);
static bool cp_parser_parse_definitely
(cp_parser *);
static inline bool cp_parser_parsing_tentatively
(cp_parser *);
static bool cp_parser_committed_to_tentative_parse
(cp_parser *);
static void cp_parser_error
(cp_parser *, const char *);
static void cp_parser_name_lookup_error
(cp_parser *, tree, tree, const char *);
static bool cp_parser_simulate_error
(cp_parser *);
static void cp_parser_check_type_definition
(cp_parser *);
static void cp_parser_check_for_definition_in_return_type
(tree, int);
static void cp_parser_check_for_invalid_template_id
(cp_parser *, tree);
static bool cp_parser_non_integral_constant_expression
(cp_parser *, const char *);
static bool cp_parser_diagnose_invalid_type_name
(cp_parser *);
static int cp_parser_skip_to_closing_parenthesis
(cp_parser *, bool, bool, bool);
static void cp_parser_skip_to_end_of_statement
(cp_parser *);
static void cp_parser_consume_semicolon_at_end_of_statement
(cp_parser *);
static void cp_parser_skip_to_end_of_block_or_statement
(cp_parser *);
static void cp_parser_skip_to_closing_brace
(cp_parser *);
static void cp_parser_skip_until_found
(cp_parser *, enum cpp_ttype, const char *);
static bool cp_parser_error_occurred
(cp_parser *);
static bool cp_parser_allow_gnu_extensions_p
(cp_parser *);
static bool cp_parser_is_string_literal
(cp_token *);
static bool cp_parser_is_keyword
(cp_token *, enum rid);
/* Returns nonzero if we are parsing tentatively. */
static inline bool
cp_parser_parsing_tentatively (cp_parser* parser)
{
return parser->context->next != NULL;
}
/* Returns nonzero if TOKEN is a string literal. */
static bool
cp_parser_is_string_literal (cp_token* token)
{
return (token->type == CPP_STRING || token->type == CPP_WSTRING);
}
/* Returns nonzero if TOKEN is the indicated KEYWORD. */
static bool
cp_parser_is_keyword (cp_token* token, enum rid keyword)
{
return token->keyword == keyword;
}
/* Issue the indicated error MESSAGE. */
static void
cp_parser_error (cp_parser* parser, const char* message)
{
/* Output the MESSAGE -- unless we're parsing tentatively. */
if (!cp_parser_simulate_error (parser))
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
c_parse_error (message,
/* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like
identifiers. */
(token->type == CPP_KEYWORD ? CPP_NAME : token->type),
token->value);
}
}
/* Issue an error about name-lookup failing. NAME is the
IDENTIFIER_NODE DECL is the result of
the lookup (as returned from cp_parser_lookup_name). DESIRED is
the thing that we hoped to find. */
static void
cp_parser_name_lookup_error (cp_parser* parser,
tree name,
tree decl,
const char* desired)
{
/* If name lookup completely failed, tell the user that NAME was not
declared. */
if (decl == error_mark_node)
{
if (parser->scope && parser->scope != global_namespace)
error ("`%D::%D' has not been declared",
parser->scope, name);
else if (parser->scope == global_namespace)
error ("`::%D' has not been declared", name);
else
error ("`%D' has not been declared", name);
}
else if (parser->scope && parser->scope != global_namespace)
error ("`%D::%D' %s", parser->scope, name, desired);
else if (parser->scope == global_namespace)
error ("`::%D' %s", name, desired);
else
error ("`%D' %s", name, desired);
}
/* If we are parsing tentatively, remember that an error has occurred
during this tentative parse. Returns true if the error was
simulated; false if a messgae should be issued by the caller. */
static bool
cp_parser_simulate_error (cp_parser* parser)
{
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
parser->context->status = CP_PARSER_STATUS_KIND_ERROR;
return true;
}
return false;
}
/* This function is called when a type is defined. If type
definitions are forbidden at this point, an error message is
issued. */
static void
cp_parser_check_type_definition (cp_parser* parser)
{
/* If types are forbidden here, issue a message. */
if (parser->type_definition_forbidden_message)
/* Use `%s' to print the string in case there are any escape
characters in the message. */
error ("%s", parser->type_definition_forbidden_message);
}
/* This function is called when a declaration is parsed. If
DECLARATOR is a function declarator and DECLARES_CLASS_OR_ENUM
indicates that a type was defined in the decl-specifiers for DECL,
then an error is issued. */
static void
cp_parser_check_for_definition_in_return_type (tree declarator,
int declares_class_or_enum)
{
/* [dcl.fct] forbids type definitions in return types.
Unfortunately, it's not easy to know whether or not we are
processing a return type until after the fact. */
while (declarator
&& (TREE_CODE (declarator) == INDIRECT_REF
|| TREE_CODE (declarator) == ADDR_EXPR))
declarator = TREE_OPERAND (declarator, 0);
if (declarator
&& TREE_CODE (declarator) == CALL_EXPR
&& declares_class_or_enum & 2)
error ("new types may not be defined in a return type");
}
/* A type-specifier (TYPE) has been parsed which cannot be followed by
"<" in any valid C++ program. If the next token is indeed "<",
issue a message warning the user about what appears to be an
invalid attempt to form a template-id. */
static void
cp_parser_check_for_invalid_template_id (cp_parser* parser,
tree type)
{
ptrdiff_t start;
cp_token *token;
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
{
if (TYPE_P (type))
error ("`%T' is not a template", type);
else if (TREE_CODE (type) == IDENTIFIER_NODE)
error ("`%s' is not a template", IDENTIFIER_POINTER (type));
else
error ("invalid template-id");
/* Remember the location of the invalid "<". */
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
token = cp_lexer_peek_token (parser->lexer);
token = cp_lexer_prev_token (parser->lexer, token);
start = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token,
token);
}
else
start = -1;
/* Consume the "<". */
cp_lexer_consume_token (parser->lexer);
/* Parse the template arguments. */
cp_parser_enclosed_template_argument_list (parser);
/* Permanently remove the invalid template arguments so that
this error message is not issued again. */
if (start >= 0)
{
token = cp_lexer_advance_token (parser->lexer,
parser->lexer->first_token,
start);
cp_lexer_purge_tokens_after (parser->lexer, token);
}
}
}
/* If parsing an integral constant-expression, issue an error message
about the fact that THING appeared and return true. Otherwise,
return false, marking the current expression as non-constant. */
static bool
cp_parser_non_integral_constant_expression (cp_parser *parser,
const char *thing)
{
if (parser->integral_constant_expression_p)
{
if (!parser->allow_non_integral_constant_expression_p)
{
error ("%s cannot appear in a constant-expression", thing);
return true;
}
parser->non_integral_constant_expression_p = true;
}
return false;
}
/* Check for a common situation where a type-name should be present,
but is not, and issue a sensible error message. Returns true if an
invalid type-name was detected. */
static bool
cp_parser_diagnose_invalid_type_name (cp_parser *parser)
{
/* If the next two tokens are both identifiers, the code is
erroneous. The usual cause of this situation is code like:
T t;
where "T" should name a type -- but does not. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)
{
tree name;
/* If parsing tentatively, we should commit; we really are
looking at a declaration. */
/* Consume the first identifier. */
name = cp_lexer_consume_token (parser->lexer)->value;
/* Issue an error message. */
error ("`%s' does not name a type", IDENTIFIER_POINTER (name));
/* If we're in a template class, it's possible that the user was
referring to a type from a base class. For example:
template <typename T> struct A { typedef T X; };
template <typename T> struct B : public A<T> { X x; };
The user should have said "typename A<T>::X". */
if (processing_template_decl && current_class_type)
{
tree b;
for (b = TREE_CHAIN (TYPE_BINFO (current_class_type));
b;
b = TREE_CHAIN (b))
{
tree base_type = BINFO_TYPE (b);
if (CLASS_TYPE_P (base_type)
&& dependent_type_p (base_type))
{
tree field;
/* Go from a particular instantiation of the
template (which will have an empty TYPE_FIELDs),
to the main version. */
base_type = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (base_type);
for (field = TYPE_FIELDS (base_type);
field;
field = TREE_CHAIN (field))
if (TREE_CODE (field) == TYPE_DECL
&& DECL_NAME (field) == name)
{
error ("(perhaps `typename %T::%s' was intended)",
BINFO_TYPE (b), IDENTIFIER_POINTER (name));
break;
}
if (field)
break;
}
}
}
/* Skip to the end of the declaration; there's no point in
trying to process it. */
cp_parser_skip_to_end_of_statement (parser);
return true;
}
return false;
}
/* Consume tokens up to, and including, the next non-nested closing `)'.
Returns 1 iff we found a closing `)'. RECOVERING is true, if we
are doing error recovery. Returns -1 if OR_COMMA is true and we
found an unnested comma. */
static int
cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
bool recovering,
bool or_comma,
bool consume_paren)
{
unsigned paren_depth = 0;
unsigned brace_depth = 0;
if (recovering && !or_comma && cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
return 0;
while (true)
{
cp_token *token;
/* If we've run out of tokens, then there is no closing `)'. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
return 0;
token = cp_lexer_peek_token (parser->lexer);
/* This matches the processing in skip_to_end_of_statement. */
if (token->type == CPP_SEMICOLON && !brace_depth)
return 0;
if (token->type == CPP_OPEN_BRACE)
++brace_depth;
if (token->type == CPP_CLOSE_BRACE)
{
if (!brace_depth--)
return 0;
}
if (recovering && or_comma && token->type == CPP_COMMA
&& !brace_depth && !paren_depth)
return -1;
if (!brace_depth)
{
/* If it is an `(', we have entered another level of nesting. */
if (token->type == CPP_OPEN_PAREN)
++paren_depth;
/* If it is a `)', then we might be done. */
else if (token->type == CPP_CLOSE_PAREN && !paren_depth--)
{
if (consume_paren)
cp_lexer_consume_token (parser->lexer);
return 1;
}
}
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
}
}
/* Consume tokens until we reach the end of the current statement.
Normally, that will be just before consuming a `;'. However, if a
non-nested `}' comes first, then we stop before consuming that. */
static void
cp_parser_skip_to_end_of_statement (cp_parser* parser)
{
unsigned nesting_depth = 0;
while (true)
{
cp_token *token;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If we've run out of tokens, stop. */
if (token->type == CPP_EOF)
break;
/* If the next token is a `;', we have reached the end of the
statement. */
if (token->type == CPP_SEMICOLON && !nesting_depth)
break;
/* If the next token is a non-nested `}', then we have reached
the end of the current block. */
if (token->type == CPP_CLOSE_BRACE)
{
/* If this is a non-nested `}', stop before consuming it.
That way, when confronted with something like:
{ 3 + }
we stop before consuming the closing `}', even though we
have not yet reached a `;'. */
if (nesting_depth == 0)
break;
/* If it is the closing `}' for a block that we have
scanned, stop -- but only after consuming the token.
That way given:
void f g () { ... }
typedef int I;
we will stop after the body of the erroneously declared
function, but before consuming the following `typedef'
declaration. */
if (--nesting_depth == 0)
{
cp_lexer_consume_token (parser->lexer);
break;
}
}
/* If it the next token is a `{', then we are entering a new
block. Consume the entire block. */
else if (token->type == CPP_OPEN_BRACE)
++nesting_depth;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
}
}
/* This function is called at the end of a statement or declaration.
If the next token is a semicolon, it is consumed; otherwise, error
recovery is attempted. */
static void
cp_parser_consume_semicolon_at_end_of_statement (cp_parser *parser)
{
/* Look for the trailing `;'. */
if (!cp_parser_require (parser, CPP_SEMICOLON, "`;'"))
{
/* If there is additional (erroneous) input, skip to the end of
the statement. */
cp_parser_skip_to_end_of_statement (parser);
/* If the next token is now a `;', consume it. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
}
}
/* Skip tokens until we have consumed an entire block, or until we
have consumed a non-nested `;'. */
static void
cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser)
{
unsigned nesting_depth = 0;
while (true)
{
cp_token *token;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If we've run out of tokens, stop. */
if (token->type == CPP_EOF)
break;
/* If the next token is a `;', we have reached the end of the
statement. */
if (token->type == CPP_SEMICOLON && !nesting_depth)
{
/* Consume the `;'. */
cp_lexer_consume_token (parser->lexer);
break;
}
/* Consume the token. */
token = cp_lexer_consume_token (parser->lexer);
/* If the next token is a non-nested `}', then we have reached
the end of the current block. */
if (token->type == CPP_CLOSE_BRACE
&& (nesting_depth == 0 || --nesting_depth == 0))
break;
/* If it the next token is a `{', then we are entering a new
block. Consume the entire block. */
if (token->type == CPP_OPEN_BRACE)
++nesting_depth;
}
}
/* Skip tokens until a non-nested closing curly brace is the next
token. */
static void
cp_parser_skip_to_closing_brace (cp_parser *parser)
{
unsigned nesting_depth = 0;
while (true)
{
cp_token *token;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If we've run out of tokens, stop. */
if (token->type == CPP_EOF)
break;
/* If the next token is a non-nested `}', then we have reached
the end of the current block. */
if (token->type == CPP_CLOSE_BRACE && nesting_depth-- == 0)
break;
/* If it the next token is a `{', then we are entering a new
block. Consume the entire block. */
else if (token->type == CPP_OPEN_BRACE)
++nesting_depth;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
}
}
/* Create a new C++ parser. */
static cp_parser *
cp_parser_new (void)
{
cp_parser *parser;
cp_lexer *lexer;
/* cp_lexer_new_main is called before calling ggc_alloc because
cp_lexer_new_main might load a PCH file. */
lexer = cp_lexer_new_main ();
parser = ggc_alloc_cleared (sizeof (cp_parser));
parser->lexer = lexer;
parser->context = cp_parser_context_new (NULL);
/* For now, we always accept GNU extensions. */
parser->allow_gnu_extensions_p = 1;
/* The `>' token is a greater-than operator, not the end of a
template-id. */
parser->greater_than_is_operator_p = true;
parser->default_arg_ok_p = true;
/* We are not parsing a constant-expression. */
parser->integral_constant_expression_p = false;
parser->allow_non_integral_constant_expression_p = false;
parser->non_integral_constant_expression_p = false;
/* We are not parsing offsetof. */
parser->in_offsetof_p = false;
/* Local variable names are not forbidden. */
parser->local_variables_forbidden_p = false;
/* We are not processing an `extern "C"' declaration. */
parser->in_unbraced_linkage_specification_p = false;
/* We are not processing a declarator. */
parser->in_declarator_p = false;
/* We are not processing a template-argument-list. */
parser->in_template_argument_list_p = false;
/* We are not in an iteration statement. */
parser->in_iteration_statement_p = false;
/* We are not in a switch statement. */
parser->in_switch_statement_p = false;
/* We are not parsing a type-id inside an expression. */
parser->in_type_id_in_expr_p = false;
/* The unparsed function queue is empty. */
parser->unparsed_functions_queues = build_tree_list (NULL_TREE, NULL_TREE);
/* There are no classes being defined. */
parser->num_classes_being_defined = 0;
/* No template parameters apply. */
parser->num_template_parameter_lists = 0;
return parser;
}
/* Lexical conventions [gram.lex] */
/* Parse an identifier. Returns an IDENTIFIER_NODE representing the
identifier. */
static tree
cp_parser_identifier (cp_parser* parser)
{
cp_token *token;
/* Look for the identifier. */
token = cp_parser_require (parser, CPP_NAME, "identifier");
/* Return the value. */
return token ? token->value : error_mark_node;
}
/* Basic concepts [gram.basic] */
/* Parse a translation-unit.
translation-unit:
declaration-seq [opt]
Returns TRUE if all went well. */
static bool
cp_parser_translation_unit (cp_parser* parser)
{
while (true)
{
cp_parser_declaration_seq_opt (parser);
/* If there are no tokens left then all went well. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
break;
/* Otherwise, issue an error message. */
cp_parser_error (parser, "expected declaration");
return false;
}
/* Consume the EOF token. */
cp_parser_require (parser, CPP_EOF, "end-of-file");
/* Finish up. */
finish_translation_unit ();
/* All went well. */
return true;
}
/* Expressions [gram.expr] */
/* Parse a primary-expression.
primary-expression:
literal
this
( expression )
id-expression
GNU Extensions:
primary-expression:
( compound-statement )
__builtin_va_arg ( assignment-expression , type-id )
literal:
__null
Returns a representation of the expression.
*IDK indicates what kind of id-expression (if any) was present.
*QUALIFYING_CLASS is set to a non-NULL value if the id-expression can be
used as the operand of a pointer-to-member. In that case,
*QUALIFYING_CLASS gives the class that is used as the qualifying
class in the pointer-to-member. */
static tree
cp_parser_primary_expression (cp_parser *parser,
cp_id_kind *idk,
tree *qualifying_class)
{
cp_token *token;
/* Assume the primary expression is not an id-expression. */
*idk = CP_ID_KIND_NONE;
/* And that it cannot be used as pointer-to-member. */
*qualifying_class = NULL_TREE;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
/* literal:
integer-literal
character-literal
floating-literal
string-literal
boolean-literal */
case CPP_CHAR:
case CPP_WCHAR:
case CPP_STRING:
case CPP_WSTRING:
case CPP_NUMBER:
token = cp_lexer_consume_token (parser->lexer);
return token->value;
case CPP_OPEN_PAREN:
{
tree expr;
bool saved_greater_than_is_operator_p;
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* Within a parenthesized expression, a `>' token is always
the greater-than operator. */
saved_greater_than_is_operator_p
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = true;
/* If we see `( { ' then we are looking at the beginning of
a GNU statement-expression. */
if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
/* Statement-expressions are not allowed by the standard. */
if (pedantic)
pedwarn ("ISO C++ forbids braced-groups within expressions");
/* And they're not allowed outside of a function-body; you
cannot, for example, write:
int i = ({ int j = 3; j + 1; });
at class or namespace scope. */
if (!at_function_scope_p ())
error ("statement-expressions are allowed only inside functions");
/* Start the statement-expression. */
expr = begin_stmt_expr ();
/* Parse the compound-statement. */
cp_parser_compound_statement (parser, true);
/* Finish up. */
expr = finish_stmt_expr (expr, false);
}
else
{
/* Parse the parenthesized expression. */
expr = cp_parser_expression (parser);
/* Let the front end know that this expression was
enclosed in parentheses. This matters in case, for
example, the expression is of the form `A::B', since
`&A::B' might be a pointer-to-member, but `&(A::B)' is
not. */
finish_parenthesized_expr (expr);
}
/* The `>' token might be the end of a template-id or
template-parameter-list now. */
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
/* Consume the `)'. */
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
cp_parser_skip_to_end_of_statement (parser);
return expr;
}
case CPP_KEYWORD:
switch (token->keyword)
{
/* These two are the boolean literals. */
case RID_TRUE:
cp_lexer_consume_token (parser->lexer);
return boolean_true_node;
case RID_FALSE:
cp_lexer_consume_token (parser->lexer);
return boolean_false_node;
/* The `__null' literal. */
case RID_NULL:
cp_lexer_consume_token (parser->lexer);
return null_node;
/* Recognize the `this' keyword. */
case RID_THIS:
cp_lexer_consume_token (parser->lexer);
if (parser->local_variables_forbidden_p)
{
error ("`this' may not be used in this context");
return error_mark_node;
}
/* Pointers cannot appear in constant-expressions. */
if (cp_parser_non_integral_constant_expression (parser,
"`this'"))
return error_mark_node;
return finish_this_expr ();
/* The `operator' keyword can be the beginning of an
id-expression. */
case RID_OPERATOR:
goto id_expression;
case RID_FUNCTION_NAME:
case RID_PRETTY_FUNCTION_NAME:
case RID_C99_FUNCTION_NAME:
/* The symbols __FUNCTION__, __PRETTY_FUNCTION__, and
__func__ are the names of variables -- but they are
treated specially. Therefore, they are handled here,
rather than relying on the generic id-expression logic
below. Grammatically, these names are id-expressions.
Consume the token. */
token = cp_lexer_consume_token (parser->lexer);
/* Look up the name. */
return finish_fname (token->value);
case RID_VA_ARG:
{
tree expression;
tree type;
/* The `__builtin_va_arg' construct is used to handle
`va_arg'. Consume the `__builtin_va_arg' token. */
cp_lexer_consume_token (parser->lexer);
/* Look for the opening `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Now, parse the assignment-expression. */
expression = cp_parser_assignment_expression (parser);
/* Look for the `,'. */
cp_parser_require (parser, CPP_COMMA, "`,'");
/* Parse the type-id. */
type = cp_parser_type_id (parser);
/* Look for the closing `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Using `va_arg' in a constant-expression is not
allowed. */
if (cp_parser_non_integral_constant_expression (parser,
"`va_arg'"))
return error_mark_node;
return build_x_va_arg (expression, type);
}
case RID_OFFSETOF:
{
tree expression;
bool saved_in_offsetof_p;
/* Consume the "__offsetof__" token. */
cp_lexer_consume_token (parser->lexer);
/* Consume the opening `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Parse the parenthesized (almost) constant-expression. */
saved_in_offsetof_p = parser->in_offsetof_p;
parser->in_offsetof_p = true;
expression
= cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
/*non_constant_p=*/NULL);
parser->in_offsetof_p = saved_in_offsetof_p;
/* Consume the closing ')'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
return expression;
}
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
/* An id-expression can start with either an identifier, a
`::' as the beginning of a qualified-id, or the "operator"
keyword. */
case CPP_NAME:
case CPP_SCOPE:
case CPP_TEMPLATE_ID:
case CPP_NESTED_NAME_SPECIFIER:
{
tree id_expression;
tree decl;
const char *error_msg;
id_expression:
/* Parse the id-expression. */
id_expression
= cp_parser_id_expression (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
/*template_p=*/NULL,
/*declarator_p=*/false);
if (id_expression == error_mark_node)
return error_mark_node;
/* If we have a template-id, then no further lookup is
required. If the template-id was for a template-class, we
will sometimes have a TYPE_DECL at this point. */
else if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
|| TREE_CODE (id_expression) == TYPE_DECL)
decl = id_expression;
/* Look up the name. */
else
{
decl = cp_parser_lookup_name_simple (parser, id_expression);
/* If name lookup gives us a SCOPE_REF, then the
qualifying scope was dependent. Just propagate the
name. */
if (TREE_CODE (decl) == SCOPE_REF)
{
if (TYPE_P (TREE_OPERAND (decl, 0)))
*qualifying_class = TREE_OPERAND (decl, 0);
return decl;
}
/* Check to see if DECL is a local variable in a context
where that is forbidden. */
if (parser->local_variables_forbidden_p
&& local_variable_p (decl))
{
/* It might be that we only found DECL because we are
trying to be generous with pre-ISO scoping rules.
For example, consider:
int i;
void g() {
for (int i = 0; i < 10; ++i) {}
extern void f(int j = i);
}
Here, name look up will originally find the out
of scope `i'. We need to issue a warning message,
but then use the global `i'. */
decl = check_for_out_of_scope_variable (decl);
if (local_variable_p (decl))
{
error ("local variable `%D' may not appear in this context",
decl);
return error_mark_node;
}
}
}
decl = finish_id_expression (id_expression, decl, parser->scope,
idk, qualifying_class,
parser->integral_constant_expression_p,
parser->allow_non_integral_constant_expression_p,
&parser->non_integral_constant_expression_p,
&error_msg);
if (error_msg)
cp_parser_error (parser, error_msg);
return decl;
}
/* Anything else is an error. */
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
}
/* Parse an id-expression.
id-expression:
unqualified-id
qualified-id
qualified-id:
:: [opt] nested-name-specifier template [opt] unqualified-id
:: identifier
:: operator-function-id
:: template-id
Return a representation of the unqualified portion of the
identifier. Sets PARSER->SCOPE to the qualifying scope if there is
a `::' or nested-name-specifier.
Often, if the id-expression was a qualified-id, the caller will
want to make a SCOPE_REF to represent the qualified-id. This
function does not do this in order to avoid wastefully creating
SCOPE_REFs when they are not required.
If TEMPLATE_KEYWORD_P is true, then we have just seen the
`template' keyword.
If CHECK_DEPENDENCY_P is false, then names are looked up inside
uninstantiated templates.
If *TEMPLATE_P is non-NULL, it is set to true iff the
`template' keyword is used to explicitly indicate that the entity
named is a template.
If DECLARATOR_P is true, the id-expression is appearing as part of
a declarator, rather than as part of an expression. */
static tree
cp_parser_id_expression (cp_parser *parser,
bool template_keyword_p,
bool check_dependency_p,
bool *template_p,
bool declarator_p)
{
bool global_scope_p;
bool nested_name_specifier_p;
/* Assume the `template' keyword was not used. */
if (template_p)
*template_p = false;
/* Look for the optional `::' operator. */
global_scope_p
= (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false)
!= NULL_TREE);
/* Look for the optional nested-name-specifier. */
nested_name_specifier_p
= (cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/false,
check_dependency_p,
/*type_p=*/false,
/*is_declarator=*/false)
!= NULL_TREE);
/* If there is a nested-name-specifier, then we are looking at
the first qualified-id production. */
if (nested_name_specifier_p)
{
tree saved_scope;
tree saved_object_scope;
tree saved_qualifying_scope;
tree unqualified_id;
bool is_template;
/* See if the next token is the `template' keyword. */
if (!template_p)
template_p = &is_template;
*template_p = cp_parser_optional_template_keyword (parser);
/* Name lookup we do during the processing of the
unqualified-id might obliterate SCOPE. */
saved_scope = parser->scope;
saved_object_scope = parser->object_scope;
saved_qualifying_scope = parser->qualifying_scope;
/* Process the final unqualified-id. */
unqualified_id = cp_parser_unqualified_id (parser, *template_p,
check_dependency_p,
declarator_p);
/* Restore the SAVED_SCOPE for our caller. */
parser->scope = saved_scope;
parser->object_scope = saved_object_scope;
parser->qualifying_scope = saved_qualifying_scope;
return unqualified_id;
}
/* Otherwise, if we are in global scope, then we are looking at one
of the other qualified-id productions. */
else if (global_scope_p)
{
cp_token *token;
tree id;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's an identifier, and the next token is not a "<", then
we can avoid the template-id case. This is an optimization
for this common case. */
if (token->type == CPP_NAME
&& !cp_parser_nth_token_starts_template_argument_list_p
(parser, 2))
return cp_parser_identifier (parser);
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
id = cp_parser_template_id (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
declarator_p);
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
/* Peek at the next token. (Changes in the token buffer may
have invalidated the pointer obtained above.) */
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_NAME:
return cp_parser_identifier (parser);
case CPP_KEYWORD:
if (token->keyword == RID_OPERATOR)
return cp_parser_operator_function_id (parser);
/* Fall through. */
default:
cp_parser_error (parser, "expected id-expression");
return error_mark_node;
}
}
else
return cp_parser_unqualified_id (parser, template_keyword_p,
/*check_dependency_p=*/true,
declarator_p);
}
/* Parse an unqualified-id.
unqualified-id:
identifier
operator-function-id
conversion-function-id
~ class-name
template-id
If TEMPLATE_KEYWORD_P is TRUE, we have just seen the `template'
keyword, in a construct like `A::template ...'.
Returns a representation of unqualified-id. For the `identifier'
production, an IDENTIFIER_NODE is returned. For the `~ class-name'
production a BIT_NOT_EXPR is returned; the operand of the
BIT_NOT_EXPR is an IDENTIFIER_NODE for the class-name. For the
other productions, see the documentation accompanying the
corresponding parsing functions. If CHECK_DEPENDENCY_P is false,
names are looked up in uninstantiated templates. If DECLARATOR_P
is true, the unqualified-id is appearing as part of a declarator,
rather than as part of an expression. */
static tree
cp_parser_unqualified_id (cp_parser* parser,
bool template_keyword_p,
bool check_dependency_p,
bool declarator_p)
{
cp_token *token;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_NAME:
{
tree id;
/* We don't know yet whether or not this will be a
template-id. */
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
id = cp_parser_template_id (parser, template_keyword_p,
check_dependency_p,
declarator_p);
/* If it worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
/* Otherwise, it's an ordinary identifier. */
return cp_parser_identifier (parser);
}
case CPP_TEMPLATE_ID:
return cp_parser_template_id (parser, template_keyword_p,
check_dependency_p,
declarator_p);
case CPP_COMPL:
{
tree type_decl;
tree qualifying_scope;
tree object_scope;
tree scope;
/* Consume the `~' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the class-name. The standard, as written, seems to
say that:
template <typename T> struct S { ~S (); };
template <typename T> S<T>::~S() {}
is invalid, since `~' must be followed by a class-name, but
`S<T>' is dependent, and so not known to be a class.
That's not right; we need to look in uninstantiated
templates. A further complication arises from:
template <typename T> void f(T t) {
t.T::~T();
}
Here, it is not possible to look up `T' in the scope of `T'
itself. We must look in both the current scope, and the
scope of the containing complete expression.
Yet another issue is:
struct S {
int S;
~S();
};
S::~S() {}
The standard does not seem to say that the `S' in `~S'
should refer to the type `S' and not the data member
`S::S'. */
/* DR 244 says that we look up the name after the "~" in the
same scope as we looked up the qualifying name. That idea
isn't fully worked out; it's more complicated than that. */
scope = parser->scope;
object_scope = parser->object_scope;
qualifying_scope = parser->qualifying_scope;
/* If the name is of the form "X::~X" it's OK. */
if (scope && TYPE_P (scope)
&& cp_lexer_next_token_is (parser->lexer, CPP_NAME)
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_OPEN_PAREN)
&& (cp_lexer_peek_token (parser->lexer)->value
== TYPE_IDENTIFIER (scope)))
{
cp_lexer_consume_token (parser->lexer);
return build_nt (BIT_NOT_EXPR, scope);
}
/* If there was an explicit qualification (S::~T), first look
in the scope given by the qualification (i.e., S). */
if (scope)
{
cp_parser_parse_tentatively (parser);
type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
/* In "N::S::~S", look in "N" as well. */
if (scope && qualifying_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = qualifying_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
/* In "p->S::~T", look in the scope given by "*p" as well. */
else if (object_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = object_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
/* Look in the surrounding context. */
parser->scope = NULL_TREE;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
/* If an error occurred, assume that the name of the
destructor is the same as the name of the qualifying
class. That allows us to keep parsing after running
into ill-formed destructor names. */
if (type_decl == error_mark_node && scope && TYPE_P (scope))
return build_nt (BIT_NOT_EXPR, scope);
else if (type_decl == error_mark_node)
return error_mark_node;
/* [class.dtor]
A typedef-name that names a class shall not be used as the
identifier in the declarator for a destructor declaration. */
if (declarator_p
&& !DECL_IMPLICIT_TYPEDEF_P (type_decl)
&& !DECL_SELF_REFERENCE_P (type_decl))
error ("typedef-name `%D' used as destructor declarator",
type_decl);
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
case CPP_KEYWORD:
if (token->keyword == RID_OPERATOR)
{
tree id;
/* This could be a template-id, so we try that first. */
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
id = cp_parser_template_id (parser, template_keyword_p,
/*check_dependency_p=*/true,
declarator_p);
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
/* We still don't know whether we're looking at an
operator-function-id or a conversion-function-id. */
cp_parser_parse_tentatively (parser);
/* Try an operator-function-id. */
id = cp_parser_operator_function_id (parser);
/* If that didn't work, try a conversion-function-id. */
if (!cp_parser_parse_definitely (parser))
id = cp_parser_conversion_function_id (parser);
return id;
}
/* Fall through. */
default:
cp_parser_error (parser, "expected unqualified-id");
return error_mark_node;
}
}
/* Parse an (optional) nested-name-specifier.
nested-name-specifier:
class-or-namespace-name :: nested-name-specifier [opt]
class-or-namespace-name :: template nested-name-specifier [opt]
PARSER->SCOPE should be set appropriately before this function is
called. TYPENAME_KEYWORD_P is TRUE if the `typename' keyword is in
effect. TYPE_P is TRUE if we non-type bindings should be ignored
in name lookups.
Sets PARSER->SCOPE to the class (TYPE) or namespace
(NAMESPACE_DECL) specified by the nested-name-specifier, or leaves
it unchanged if there is no nested-name-specifier. Returns the new
scope iff there is a nested-name-specifier, or NULL_TREE otherwise.
If IS_DECLARATION is TRUE, the nested-name-specifier is known to be
part of a declaration and/or decl-specifier. */
static tree
cp_parser_nested_name_specifier_opt (cp_parser *parser,
bool typename_keyword_p,
bool check_dependency_p,
bool type_p,
bool is_declaration)
{
bool success = false;
tree access_check = NULL_TREE;
ptrdiff_t start;
cp_token* token;
/* If the next token corresponds to a nested name specifier, there
is no need to reparse it. However, if CHECK_DEPENDENCY_P is
false, it may have been true before, in which case something
like `A<X>::B<Y>::C' may have resulted in a nested-name-specifier
of `A<X>::', where it should now be `A<X>::B<Y>::'. So, when
CHECK_DEPENDENCY_P is false, we have to fall through into the
main loop. */
if (check_dependency_p
&& cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
{
cp_parser_pre_parsed_nested_name_specifier (parser);
return parser->scope;
}
/* Remember where the nested-name-specifier starts. */
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
token = cp_lexer_peek_token (parser->lexer);
start = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token,
token);
}
else
start = -1;
push_deferring_access_checks (dk_deferred);
while (true)
{
tree new_scope;
tree old_scope;
tree saved_qualifying_scope;
bool template_keyword_p;
/* Spot cases that cannot be the beginning of a
nested-name-specifier. */
token = cp_lexer_peek_token (parser->lexer);
/* If the next token is CPP_NESTED_NAME_SPECIFIER, just process
the already parsed nested-name-specifier. */
if (token->type == CPP_NESTED_NAME_SPECIFIER)
{
/* Grab the nested-name-specifier and continue the loop. */
cp_parser_pre_parsed_nested_name_specifier (parser);
success = true;
continue;
}
/* Spot cases that cannot be the beginning of a
nested-name-specifier. On the second and subsequent times
through the loop, we look for the `template' keyword. */
if (success && token->keyword == RID_TEMPLATE)
;
/* A template-id can start a nested-name-specifier. */
else if (token->type == CPP_TEMPLATE_ID)
;
else
{
/* If the next token is not an identifier, then it is
definitely not a class-or-namespace-name. */
if (token->type != CPP_NAME)
break;
/* If the following token is neither a `<' (to begin a
template-id), nor a `::', then we are not looking at a
nested-name-specifier. */
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type != CPP_SCOPE
&& !cp_parser_nth_token_starts_template_argument_list_p
(parser, 2))
break;
}
/* The nested-name-specifier is optional, so we parse
tentatively. */
cp_parser_parse_tentatively (parser);
/* Look for the optional `template' keyword, if this isn't the
first time through the loop. */
if (success)
template_keyword_p = cp_parser_optional_template_keyword (parser);
else
template_keyword_p = false;
/* Save the old scope since the name lookup we are about to do
might destroy it. */
old_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
/* Parse the qualifying entity. */
new_scope
= cp_parser_class_or_namespace_name (parser,
typename_keyword_p,
template_keyword_p,
check_dependency_p,
type_p,
is_declaration);
/* Look for the `::' token. */
cp_parser_require (parser, CPP_SCOPE, "`::'");
/* If we found what we wanted, we keep going; otherwise, we're
done. */
if (!cp_parser_parse_definitely (parser))
{
bool error_p = false;
/* Restore the OLD_SCOPE since it was valid before the
failed attempt at finding the last
class-or-namespace-name. */
parser->scope = old_scope;
parser->qualifying_scope = saved_qualifying_scope;
/* If the next token is an identifier, and the one after
that is a `::', then any valid interpretation would have
found a class-or-namespace-name. */
while (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_SCOPE)
&& (cp_lexer_peek_nth_token (parser->lexer, 3)->type
!= CPP_COMPL))
{
token = cp_lexer_consume_token (parser->lexer);
if (!error_p)
{
tree decl;
decl = cp_parser_lookup_name_simple (parser, token->value);
if (TREE_CODE (decl) == TEMPLATE_DECL)
error ("`%D' used without template parameters",
decl);
else
cp_parser_name_lookup_error
(parser, token->value, decl,
"is not a class or namespace");
parser->scope = NULL_TREE;
error_p = true;
/* Treat this as a successful nested-name-specifier
due to:
[basic.lookup.qual]
If the name found is not a class-name (clause
_class_) or namespace-name (_namespace.def_), the
program is ill-formed. */
success = true;
}
cp_lexer_consume_token (parser->lexer);
}
break;
}
/* We've found one valid nested-name-specifier. */
success = true;
/* Make sure we look in the right scope the next time through
the loop. */
parser->scope = (TREE_CODE (new_scope) == TYPE_DECL
? TREE_TYPE (new_scope)
: new_scope);
/* If it is a class scope, try to complete it; we are about to
be looking up names inside the class. */
if (TYPE_P (parser->scope)
/* Since checking types for dependency can be expensive,
avoid doing it if the type is already complete. */
&& !COMPLETE_TYPE_P (parser->scope)
/* Do not try to complete dependent types. */
&& !dependent_type_p (parser->scope))
complete_type (parser->scope);
}
/* Retrieve any deferred checks. Do not pop this access checks yet
so the memory will not be reclaimed during token replacing below. */
access_check = get_deferred_access_checks ();
/* If parsing tentatively, replace the sequence of tokens that makes
up the nested-name-specifier with a CPP_NESTED_NAME_SPECIFIER
token. That way, should we re-parse the token stream, we will
not have to repeat the effort required to do the parse, nor will
we issue duplicate error messages. */
if (success && start >= 0)
{
/* Find the token that corresponds to the start of the
template-id. */
token = cp_lexer_advance_token (parser->lexer,
parser->lexer->first_token,
start);
/* Reset the contents of the START token. */
token->type = CPP_NESTED_NAME_SPECIFIER;
token->value = build_tree_list (access_check, parser->scope);
TREE_TYPE (token->value) = parser->qualifying_scope;
token->keyword = RID_MAX;
/* Purge all subsequent tokens. */
cp_lexer_purge_tokens_after (parser->lexer, token);
}
pop_deferring_access_checks ();
return success ? parser->scope : NULL_TREE;
}
/* Parse a nested-name-specifier. See
cp_parser_nested_name_specifier_opt for details. This function
behaves identically, except that it will an issue an error if no
nested-name-specifier is present, and it will return
ERROR_MARK_NODE, rather than NULL_TREE, if no nested-name-specifier
is present. */
static tree
cp_parser_nested_name_specifier (cp_parser *parser,
bool typename_keyword_p,
bool check_dependency_p,
bool type_p,
bool is_declaration)
{
tree scope;
/* Look for the nested-name-specifier. */
scope = cp_parser_nested_name_specifier_opt (parser,
typename_keyword_p,
check_dependency_p,
type_p,
is_declaration);
/* If it was not present, issue an error message. */
if (!scope)
{
cp_parser_error (parser, "expected nested-name-specifier");
parser->scope = NULL_TREE;
return error_mark_node;
}
return scope;
}
/* Parse a class-or-namespace-name.
class-or-namespace-name:
class-name
namespace-name
TYPENAME_KEYWORD_P is TRUE iff the `typename' keyword is in effect.
TEMPLATE_KEYWORD_P is TRUE iff the `template' keyword is in effect.
CHECK_DEPENDENCY_P is FALSE iff dependent names should be looked up.
TYPE_P is TRUE iff the next name should be taken as a class-name,
even the same name is declared to be another entity in the same
scope.
Returns the class (TYPE_DECL) or namespace (NAMESPACE_DECL)
specified by the class-or-namespace-name. If neither is found the
ERROR_MARK_NODE is returned. */
static tree
cp_parser_class_or_namespace_name (cp_parser *parser,
bool typename_keyword_p,
bool template_keyword_p,
bool check_dependency_p,
bool type_p,
bool is_declaration)
{
tree saved_scope;
tree saved_qualifying_scope;
tree saved_object_scope;
tree scope;
bool only_class_p;
/* Before we try to parse the class-name, we must save away the
current PARSER->SCOPE since cp_parser_class_name will destroy
it. */
saved_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
saved_object_scope = parser->object_scope;
/* Try for a class-name first. If the SAVED_SCOPE is a type, then
there is no need to look for a namespace-name. */
only_class_p = template_keyword_p || (saved_scope && TYPE_P (saved_scope));
if (!only_class_p)
cp_parser_parse_tentatively (parser);
scope = cp_parser_class_name (parser,
typename_keyword_p,
template_keyword_p,
type_p,
check_dependency_p,
/*class_head_p=*/false,
is_declaration);
/* If that didn't work, try for a namespace-name. */
if (!only_class_p && !cp_parser_parse_definitely (parser))
{
/* Restore the saved scope. */
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
parser->object_scope = saved_object_scope;
/* If we are not looking at an identifier followed by the scope
resolution operator, then this is not part of a
nested-name-specifier. (Note that this function is only used
to parse the components of a nested-name-specifier.) */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)
|| cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE)
return error_mark_node;
scope = cp_parser_namespace_name (parser);
}
return scope;
}
/* Parse a postfix-expression.
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( expression-list [opt] )
simple-type-specifier ( expression-list [opt] )
typename :: [opt] nested-name-specifier identifier
( expression-list [opt] )
typename :: [opt] nested-name-specifier template [opt] template-id
( expression-list [opt] )
postfix-expression . template [opt] id-expression
postfix-expression -> template [opt] id-expression
postfix-expression . pseudo-destructor-name
postfix-expression -> pseudo-destructor-name
postfix-expression ++
postfix-expression --
dynamic_cast < type-id > ( expression )
static_cast < type-id > ( expression )
reinterpret_cast < type-id > ( expression )
const_cast < type-id > ( expression )
typeid ( expression )
typeid ( type-id )
GNU Extension:
postfix-expression:
( type-id ) { initializer-list , [opt] }
This extension is a GNU version of the C99 compound-literal
construct. (The C99 grammar uses `type-name' instead of `type-id',
but they are essentially the same concept.)
If ADDRESS_P is true, the postfix expression is the operand of the
`&' operator.
Returns a representation of the expression. */
static tree
cp_parser_postfix_expression (cp_parser *parser, bool address_p)
{
cp_token *token;
enum rid keyword;
cp_id_kind idk = CP_ID_KIND_NONE;
tree postfix_expression = NULL_TREE;
/* Non-NULL only if the current postfix-expression can be used to
form a pointer-to-member. In that case, QUALIFYING_CLASS is the
class used to qualify the member. */
tree qualifying_class = NULL_TREE;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* Some of the productions are determined by keywords. */
keyword = token->keyword;
switch (keyword)
{
case RID_DYNCAST:
case RID_STATCAST:
case RID_REINTCAST:
case RID_CONSTCAST:
{
tree type;
tree expression;
const char *saved_message;
/* All of these can be handled in the same way from the point
of view of parsing. Begin by consuming the token
identifying the cast. */
cp_lexer_consume_token (parser->lexer);
/* New types cannot be defined in the cast. */
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in casts";
/* Look for the opening `<'. */
cp_parser_require (parser, CPP_LESS, "`<'");
/* Parse the type to which we are casting. */
type = cp_parser_type_id (parser);
/* Look for the closing `>'. */
cp_parser_require (parser, CPP_GREATER, "`>'");
/* Restore the old message. */
parser->type_definition_forbidden_message = saved_message;
/* And the expression which is being cast. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
expression = cp_parser_expression (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
if (parser->integral_constant_expression_p
&& !dependent_type_p (type)
&& !INTEGRAL_OR_ENUMERATION_TYPE_P (type)
/* A cast to pointer or reference type is allowed in the
implementation of "offsetof". */
&& !(parser->in_offsetof_p && POINTER_TYPE_P (type))
&& (cp_parser_non_integral_constant_expression
(parser,
"a cast to a type other than an integral or "
"enumeration type")))
return error_mark_node;
switch (keyword)
{
case RID_DYNCAST:
postfix_expression
= build_dynamic_cast (type, expression);
break;
case RID_STATCAST:
postfix_expression
= build_static_cast (type, expression);
break;
case RID_REINTCAST:
postfix_expression
= build_reinterpret_cast (type, expression);
break;
case RID_CONSTCAST:
postfix_expression
= build_const_cast (type, expression);
break;
default:
abort ();
}
}
break;