diff options
author | kan <kan@FreeBSD.org> | 2004-07-28 03:11:36 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2004-07-28 03:11:36 +0000 |
commit | e0020c9fe3d2c91658ad0f59cb6a55c44f909db3 (patch) | |
tree | b406472295ae0b130894cc19f02f43b36157fec6 /contrib/gcc/cp/parser.c | |
parent | b754d213ab76dee1e7bcd5acb4becd5658c0ca99 (diff) | |
parent | 5e00ec74d8ce58f99801200d4d3d0412c7cc1b28 (diff) | |
download | FreeBSD-src-e0020c9fe3d2c91658ad0f59cb6a55c44f909db3.zip FreeBSD-src-e0020c9fe3d2c91658ad0f59cb6a55c44f909db3.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r132718,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/gcc/cp/parser.c')
-rw-r--r-- | contrib/gcc/cp/parser.c | 15323 |
1 files changed, 15323 insertions, 0 deletions
diff --git a/contrib/gcc/cp/parser.c b/contrib/gcc/cp/parser.c new file mode 100644 index 0000000..344a8f5 --- /dev/null +++ b/contrib/gcc/cp/parser.c @@ -0,0 +1,15323 @@ +/* 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; + + case RID_TYPEID: + { + tree type; + const char *saved_message; + bool saved_in_type_id_in_expr_p; + + /* Consume the `typeid' token. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the `(' token. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + /* Types cannot be defined in a `typeid' expression. */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = "types may not be defined in a `typeid\' expression"; + /* We can't be sure yet whether we're looking at a type-id or an + expression. */ + cp_parser_parse_tentatively (parser); + /* Try a type-id first. */ + saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; + parser->in_type_id_in_expr_p = true; + type = cp_parser_type_id (parser); + parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; + /* Look for the `)' token. Otherwise, we can't be sure that + we're not looking at an expression: consider `typeid (int + (3))', for example. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* If all went well, simply lookup the type-id. */ + if (cp_parser_parse_definitely (parser)) + postfix_expression = get_typeid (type); + /* Otherwise, fall back to the expression variant. */ + else + { + tree expression; + + /* Look for an expression. */ + expression = cp_parser_expression (parser); + /* Compute its typeid. */ + postfix_expression = build_typeid (expression); + /* Look for the `)' token. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + } + /* `typeid' may not appear in an integral constant expression. */ + if (cp_parser_non_integral_constant_expression(parser, + "`typeid' operator")) + return error_mark_node; + /* Restore the saved message. */ + parser->type_definition_forbidden_message = saved_message; + } + break; + + case RID_TYPENAME: + { + bool template_p = false; + tree id; + tree type; + + /* Consume the `typename' token. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the optional `::' operator. */ + cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false); + /* Look for the nested-name-specifier. */ + cp_parser_nested_name_specifier (parser, + /*typename_keyword_p=*/true, + /*check_dependency_p=*/true, + /*type_p=*/true, + /*is_declaration=*/true); + /* Look for the optional `template' keyword. */ + template_p = cp_parser_optional_template_keyword (parser); + /* We don't know whether we're looking at a template-id or an + identifier. */ + cp_parser_parse_tentatively (parser); + /* Try a template-id. */ + id = cp_parser_template_id (parser, template_p, + /*check_dependency_p=*/true, + /*is_declaration=*/true); + /* If that didn't work, try an identifier. */ + if (!cp_parser_parse_definitely (parser)) + id = cp_parser_identifier (parser); + /* If we look up a template-id in a non-dependent qualifying + scope, there's no need to create a dependent type. */ + if (TREE_CODE (id) == TYPE_DECL + && !dependent_type_p (parser->scope)) + type = TREE_TYPE (id); + /* Create a TYPENAME_TYPE to represent the type to which the + functional cast is being performed. */ + else + type = make_typename_type (parser->scope, id, + /*complain=*/1); + + postfix_expression = cp_parser_functional_cast (parser, type); + } + break; + + default: + { + tree type; + + /* If the next thing is a simple-type-specifier, we may be + looking at a functional cast. We could also be looking at + an id-expression. So, we try the functional cast, and if + that doesn't work we fall back to the primary-expression. */ + cp_parser_parse_tentatively (parser); + /* Look for the simple-type-specifier. */ + type = cp_parser_simple_type_specifier (parser, + CP_PARSER_FLAGS_NONE, + /*identifier_p=*/false); + /* Parse the cast itself. */ + if (!cp_parser_error_occurred (parser)) + postfix_expression + = cp_parser_functional_cast (parser, type); + /* If that worked, we're done. */ + if (cp_parser_parse_definitely (parser)) + break; + + /* If the functional-cast didn't work out, try a + compound-literal. */ + if (cp_parser_allow_gnu_extensions_p (parser) + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + tree initializer_list = NULL_TREE; + bool saved_in_type_id_in_expr_p; + + cp_parser_parse_tentatively (parser); + /* Consume the `('. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the type. */ + saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; + parser->in_type_id_in_expr_p = true; + type = cp_parser_type_id (parser); + parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* Look for the `{'. */ + cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"); + /* If things aren't going well, there's no need to + keep going. */ + if (!cp_parser_error_occurred (parser)) + { + bool non_constant_p; + /* Parse the initializer-list. */ + initializer_list + = cp_parser_initializer_list (parser, &non_constant_p); + /* Allow a trailing `,'. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + /* Look for the final `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); + } + /* If that worked, we're definitely looking at a + compound-literal expression. */ + if (cp_parser_parse_definitely (parser)) + { + /* Warn the user that a compound literal is not + allowed in standard C++. */ + if (pedantic) + pedwarn ("ISO C++ forbids compound-literals"); + /* Form the representation of the compound-literal. */ + postfix_expression + = finish_compound_literal (type, initializer_list); + break; + } + } + + /* It must be a primary-expression. */ + postfix_expression = cp_parser_primary_expression (parser, + &idk, + &qualifying_class); + } + break; + } + + /* If we were avoiding committing to the processing of a + qualified-id until we knew whether or not we had a + pointer-to-member, we now know. */ + if (qualifying_class) + { + bool done; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + done = (token->type != CPP_OPEN_SQUARE + && token->type != CPP_OPEN_PAREN + && token->type != CPP_DOT + && token->type != CPP_DEREF + && token->type != CPP_PLUS_PLUS + && token->type != CPP_MINUS_MINUS); + + postfix_expression = finish_qualified_id_expr (qualifying_class, + postfix_expression, + done, + address_p); + if (done) + return postfix_expression; + } + + /* Keep looping until the postfix-expression is complete. */ + while (true) + { + if (idk == CP_ID_KIND_UNQUALIFIED + && TREE_CODE (postfix_expression) == IDENTIFIER_NODE + && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) + /* It is not a Koenig lookup function call. */ + postfix_expression + = unqualified_name_lookup_error (postfix_expression); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + switch (token->type) + { + case CPP_OPEN_SQUARE: + /* postfix-expression [ expression ] */ + { + tree index; + + /* Consume the `[' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the index expression. */ + index = cp_parser_expression (parser); + /* Look for the closing `]'. */ + cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"); + + /* Build the ARRAY_REF. */ + postfix_expression + = grok_array_decl (postfix_expression, index); + idk = CP_ID_KIND_NONE; + /* Array references are not permitted in + constant-expressions (but they are allowed + in offsetof). */ + if (!parser->in_offsetof_p + && cp_parser_non_integral_constant_expression + (parser, "an array reference")) + postfix_expression = error_mark_node; + } + break; + + case CPP_OPEN_PAREN: + /* postfix-expression ( expression-list [opt] ) */ + { + bool koenig_p; + tree args = (cp_parser_parenthesized_expression_list + (parser, false, /*non_constant_p=*/NULL)); + + if (args == error_mark_node) + { + postfix_expression = error_mark_node; + break; + } + + /* Function calls are not permitted in + constant-expressions. */ + if (cp_parser_non_integral_constant_expression (parser, + "a function call")) + { + postfix_expression = error_mark_node; + break; + } + + koenig_p = false; + if (idk == CP_ID_KIND_UNQUALIFIED) + { + /* We do not perform argument-dependent lookup if + normal lookup finds a non-function, in accordance + with the expected resolution of DR 218. */ + if (args + && (is_overloaded_fn (postfix_expression) + || TREE_CODE (postfix_expression) == IDENTIFIER_NODE)) + { + koenig_p = true; + postfix_expression + = perform_koenig_lookup (postfix_expression, args); + } + else if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE) + postfix_expression + = unqualified_fn_lookup_error (postfix_expression); + } + + if (TREE_CODE (postfix_expression) == COMPONENT_REF) + { + tree instance = TREE_OPERAND (postfix_expression, 0); + tree fn = TREE_OPERAND (postfix_expression, 1); + + if (processing_template_decl + && (type_dependent_expression_p (instance) + || (!BASELINK_P (fn) + && TREE_CODE (fn) != FIELD_DECL) + || type_dependent_expression_p (fn) + || any_type_dependent_arguments_p (args))) + { + postfix_expression + = build_min_nt (CALL_EXPR, postfix_expression, args); + break; + } + + if (BASELINK_P (fn)) + postfix_expression + = (build_new_method_call + (instance, fn, args, NULL_TREE, + (idk == CP_ID_KIND_QUALIFIED + ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL))); + else + postfix_expression + = finish_call_expr (postfix_expression, args, + /*disallow_virtual=*/false, + /*koenig_p=*/false); + } + else if (TREE_CODE (postfix_expression) == OFFSET_REF + || TREE_CODE (postfix_expression) == MEMBER_REF + || TREE_CODE (postfix_expression) == DOTSTAR_EXPR) + postfix_expression = (build_offset_ref_call_from_tree + (postfix_expression, args)); + else if (idk == CP_ID_KIND_QUALIFIED) + /* A call to a static class member, or a namespace-scope + function. */ + postfix_expression + = finish_call_expr (postfix_expression, args, + /*disallow_virtual=*/true, + koenig_p); + else + /* All other function calls. */ + postfix_expression + = finish_call_expr (postfix_expression, args, + /*disallow_virtual=*/false, + koenig_p); + + /* The POSTFIX_EXPRESSION is certainly no longer an id. */ + idk = CP_ID_KIND_NONE; + } + break; + + case CPP_DOT: + case CPP_DEREF: + /* postfix-expression . template [opt] id-expression + postfix-expression . pseudo-destructor-name + postfix-expression -> template [opt] id-expression + postfix-expression -> pseudo-destructor-name */ + { + tree name; + bool dependent_p; + bool template_p; + tree scope = NULL_TREE; + enum cpp_ttype token_type = token->type; + + /* If this is a `->' operator, dereference the pointer. */ + if (token->type == CPP_DEREF) + postfix_expression = build_x_arrow (postfix_expression); + /* Check to see whether or not the expression is + type-dependent. */ + dependent_p = type_dependent_expression_p (postfix_expression); + /* The identifier following the `->' or `.' is not + qualified. */ + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + idk = CP_ID_KIND_NONE; + /* Enter the scope corresponding to the type of the object + given by the POSTFIX_EXPRESSION. */ + if (!dependent_p + && TREE_TYPE (postfix_expression) != NULL_TREE) + { + scope = TREE_TYPE (postfix_expression); + /* According to the standard, no expression should + ever have reference type. Unfortunately, we do not + currently match the standard in this respect in + that our internal representation of an expression + may have reference type even when the standard says + it does not. Therefore, we have to manually obtain + the underlying type here. */ + scope = non_reference (scope); + /* The type of the POSTFIX_EXPRESSION must be + complete. */ + scope = complete_type_or_else (scope, NULL_TREE); + /* Let the name lookup machinery know that we are + processing a class member access expression. */ + parser->context->object_type = scope; + /* If something went wrong, we want to be able to + discern that case, as opposed to the case where + there was no SCOPE due to the type of expression + being dependent. */ + if (!scope) + scope = error_mark_node; + /* If the SCOPE was erroneous, make the various + semantic analysis functions exit quickly -- and + without issuing additional error messages. */ + if (scope == error_mark_node) + postfix_expression = error_mark_node; + } + + /* Consume the `.' or `->' operator. */ + cp_lexer_consume_token (parser->lexer); + /* If the SCOPE is not a scalar type, we are looking at an + ordinary class member access expression, rather than a + pseudo-destructor-name. */ + if (!scope || !SCALAR_TYPE_P (scope)) + { + template_p = cp_parser_optional_template_keyword (parser); + /* Parse the id-expression. */ + name = cp_parser_id_expression (parser, + template_p, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false); + /* In general, build a SCOPE_REF if the member name is + qualified. However, if the name was not dependent + and has already been resolved; there is no need to + build the SCOPE_REF. For example; + + struct X { void f(); }; + template <typename T> void f(T* t) { t->X::f(); } + + Even though "t" is dependent, "X::f" is not and has + been resolved to a BASELINK; there is no need to + include scope information. */ + + /* But we do need to remember that there was an explicit + scope for virtual function calls. */ + if (parser->scope) + idk = CP_ID_KIND_QUALIFIED; + + if (name != error_mark_node + && !BASELINK_P (name) + && parser->scope) + { + name = build_nt (SCOPE_REF, parser->scope, name); + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + } + if (scope && name && BASELINK_P (name)) + adjust_result_of_qualified_name_lookup + (name, BINFO_TYPE (BASELINK_BINFO (name)), scope); + postfix_expression + = finish_class_member_access_expr (postfix_expression, name); + } + /* Otherwise, try the pseudo-destructor-name production. */ + else + { + tree s = NULL_TREE; + tree type; + + /* Parse the pseudo-destructor-name. */ + cp_parser_pseudo_destructor_name (parser, &s, &type); + /* Form the call. */ + postfix_expression + = finish_pseudo_destructor_expr (postfix_expression, + s, TREE_TYPE (type)); + } + + /* We no longer need to look up names in the scope of the + object on the left-hand side of the `.' or `->' + operator. */ + parser->context->object_type = NULL_TREE; + /* These operators may not appear in constant-expressions. */ + if (/* The "->" operator is allowed in the implementation + of "offsetof". The "." operator may appear in the + name of the member. */ + !parser->in_offsetof_p + && (cp_parser_non_integral_constant_expression + (parser, + token_type == CPP_DEREF ? "'->'" : "`.'"))) + postfix_expression = error_mark_node; + } + break; + + case CPP_PLUS_PLUS: + /* postfix-expression ++ */ + /* Consume the `++' token. */ + cp_lexer_consume_token (parser->lexer); + /* Generate a representation for the complete expression. */ + postfix_expression + = finish_increment_expr (postfix_expression, + POSTINCREMENT_EXPR); + /* Increments may not appear in constant-expressions. */ + if (cp_parser_non_integral_constant_expression (parser, + "an increment")) + postfix_expression = error_mark_node; + idk = CP_ID_KIND_NONE; + break; + + case CPP_MINUS_MINUS: + /* postfix-expression -- */ + /* Consume the `--' token. */ + cp_lexer_consume_token (parser->lexer); + /* Generate a representation for the complete expression. */ + postfix_expression + = finish_increment_expr (postfix_expression, + POSTDECREMENT_EXPR); + /* Decrements may not appear in constant-expressions. */ + if (cp_parser_non_integral_constant_expression (parser, + "a decrement")) + postfix_expression = error_mark_node; + idk = CP_ID_KIND_NONE; + break; + + default: + return postfix_expression; + } + } + + /* We should never get here. */ + abort (); + return error_mark_node; +} + +/* Parse a parenthesized expression-list. + + expression-list: + assignment-expression + expression-list, assignment-expression + + attribute-list: + expression-list + identifier + identifier, expression-list + + Returns a TREE_LIST. The TREE_VALUE of each node is a + representation of an assignment-expression. Note that a TREE_LIST + is returned even if there is only a single expression in the list. + error_mark_node is returned if the ( and or ) are + missing. NULL_TREE is returned on no expressions. The parentheses + are eaten. IS_ATTRIBUTE_LIST is true if this is really an attribute + list being parsed. If NON_CONSTANT_P is non-NULL, *NON_CONSTANT_P + indicates whether or not all of the expressions in the list were + constant. */ + +static tree +cp_parser_parenthesized_expression_list (cp_parser* parser, + bool is_attribute_list, + bool *non_constant_p) +{ + tree expression_list = NULL_TREE; + tree identifier = NULL_TREE; + + /* Assume all the expressions will be constant. */ + if (non_constant_p) + *non_constant_p = false; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + return error_mark_node; + + /* Consume expressions until there are no more. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) + while (true) + { + tree expr; + + /* At the beginning of attribute lists, check to see if the + next token is an identifier. */ + if (is_attribute_list + && cp_lexer_peek_token (parser->lexer)->type == CPP_NAME) + { + cp_token *token; + + /* Consume the identifier. */ + token = cp_lexer_consume_token (parser->lexer); + /* Save the identifier. */ + identifier = token->value; + } + else + { + /* Parse the next assignment-expression. */ + if (non_constant_p) + { + bool expr_non_constant_p; + expr = (cp_parser_constant_expression + (parser, /*allow_non_constant_p=*/true, + &expr_non_constant_p)); + if (expr_non_constant_p) + *non_constant_p = true; + } + else + expr = cp_parser_assignment_expression (parser); + + /* Add it to the list. We add error_mark_node + expressions to the list, so that we can still tell if + the correct form for a parenthesized expression-list + is found. That gives better errors. */ + expression_list = tree_cons (NULL_TREE, expr, expression_list); + + if (expr == error_mark_node) + goto skip_comma; + } + + /* After the first item, attribute lists look the same as + expression lists. */ + is_attribute_list = false; + + get_comma:; + /* If the next token isn't a `,', then we are done. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + + /* Otherwise, consume the `,' and keep going. */ + cp_lexer_consume_token (parser->lexer); + } + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + { + int ending; + + skip_comma:; + /* We try and resync to an unnested comma, as that will give the + user better diagnostics. */ + ending = cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/true, + /*consume_paren=*/true); + if (ending < 0) + goto get_comma; + if (!ending) + return error_mark_node; + } + + /* We built up the list in reverse order so we must reverse it now. */ + expression_list = nreverse (expression_list); + if (identifier) + expression_list = tree_cons (NULL_TREE, identifier, expression_list); + + return expression_list; +} + +/* Parse a pseudo-destructor-name. + + pseudo-destructor-name: + :: [opt] nested-name-specifier [opt] type-name :: ~ type-name + :: [opt] nested-name-specifier template template-id :: ~ type-name + :: [opt] nested-name-specifier [opt] ~ type-name + + If either of the first two productions is used, sets *SCOPE to the + TYPE specified before the final `::'. Otherwise, *SCOPE is set to + NULL_TREE. *TYPE is set to the TYPE_DECL for the final type-name, + or ERROR_MARK_NODE if the parse fails. */ + +static void +cp_parser_pseudo_destructor_name (cp_parser* parser, + tree* scope, + tree* type) +{ + bool nested_name_specifier_p; + + /* Look for the optional `::' operator. */ + cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/true); + /* 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=*/true, + /*type_p=*/false, + /*is_declaration=*/true) + != NULL_TREE); + /* Now, if we saw a nested-name-specifier, we might be doing the + second production. */ + if (nested_name_specifier_p + && cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + { + /* Consume the `template' keyword. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the template-id. */ + cp_parser_template_id (parser, + /*template_keyword_p=*/true, + /*check_dependency_p=*/false, + /*is_declaration=*/true); + /* Look for the `::' token. */ + cp_parser_require (parser, CPP_SCOPE, "`::'"); + } + /* If the next token is not a `~', then there might be some + additional qualification. */ + else if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMPL)) + { + /* Look for the type-name. */ + *scope = TREE_TYPE (cp_parser_type_name (parser)); + + /* If we didn't get an aggregate type, or we don't have ::~, + then something has gone wrong. Since the only caller of this + function is looking for something after `.' or `->' after a + scalar type, most likely the program is trying to get a + member of a non-aggregate type. */ + if (*scope == error_mark_node + || cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE) + || cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_COMPL) + { + cp_parser_error (parser, "request for member of non-aggregate type"); + *type = error_mark_node; + return; + } + + /* Look for the `::' token. */ + cp_parser_require (parser, CPP_SCOPE, "`::'"); + } + else + *scope = NULL_TREE; + + /* Look for the `~'. */ + cp_parser_require (parser, CPP_COMPL, "`~'"); + /* Look for the type-name again. We are not responsible for + checking that it matches the first type-name. */ + *type = cp_parser_type_name (parser); +} + +/* Parse a unary-expression. + + unary-expression: + postfix-expression + ++ cast-expression + -- cast-expression + unary-operator cast-expression + sizeof unary-expression + sizeof ( type-id ) + new-expression + delete-expression + + GNU Extensions: + + unary-expression: + __extension__ cast-expression + __alignof__ unary-expression + __alignof__ ( type-id ) + __real__ cast-expression + __imag__ cast-expression + && identifier + + ADDRESS_P is true iff the unary-expression is appearing as the + operand of the `&' operator. + + Returns a representation of the expression. */ + +static tree +cp_parser_unary_expression (cp_parser *parser, bool address_p) +{ + cp_token *token; + enum tree_code unary_operator; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* Some keywords give away the kind of expression. */ + if (token->type == CPP_KEYWORD) + { + enum rid keyword = token->keyword; + + switch (keyword) + { + case RID_ALIGNOF: + case RID_SIZEOF: + { + tree operand; + enum tree_code op; + + op = keyword == RID_ALIGNOF ? ALIGNOF_EXPR : SIZEOF_EXPR; + /* Consume the token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the operand. */ + operand = cp_parser_sizeof_operand (parser, keyword); + + if (TYPE_P (operand)) + return cxx_sizeof_or_alignof_type (operand, op, true); + else + return cxx_sizeof_or_alignof_expr (operand, op); + } + + case RID_NEW: + return cp_parser_new_expression (parser); + + case RID_DELETE: + return cp_parser_delete_expression (parser); + + case RID_EXTENSION: + { + /* The saved value of the PEDANTIC flag. */ + int saved_pedantic; + tree expr; + + /* Save away the PEDANTIC flag. */ + cp_parser_extension_opt (parser, &saved_pedantic); + /* Parse the cast-expression. */ + expr = cp_parser_simple_cast_expression (parser); + /* Restore the PEDANTIC flag. */ + pedantic = saved_pedantic; + + return expr; + } + + case RID_REALPART: + case RID_IMAGPART: + { + tree expression; + + /* Consume the `__real__' or `__imag__' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the cast-expression. */ + expression = cp_parser_simple_cast_expression (parser); + /* Create the complete representation. */ + return build_x_unary_op ((keyword == RID_REALPART + ? REALPART_EXPR : IMAGPART_EXPR), + expression); + } + break; + + default: + break; + } + } + + /* Look for the `:: new' and `:: delete', which also signal the + beginning of a new-expression, or delete-expression, + respectively. If the next token is `::', then it might be one of + these. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) + { + enum rid keyword; + + /* See if the token after the `::' is one of the keywords in + which we're interested. */ + keyword = cp_lexer_peek_nth_token (parser->lexer, 2)->keyword; + /* If it's `new', we have a new-expression. */ + if (keyword == RID_NEW) + return cp_parser_new_expression (parser); + /* Similarly, for `delete'. */ + else if (keyword == RID_DELETE) + return cp_parser_delete_expression (parser); + } + + /* Look for a unary operator. */ + unary_operator = cp_parser_unary_operator (token); + /* The `++' and `--' operators can be handled similarly, even though + they are not technically unary-operators in the grammar. */ + if (unary_operator == ERROR_MARK) + { + if (token->type == CPP_PLUS_PLUS) + unary_operator = PREINCREMENT_EXPR; + else if (token->type == CPP_MINUS_MINUS) + unary_operator = PREDECREMENT_EXPR; + /* Handle the GNU address-of-label extension. */ + else if (cp_parser_allow_gnu_extensions_p (parser) + && token->type == CPP_AND_AND) + { + tree identifier; + + /* Consume the '&&' token. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the identifier. */ + identifier = cp_parser_identifier (parser); + /* Create an expression representing the address. */ + return finish_label_address_expr (identifier); + } + } + if (unary_operator != ERROR_MARK) + { + tree cast_expression; + tree expression = error_mark_node; + const char *non_constant_p = NULL; + + /* Consume the operator token. */ + token = cp_lexer_consume_token (parser->lexer); + /* Parse the cast-expression. */ + cast_expression + = cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR); + /* Now, build an appropriate representation. */ + switch (unary_operator) + { + case INDIRECT_REF: + non_constant_p = "`*'"; + expression = build_x_indirect_ref (cast_expression, "unary *"); + break; + + case ADDR_EXPR: + /* The "&" operator is allowed in the implementation of + "offsetof". */ + if (!parser->in_offsetof_p) + non_constant_p = "`&'"; + /* Fall through. */ + case BIT_NOT_EXPR: + expression = build_x_unary_op (unary_operator, cast_expression); + break; + + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + non_constant_p = (unary_operator == PREINCREMENT_EXPR + ? "`++'" : "`--'"); + /* Fall through. */ + case CONVERT_EXPR: + case NEGATE_EXPR: + case TRUTH_NOT_EXPR: + expression = finish_unary_op_expr (unary_operator, cast_expression); + break; + + default: + abort (); + } + + if (non_constant_p + && cp_parser_non_integral_constant_expression (parser, + non_constant_p)) + expression = error_mark_node; + + return expression; + } + + return cp_parser_postfix_expression (parser, address_p); +} + +/* Returns ERROR_MARK if TOKEN is not a unary-operator. If TOKEN is a + unary-operator, the corresponding tree code is returned. */ + +static enum tree_code +cp_parser_unary_operator (cp_token* token) +{ + switch (token->type) + { + case CPP_MULT: + return INDIRECT_REF; + + case CPP_AND: + return ADDR_EXPR; + + case CPP_PLUS: + return CONVERT_EXPR; + + case CPP_MINUS: + return NEGATE_EXPR; + + case CPP_NOT: + return TRUTH_NOT_EXPR; + + case CPP_COMPL: + return BIT_NOT_EXPR; + + default: + return ERROR_MARK; + } +} + +/* Parse a new-expression. + + new-expression: + :: [opt] new new-placement [opt] new-type-id new-initializer [opt] + :: [opt] new new-placement [opt] ( type-id ) new-initializer [opt] + + Returns a representation of the expression. */ + +static tree +cp_parser_new_expression (cp_parser* parser) +{ + bool global_scope_p; + tree placement; + tree type; + tree initializer; + + /* Look for the optional `::' operator. */ + global_scope_p + = (cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false) + != NULL_TREE); + /* Look for the `new' operator. */ + cp_parser_require_keyword (parser, RID_NEW, "`new'"); + /* There's no easy way to tell a new-placement from the + `( type-id )' construct. */ + cp_parser_parse_tentatively (parser); + /* Look for a new-placement. */ + placement = cp_parser_new_placement (parser); + /* If that didn't work out, there's no new-placement. */ + if (!cp_parser_parse_definitely (parser)) + placement = NULL_TREE; + + /* If the next token is a `(', then we have a parenthesized + type-id. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + /* Consume the `('. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the type-id. */ + type = cp_parser_type_id (parser); + /* Look for the closing `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* There should not be a direct-new-declarator in this production, + but GCC used to allowed this, so we check and emit a sensible error + message for this case. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + { + error ("array bound forbidden after parenthesized type-id"); + inform ("try removing the parentheses around the type-id"); + cp_parser_direct_new_declarator (parser); + } + } + /* Otherwise, there must be a new-type-id. */ + else + type = cp_parser_new_type_id (parser); + + /* If the next token is a `(', then we have a new-initializer. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + initializer = cp_parser_new_initializer (parser); + else + initializer = NULL_TREE; + + /* A new-expression may not appear in an integral constant + expression. */ + if (cp_parser_non_integral_constant_expression (parser, "`new'")) + return error_mark_node; + + /* Create a representation of the new-expression. */ + return build_new (placement, type, initializer, global_scope_p); +} + +/* Parse a new-placement. + + new-placement: + ( expression-list ) + + Returns the same representation as for an expression-list. */ + +static tree +cp_parser_new_placement (cp_parser* parser) +{ + tree expression_list; + + /* Parse the expression-list. */ + expression_list = (cp_parser_parenthesized_expression_list + (parser, false, /*non_constant_p=*/NULL)); + + return expression_list; +} + +/* Parse a new-type-id. + + new-type-id: + type-specifier-seq new-declarator [opt] + + Returns a TREE_LIST whose TREE_PURPOSE is the type-specifier-seq, + and whose TREE_VALUE is the new-declarator. */ + +static tree +cp_parser_new_type_id (cp_parser* parser) +{ + tree type_specifier_seq; + tree declarator; + const char *saved_message; + + /* The type-specifier sequence must not contain type definitions. + (It cannot contain declarations of new types either, but if they + are not definitions we will catch that because they are not + complete.) */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = "types may not be defined in a new-type-id"; + /* Parse the type-specifier-seq. */ + type_specifier_seq = cp_parser_type_specifier_seq (parser); + /* Restore the old message. */ + parser->type_definition_forbidden_message = saved_message; + /* Parse the new-declarator. */ + declarator = cp_parser_new_declarator_opt (parser); + + return build_tree_list (type_specifier_seq, declarator); +} + +/* Parse an (optional) new-declarator. + + new-declarator: + ptr-operator new-declarator [opt] + direct-new-declarator + + Returns a representation of the declarator. See + cp_parser_declarator for the representations used. */ + +static tree +cp_parser_new_declarator_opt (cp_parser* parser) +{ + enum tree_code code; + tree type; + tree cv_qualifier_seq; + + /* We don't know if there's a ptr-operator next, or not. */ + cp_parser_parse_tentatively (parser); + /* Look for a ptr-operator. */ + code = cp_parser_ptr_operator (parser, &type, &cv_qualifier_seq); + /* If that worked, look for more new-declarators. */ + if (cp_parser_parse_definitely (parser)) + { + tree declarator; + + /* Parse another optional declarator. */ + declarator = cp_parser_new_declarator_opt (parser); + + /* Create the representation of the declarator. */ + if (code == INDIRECT_REF) + declarator = make_pointer_declarator (cv_qualifier_seq, + declarator); + else + declarator = make_reference_declarator (cv_qualifier_seq, + declarator); + + /* Handle the pointer-to-member case. */ + if (type) + declarator = build_nt (SCOPE_REF, type, declarator); + + return declarator; + } + + /* If the next token is a `[', there is a direct-new-declarator. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + return cp_parser_direct_new_declarator (parser); + + return NULL_TREE; +} + +/* Parse a direct-new-declarator. + + direct-new-declarator: + [ expression ] + direct-new-declarator [constant-expression] + + Returns an ARRAY_REF, following the same conventions as are + documented for cp_parser_direct_declarator. */ + +static tree +cp_parser_direct_new_declarator (cp_parser* parser) +{ + tree declarator = NULL_TREE; + + while (true) + { + tree expression; + + /* Look for the opening `['. */ + cp_parser_require (parser, CPP_OPEN_SQUARE, "`['"); + /* The first expression is not required to be constant. */ + if (!declarator) + { + expression = cp_parser_expression (parser); + /* The standard requires that the expression have integral + type. DR 74 adds enumeration types. We believe that the + real intent is that these expressions be handled like the + expression in a `switch' condition, which also allows + classes with a single conversion to integral or + enumeration type. */ + if (!processing_template_decl) + { + expression + = build_expr_type_conversion (WANT_INT | WANT_ENUM, + expression, + /*complain=*/true); + if (!expression) + { + error ("expression in new-declarator must have integral or enumeration type"); + expression = error_mark_node; + } + } + } + /* But all the other expressions must be. */ + else + expression + = cp_parser_constant_expression (parser, + /*allow_non_constant=*/false, + NULL); + /* Look for the closing `]'. */ + cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"); + + /* Add this bound to the declarator. */ + declarator = build_nt (ARRAY_REF, declarator, expression); + + /* If the next token is not a `[', then there are no more + bounds. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE)) + break; + } + + return declarator; +} + +/* Parse a new-initializer. + + new-initializer: + ( expression-list [opt] ) + + Returns a representation of the expression-list. If there is no + expression-list, VOID_ZERO_NODE is returned. */ + +static tree +cp_parser_new_initializer (cp_parser* parser) +{ + tree expression_list; + + expression_list = (cp_parser_parenthesized_expression_list + (parser, false, /*non_constant_p=*/NULL)); + if (!expression_list) + expression_list = void_zero_node; + + return expression_list; +} + +/* Parse a delete-expression. + + delete-expression: + :: [opt] delete cast-expression + :: [opt] delete [ ] cast-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_delete_expression (cp_parser* parser) +{ + bool global_scope_p; + bool array_p; + tree expression; + + /* Look for the optional `::' operator. */ + global_scope_p + = (cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false) + != NULL_TREE); + /* Look for the `delete' keyword. */ + cp_parser_require_keyword (parser, RID_DELETE, "`delete'"); + /* See if the array syntax is in use. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + { + /* Consume the `[' token. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the `]' token. */ + cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"); + /* Remember that this is the `[]' construct. */ + array_p = true; + } + else + array_p = false; + + /* Parse the cast-expression. */ + expression = cp_parser_simple_cast_expression (parser); + + /* A delete-expression may not appear in an integral constant + expression. */ + if (cp_parser_non_integral_constant_expression (parser, "`delete'")) + return error_mark_node; + + return delete_sanity (expression, NULL_TREE, array_p, global_scope_p); +} + +/* Parse a cast-expression. + + cast-expression: + unary-expression + ( type-id ) cast-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_cast_expression (cp_parser *parser, bool address_p) +{ + /* If it's a `(', then we might be looking at a cast. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + tree type = NULL_TREE; + tree expr = NULL_TREE; + bool compound_literal_p; + const char *saved_message; + + /* There's no way to know yet whether or not this is a cast. + For example, `(int (3))' is a unary-expression, while `(int) + 3' is a cast. So, we resort to parsing tentatively. */ + cp_parser_parse_tentatively (parser); + /* Types may not be defined in a cast. */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = "types may not be defined in casts"; + /* Consume the `('. */ + cp_lexer_consume_token (parser->lexer); + /* A very tricky bit is that `(struct S) { 3 }' is a + compound-literal (which we permit in C++ as an extension). + But, that construct is not a cast-expression -- it is a + postfix-expression. (The reason is that `(struct S) { 3 }.i' + is legal; if the compound-literal were a cast-expression, + you'd need an extra set of parentheses.) But, if we parse + the type-id, and it happens to be a class-specifier, then we + will commit to the parse at that point, because we cannot + undo the action that is done when creating a new class. So, + then we cannot back up and do a postfix-expression. + + Therefore, we scan ahead to the closing `)', and check to see + if the token after the `)' is a `{'. If so, we are not + looking at a cast-expression. + + Save tokens so that we can put them back. */ + cp_lexer_save_tokens (parser->lexer); + /* Skip tokens until the next token is a closing parenthesis. + If we find the closing `)', and the next token is a `{', then + we are looking at a compound-literal. */ + compound_literal_p + = (cp_parser_skip_to_closing_parenthesis (parser, false, false, + /*consume_paren=*/true) + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)); + /* Roll back the tokens we skipped. */ + cp_lexer_rollback_tokens (parser->lexer); + /* If we were looking at a compound-literal, simulate an error + so that the call to cp_parser_parse_definitely below will + fail. */ + if (compound_literal_p) + cp_parser_simulate_error (parser); + else + { + bool saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; + parser->in_type_id_in_expr_p = true; + /* Look for the type-id. */ + type = cp_parser_type_id (parser); + /* Look for the closing `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; + } + + /* Restore the saved message. */ + parser->type_definition_forbidden_message = saved_message; + + /* If ok so far, parse the dependent expression. We cannot be + sure it is a cast. Consider `(T ())'. It is a parenthesized + ctor of T, but looks like a cast to function returning T + without a dependent expression. */ + if (!cp_parser_error_occurred (parser)) + expr = cp_parser_simple_cast_expression (parser); + + if (cp_parser_parse_definitely (parser)) + { + /* Warn about old-style casts, if so requested. */ + if (warn_old_style_cast + && !in_system_header + && !VOID_TYPE_P (type) + && current_lang_name != lang_name_c) + warning ("use of old-style cast"); + + /* 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) + && (cp_parser_non_integral_constant_expression + (parser, + "a casts to a type other than an integral or " + "enumeration type"))) + return error_mark_node; + + /* Perform the cast. */ + expr = build_c_cast (type, expr); + return expr; + } + } + + /* If we get here, then it's not a cast, so it must be a + unary-expression. */ + return cp_parser_unary_expression (parser, address_p); +} + +/* Parse a pm-expression. + + pm-expression: + cast-expression + pm-expression .* cast-expression + pm-expression ->* cast-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_pm_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_DEREF_STAR, MEMBER_REF }, + { CPP_DOT_STAR, DOTSTAR_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, map, + cp_parser_simple_cast_expression); +} + +/* Parse a multiplicative-expression. + + mulitplicative-expression: + pm-expression + multiplicative-expression * pm-expression + multiplicative-expression / pm-expression + multiplicative-expression % pm-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_multiplicative_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_MULT, MULT_EXPR }, + { CPP_DIV, TRUNC_DIV_EXPR }, + { CPP_MOD, TRUNC_MOD_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_pm_expression); +} + +/* Parse an additive-expression. + + additive-expression: + multiplicative-expression + additive-expression + multiplicative-expression + additive-expression - multiplicative-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_additive_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_PLUS, PLUS_EXPR }, + { CPP_MINUS, MINUS_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_multiplicative_expression); +} + +/* Parse a shift-expression. + + shift-expression: + additive-expression + shift-expression << additive-expression + shift-expression >> additive-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_shift_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_LSHIFT, LSHIFT_EXPR }, + { CPP_RSHIFT, RSHIFT_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_additive_expression); +} + +/* Parse a relational-expression. + + relational-expression: + shift-expression + relational-expression < shift-expression + relational-expression > shift-expression + relational-expression <= shift-expression + relational-expression >= shift-expression + + GNU Extension: + + relational-expression: + relational-expression <? shift-expression + relational-expression >? shift-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_relational_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_LESS, LT_EXPR }, + { CPP_GREATER, GT_EXPR }, + { CPP_LESS_EQ, LE_EXPR }, + { CPP_GREATER_EQ, GE_EXPR }, + { CPP_MIN, MIN_EXPR }, + { CPP_MAX, MAX_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_shift_expression); +} + +/* Parse an equality-expression. + + equality-expression: + relational-expression + equality-expression == relational-expression + equality-expression != relational-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_equality_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_EQ_EQ, EQ_EXPR }, + { CPP_NOT_EQ, NE_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_relational_expression); +} + +/* Parse an and-expression. + + and-expression: + equality-expression + and-expression & equality-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_and_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_AND, BIT_AND_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_equality_expression); +} + +/* Parse an exclusive-or-expression. + + exclusive-or-expression: + and-expression + exclusive-or-expression ^ and-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_exclusive_or_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_XOR, BIT_XOR_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_and_expression); +} + + +/* Parse an inclusive-or-expression. + + inclusive-or-expression: + exclusive-or-expression + inclusive-or-expression | exclusive-or-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_inclusive_or_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_OR, BIT_IOR_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_exclusive_or_expression); +} + +/* Parse a logical-and-expression. + + logical-and-expression: + inclusive-or-expression + logical-and-expression && inclusive-or-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_logical_and_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_AND_AND, TRUTH_ANDIF_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_inclusive_or_expression); +} + +/* Parse a logical-or-expression. + + logical-or-expression: + logical-and-expression + logical-or-expression || logical-and-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_logical_or_expression (cp_parser* parser) +{ + static const cp_parser_token_tree_map map = { + { CPP_OR_OR, TRUTH_ORIF_EXPR }, + { CPP_EOF, ERROR_MARK } + }; + + return cp_parser_binary_expression (parser, + map, + cp_parser_logical_and_expression); +} + +/* Parse the `? expression : assignment-expression' part of a + conditional-expression. The LOGICAL_OR_EXPR is the + logical-or-expression that started the conditional-expression. + Returns a representation of the entire conditional-expression. + + This routine is used by cp_parser_assignment_expression. + + ? expression : assignment-expression + + GNU Extensions: + + ? : assignment-expression */ + +static tree +cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr) +{ + tree expr; + tree assignment_expr; + + /* Consume the `?' token. */ + cp_lexer_consume_token (parser->lexer); + if (cp_parser_allow_gnu_extensions_p (parser) + && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + /* Implicit true clause. */ + expr = NULL_TREE; + else + /* Parse the expression. */ + expr = cp_parser_expression (parser); + + /* The next token should be a `:'. */ + cp_parser_require (parser, CPP_COLON, "`:'"); + /* Parse the assignment-expression. */ + assignment_expr = cp_parser_assignment_expression (parser); + + /* Build the conditional-expression. */ + return build_x_conditional_expr (logical_or_expr, + expr, + assignment_expr); +} + +/* Parse an assignment-expression. + + assignment-expression: + conditional-expression + logical-or-expression assignment-operator assignment_expression + throw-expression + + Returns a representation for the expression. */ + +static tree +cp_parser_assignment_expression (cp_parser* parser) +{ + tree expr; + + /* If the next token is the `throw' keyword, then we're looking at + a throw-expression. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_THROW)) + expr = cp_parser_throw_expression (parser); + /* Otherwise, it must be that we are looking at a + logical-or-expression. */ + else + { + /* Parse the logical-or-expression. */ + expr = cp_parser_logical_or_expression (parser); + /* If the next token is a `?' then we're actually looking at a + conditional-expression. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY)) + return cp_parser_question_colon_clause (parser, expr); + else + { + enum tree_code assignment_operator; + + /* If it's an assignment-operator, we're using the second + production. */ + assignment_operator + = cp_parser_assignment_operator_opt (parser); + if (assignment_operator != ERROR_MARK) + { + tree rhs; + + /* Parse the right-hand side of the assignment. */ + rhs = cp_parser_assignment_expression (parser); + /* An assignment may not appear in a + constant-expression. */ + if (cp_parser_non_integral_constant_expression (parser, + "an assignment")) + return error_mark_node; + /* Build the assignment expression. */ + expr = build_x_modify_expr (expr, + assignment_operator, + rhs); + } + } + } + + return expr; +} + +/* Parse an (optional) assignment-operator. + + assignment-operator: one of + = *= /= %= += -= >>= <<= &= ^= |= + + GNU Extension: + + assignment-operator: one of + <?= >?= + + If the next token is an assignment operator, the corresponding tree + code is returned, and the token is consumed. For example, for + `+=', PLUS_EXPR is returned. For `=' itself, the code returned is + NOP_EXPR. For `/', TRUNC_DIV_EXPR is returned; for `%', + TRUNC_MOD_EXPR is returned. If TOKEN is not an assignment + operator, ERROR_MARK is returned. */ + +static enum tree_code +cp_parser_assignment_operator_opt (cp_parser* parser) +{ + enum tree_code op; + cp_token *token; + + /* Peek at the next toen. */ + token = cp_lexer_peek_token (parser->lexer); + + switch (token->type) + { + case CPP_EQ: + op = NOP_EXPR; + break; + + case CPP_MULT_EQ: + op = MULT_EXPR; + break; + + case CPP_DIV_EQ: + op = TRUNC_DIV_EXPR; + break; + + case CPP_MOD_EQ: + op = TRUNC_MOD_EXPR; + break; + + case CPP_PLUS_EQ: + op = PLUS_EXPR; + break; + + case CPP_MINUS_EQ: + op = MINUS_EXPR; + break; + + case CPP_RSHIFT_EQ: + op = RSHIFT_EXPR; + break; + + case CPP_LSHIFT_EQ: + op = LSHIFT_EXPR; + break; + + case CPP_AND_EQ: + op = BIT_AND_EXPR; + break; + + case CPP_XOR_EQ: + op = BIT_XOR_EXPR; + break; + + case CPP_OR_EQ: + op = BIT_IOR_EXPR; + break; + + case CPP_MIN_EQ: + op = MIN_EXPR; + break; + + case CPP_MAX_EQ: + op = MAX_EXPR; + break; + + default: + /* Nothing else is an assignment operator. */ + op = ERROR_MARK; + } + + /* If it was an assignment operator, consume it. */ + if (op != ERROR_MARK) + cp_lexer_consume_token (parser->lexer); + + return op; +} + +/* Parse an expression. + + expression: + assignment-expression + expression , assignment-expression + + Returns a representation of the expression. */ + +static tree +cp_parser_expression (cp_parser* parser) +{ + tree expression = NULL_TREE; + + while (true) + { + tree assignment_expression; + + /* Parse the next assignment-expression. */ + assignment_expression + = cp_parser_assignment_expression (parser); + /* If this is the first assignment-expression, we can just + save it away. */ + if (!expression) + expression = assignment_expression; + else + expression = build_x_compound_expr (expression, + assignment_expression); + /* If the next token is not a comma, then we are done with the + expression. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + /* Consume the `,'. */ + cp_lexer_consume_token (parser->lexer); + /* A comma operator cannot appear in a constant-expression. */ + if (cp_parser_non_integral_constant_expression (parser, + "a comma operator")) + expression = error_mark_node; + } + + return expression; +} + +/* Parse a constant-expression. + + constant-expression: + conditional-expression + + If ALLOW_NON_CONSTANT_P a non-constant expression is silently + accepted. If ALLOW_NON_CONSTANT_P is true and the expression is not + constant, *NON_CONSTANT_P is set to TRUE. If ALLOW_NON_CONSTANT_P + is false, NON_CONSTANT_P should be NULL. */ + +static tree +cp_parser_constant_expression (cp_parser* parser, + bool allow_non_constant_p, + bool *non_constant_p) +{ + bool saved_integral_constant_expression_p; + bool saved_allow_non_integral_constant_expression_p; + bool saved_non_integral_constant_expression_p; + tree expression; + + /* It might seem that we could simply parse the + conditional-expression, and then check to see if it were + TREE_CONSTANT. However, an expression that is TREE_CONSTANT is + one that the compiler can figure out is constant, possibly after + doing some simplifications or optimizations. The standard has a + precise definition of constant-expression, and we must honor + that, even though it is somewhat more restrictive. + + For example: + + int i[(2, 3)]; + + is not a legal declaration, because `(2, 3)' is not a + constant-expression. The `,' operator is forbidden in a + constant-expression. However, GCC's constant-folding machinery + will fold this operation to an INTEGER_CST for `3'. */ + + /* Save the old settings. */ + saved_integral_constant_expression_p = parser->integral_constant_expression_p; + saved_allow_non_integral_constant_expression_p + = parser->allow_non_integral_constant_expression_p; + saved_non_integral_constant_expression_p = parser->non_integral_constant_expression_p; + /* We are now parsing a constant-expression. */ + parser->integral_constant_expression_p = true; + parser->allow_non_integral_constant_expression_p = allow_non_constant_p; + parser->non_integral_constant_expression_p = false; + /* Although the grammar says "conditional-expression", we parse an + "assignment-expression", which also permits "throw-expression" + and the use of assignment operators. In the case that + ALLOW_NON_CONSTANT_P is false, we get better errors than we would + otherwise. In the case that ALLOW_NON_CONSTANT_P is true, it is + actually essential that we look for an assignment-expression. + For example, cp_parser_initializer_clauses uses this function to + determine whether a particular assignment-expression is in fact + constant. */ + expression = cp_parser_assignment_expression (parser); + /* Restore the old settings. */ + parser->integral_constant_expression_p = saved_integral_constant_expression_p; + parser->allow_non_integral_constant_expression_p + = saved_allow_non_integral_constant_expression_p; + if (allow_non_constant_p) + *non_constant_p = parser->non_integral_constant_expression_p; + parser->non_integral_constant_expression_p = saved_non_integral_constant_expression_p; + + return expression; +} + +/* Statements [gram.stmt.stmt] */ + +/* Parse a statement. + + statement: + labeled-statement + expression-statement + compound-statement + selection-statement + iteration-statement + jump-statement + declaration-statement + try-block */ + +static void +cp_parser_statement (cp_parser* parser, bool in_statement_expr_p) +{ + tree statement; + cp_token *token; + int statement_line_number; + + /* There is no statement yet. */ + statement = NULL_TREE; + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* Remember the line number of the first token in the statement. */ + statement_line_number = token->location.line; + /* If this is a keyword, then that will often determine what kind of + statement we have. */ + if (token->type == CPP_KEYWORD) + { + enum rid keyword = token->keyword; + + switch (keyword) + { + case RID_CASE: + case RID_DEFAULT: + statement = cp_parser_labeled_statement (parser, + in_statement_expr_p); + break; + + case RID_IF: + case RID_SWITCH: + statement = cp_parser_selection_statement (parser); + break; + + case RID_WHILE: + case RID_DO: + case RID_FOR: + statement = cp_parser_iteration_statement (parser); + break; + + case RID_BREAK: + case RID_CONTINUE: + case RID_RETURN: + case RID_GOTO: + statement = cp_parser_jump_statement (parser); + break; + + case RID_TRY: + statement = cp_parser_try_block (parser); + break; + + default: + /* It might be a keyword like `int' that can start a + declaration-statement. */ + break; + } + } + else if (token->type == CPP_NAME) + { + /* If the next token is a `:', then we are looking at a + labeled-statement. */ + token = cp_lexer_peek_nth_token (parser->lexer, 2); + if (token->type == CPP_COLON) + statement = cp_parser_labeled_statement (parser, in_statement_expr_p); + } + /* Anything that starts with a `{' must be a compound-statement. */ + else if (token->type == CPP_OPEN_BRACE) + statement = cp_parser_compound_statement (parser, false); + + /* Everything else must be a declaration-statement or an + expression-statement. Try for the declaration-statement + first, unless we are looking at a `;', in which case we know that + we have an expression-statement. */ + if (!statement) + { + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + { + cp_parser_parse_tentatively (parser); + /* Try to parse the declaration-statement. */ + cp_parser_declaration_statement (parser); + /* If that worked, we're done. */ + if (cp_parser_parse_definitely (parser)) + return; + } + /* Look for an expression-statement instead. */ + statement = cp_parser_expression_statement (parser, in_statement_expr_p); + } + + /* Set the line number for the statement. */ + if (statement && STATEMENT_CODE_P (TREE_CODE (statement))) + STMT_LINENO (statement) = statement_line_number; +} + +/* Parse a labeled-statement. + + labeled-statement: + identifier : statement + case constant-expression : statement + default : statement + + GNU Extension: + + labeled-statement: + case constant-expression ... constant-expression : statement + + Returns the new CASE_LABEL, for a `case' or `default' label. For + an ordinary label, returns a LABEL_STMT. */ + +static tree +cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p) +{ + cp_token *token; + tree statement = error_mark_node; + + /* The next token should be an identifier. */ + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_NAME + && token->type != CPP_KEYWORD) + { + cp_parser_error (parser, "expected labeled-statement"); + return error_mark_node; + } + + switch (token->keyword) + { + case RID_CASE: + { + tree expr, expr_hi; + cp_token *ellipsis; + + /* Consume the `case' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the constant-expression. */ + expr = cp_parser_constant_expression (parser, + /*allow_non_constant_p=*/false, + NULL); + + ellipsis = cp_lexer_peek_token (parser->lexer); + if (ellipsis->type == CPP_ELLIPSIS) + { + /* Consume the `...' token. */ + cp_lexer_consume_token (parser->lexer); + expr_hi = + cp_parser_constant_expression (parser, + /*allow_non_constant_p=*/false, + NULL); + /* We don't need to emit warnings here, as the common code + will do this for us. */ + } + else + expr_hi = NULL_TREE; + + if (!parser->in_switch_statement_p) + error ("case label `%E' not within a switch statement", expr); + else + statement = finish_case_label (expr, expr_hi); + } + break; + + case RID_DEFAULT: + /* Consume the `default' token. */ + cp_lexer_consume_token (parser->lexer); + if (!parser->in_switch_statement_p) + error ("case label not within a switch statement"); + else + statement = finish_case_label (NULL_TREE, NULL_TREE); + break; + + default: + /* Anything else must be an ordinary label. */ + statement = finish_label_stmt (cp_parser_identifier (parser)); + break; + } + + /* Require the `:' token. */ + cp_parser_require (parser, CPP_COLON, "`:'"); + /* Parse the labeled statement. */ + cp_parser_statement (parser, in_statement_expr_p); + + /* Return the label, in the case of a `case' or `default' label. */ + return statement; +} + +/* Parse an expression-statement. + + expression-statement: + expression [opt] ; + + Returns the new EXPR_STMT -- or NULL_TREE if the expression + statement consists of nothing more than an `;'. IN_STATEMENT_EXPR_P + indicates whether this expression-statement is part of an + expression statement. */ + +static tree +cp_parser_expression_statement (cp_parser* parser, bool in_statement_expr_p) +{ + tree statement = NULL_TREE; + + /* If the next token is a ';', then there is no expression + statement. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + statement = cp_parser_expression (parser); + + /* Consume the final `;'. */ + cp_parser_consume_semicolon_at_end_of_statement (parser); + + if (in_statement_expr_p + && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) + { + /* This is the final expression statement of a statement + expression. */ + statement = finish_stmt_expr_expr (statement); + } + else if (statement) + statement = finish_expr_stmt (statement); + else + finish_stmt (); + + return statement; +} + +/* Parse a compound-statement. + + compound-statement: + { statement-seq [opt] } + + Returns a COMPOUND_STMT representing the statement. */ + +static tree +cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p) +{ + tree compound_stmt; + + /* Consume the `{'. */ + if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'")) + return error_mark_node; + /* Begin the compound-statement. */ + compound_stmt = begin_compound_stmt (/*has_no_scope=*/false); + /* Parse an (optional) statement-seq. */ + cp_parser_statement_seq_opt (parser, in_statement_expr_p); + /* Finish the compound-statement. */ + finish_compound_stmt (compound_stmt); + /* Consume the `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); + + return compound_stmt; +} + +/* Parse an (optional) statement-seq. + + statement-seq: + statement + statement-seq [opt] statement */ + +static void +cp_parser_statement_seq_opt (cp_parser* parser, bool in_statement_expr_p) +{ + /* Scan statements until there aren't any more. */ + while (true) + { + /* If we're looking at a `}', then we've run out of statements. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE) + || cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + break; + + /* Parse the statement. */ + cp_parser_statement (parser, in_statement_expr_p); + } +} + +/* Parse a selection-statement. + + selection-statement: + if ( condition ) statement + if ( condition ) statement else statement + switch ( condition ) statement + + Returns the new IF_STMT or SWITCH_STMT. */ + +static tree +cp_parser_selection_statement (cp_parser* parser) +{ + cp_token *token; + enum rid keyword; + + /* Peek at the next token. */ + token = cp_parser_require (parser, CPP_KEYWORD, "selection-statement"); + + /* See what kind of keyword it is. */ + keyword = token->keyword; + switch (keyword) + { + case RID_IF: + case RID_SWITCH: + { + tree statement; + tree condition; + + /* Look for the `('. */ + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + { + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + + /* Begin the selection-statement. */ + if (keyword == RID_IF) + statement = begin_if_stmt (); + else + statement = begin_switch_stmt (); + + /* Parse the condition. */ + condition = cp_parser_condition (parser); + /* Look for the `)'. */ + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, true, false, + /*consume_paren=*/true); + + if (keyword == RID_IF) + { + tree then_stmt; + + /* Add the condition. */ + finish_if_stmt_cond (condition, statement); + + /* Parse the then-clause. */ + then_stmt = cp_parser_implicitly_scoped_statement (parser); + finish_then_clause (statement); + + /* If the next token is `else', parse the else-clause. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_ELSE)) + { + tree else_stmt; + + /* Consume the `else' keyword. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the else-clause. */ + else_stmt + = cp_parser_implicitly_scoped_statement (parser); + finish_else_clause (statement); + } + + /* Now we're all done with the if-statement. */ + finish_if_stmt (); + } + else + { + tree body; + bool in_switch_statement_p; + + /* Add the condition. */ + finish_switch_cond (condition, statement); + + /* Parse the body of the switch-statement. */ + in_switch_statement_p = parser->in_switch_statement_p; + parser->in_switch_statement_p = true; + body = cp_parser_implicitly_scoped_statement (parser); + parser->in_switch_statement_p = in_switch_statement_p; + + /* Now we're all done with the switch-statement. */ + finish_switch_stmt (statement); + } + + return statement; + } + break; + + default: + cp_parser_error (parser, "expected selection-statement"); + return error_mark_node; + } +} + +/* Parse a condition. + + condition: + expression + type-specifier-seq declarator = assignment-expression + + GNU Extension: + + condition: + type-specifier-seq declarator asm-specification [opt] + attributes [opt] = assignment-expression + + Returns the expression that should be tested. */ + +static tree +cp_parser_condition (cp_parser* parser) +{ + tree type_specifiers; + const char *saved_message; + + /* Try the declaration first. */ + cp_parser_parse_tentatively (parser); + /* New types are not allowed in the type-specifier-seq for a + condition. */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = "types may not be defined in conditions"; + /* Parse the type-specifier-seq. */ + type_specifiers = cp_parser_type_specifier_seq (parser); + /* Restore the saved message. */ + parser->type_definition_forbidden_message = saved_message; + /* If all is well, we might be looking at a declaration. */ + if (!cp_parser_error_occurred (parser)) + { + tree decl; + tree asm_specification; + tree attributes; + tree declarator; + tree initializer = NULL_TREE; + + /* Parse the declarator. */ + declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + /*ctor_dtor_or_conv_p=*/NULL, + /*parenthesized_p=*/NULL); + /* Parse the attributes. */ + attributes = cp_parser_attributes_opt (parser); + /* Parse the asm-specification. */ + asm_specification = cp_parser_asm_specification_opt (parser); + /* If the next token is not an `=', then we might still be + looking at an expression. For example: + + if (A(a).x) + + looks like a decl-specifier-seq and a declarator -- but then + there is no `=', so this is an expression. */ + cp_parser_require (parser, CPP_EQ, "`='"); + /* If we did see an `=', then we are looking at a declaration + for sure. */ + if (cp_parser_parse_definitely (parser)) + { + /* Create the declaration. */ + decl = start_decl (declarator, type_specifiers, + /*initialized_p=*/true, + attributes, /*prefix_attributes=*/NULL_TREE); + /* Parse the assignment-expression. */ + initializer = cp_parser_assignment_expression (parser); + + /* Process the initializer. */ + cp_finish_decl (decl, + initializer, + asm_specification, + LOOKUP_ONLYCONVERTING); + + return convert_from_reference (decl); + } + } + /* If we didn't even get past the declarator successfully, we are + definitely not looking at a declaration. */ + else + cp_parser_abort_tentative_parse (parser); + + /* Otherwise, we are looking at an expression. */ + return cp_parser_expression (parser); +} + +/* Parse an iteration-statement. + + iteration-statement: + while ( condition ) statement + do statement while ( expression ) ; + for ( for-init-statement condition [opt] ; expression [opt] ) + statement + + Returns the new WHILE_STMT, DO_STMT, or FOR_STMT. */ + +static tree +cp_parser_iteration_statement (cp_parser* parser) +{ + cp_token *token; + enum rid keyword; + tree statement; + bool in_iteration_statement_p; + + + /* Peek at the next token. */ + token = cp_parser_require (parser, CPP_KEYWORD, "iteration-statement"); + if (!token) + return error_mark_node; + + /* Remember whether or not we are already within an iteration + statement. */ + in_iteration_statement_p = parser->in_iteration_statement_p; + + /* See what kind of keyword it is. */ + keyword = token->keyword; + switch (keyword) + { + case RID_WHILE: + { + tree condition; + + /* Begin the while-statement. */ + statement = begin_while_stmt (); + /* Look for the `('. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + /* Parse the condition. */ + condition = cp_parser_condition (parser); + finish_while_stmt_cond (condition, statement); + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* Parse the dependent statement. */ + parser->in_iteration_statement_p = true; + cp_parser_already_scoped_statement (parser); + parser->in_iteration_statement_p = in_iteration_statement_p; + /* We're done with the while-statement. */ + finish_while_stmt (statement); + } + break; + + case RID_DO: + { + tree expression; + + /* Begin the do-statement. */ + statement = begin_do_stmt (); + /* Parse the body of the do-statement. */ + parser->in_iteration_statement_p = true; + cp_parser_implicitly_scoped_statement (parser); + parser->in_iteration_statement_p = in_iteration_statement_p; + finish_do_body (statement); + /* Look for the `while' keyword. */ + cp_parser_require_keyword (parser, RID_WHILE, "`while'"); + /* Look for the `('. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + /* Parse the expression. */ + expression = cp_parser_expression (parser); + /* We're done with the do-statement. */ + finish_do_stmt (expression, statement); + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* Look for the `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + } + break; + + case RID_FOR: + { + tree condition = NULL_TREE; + tree expression = NULL_TREE; + + /* Begin the for-statement. */ + statement = begin_for_stmt (); + /* Look for the `('. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + /* Parse the initialization. */ + cp_parser_for_init_statement (parser); + finish_for_init_stmt (statement); + + /* If there's a condition, process it. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + condition = cp_parser_condition (parser); + finish_for_cond (condition, statement); + /* Look for the `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + + /* If there's an expression, process it. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) + expression = cp_parser_expression (parser); + finish_for_expr (expression, statement); + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + + /* Parse the body of the for-statement. */ + parser->in_iteration_statement_p = true; + cp_parser_already_scoped_statement (parser); + parser->in_iteration_statement_p = in_iteration_statement_p; + + /* We're done with the for-statement. */ + finish_for_stmt (statement); + } + break; + + default: + cp_parser_error (parser, "expected iteration-statement"); + statement = error_mark_node; + break; + } + + return statement; +} + +/* Parse a for-init-statement. + + for-init-statement: + expression-statement + simple-declaration */ + +static void +cp_parser_for_init_statement (cp_parser* parser) +{ + /* If the next token is a `;', then we have an empty + expression-statement. Grammatically, this is also a + simple-declaration, but an invalid one, because it does not + declare anything. Therefore, if we did not handle this case + specially, we would issue an error message about an invalid + declaration. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + { + /* We're going to speculatively look for a declaration, falling back + to an expression, if necessary. */ + cp_parser_parse_tentatively (parser); + /* Parse the declaration. */ + cp_parser_simple_declaration (parser, + /*function_definition_allowed_p=*/false); + /* If the tentative parse failed, then we shall need to look for an + expression-statement. */ + if (cp_parser_parse_definitely (parser)) + return; + } + + cp_parser_expression_statement (parser, false); +} + +/* Parse a jump-statement. + + jump-statement: + break ; + continue ; + return expression [opt] ; + goto identifier ; + + GNU extension: + + jump-statement: + goto * expression ; + + Returns the new BREAK_STMT, CONTINUE_STMT, RETURN_STMT, or + GOTO_STMT. */ + +static tree +cp_parser_jump_statement (cp_parser* parser) +{ + tree statement = error_mark_node; + cp_token *token; + enum rid keyword; + + /* Peek at the next token. */ + token = cp_parser_require (parser, CPP_KEYWORD, "jump-statement"); + if (!token) + return error_mark_node; + + /* See what kind of keyword it is. */ + keyword = token->keyword; + switch (keyword) + { + case RID_BREAK: + if (!parser->in_switch_statement_p + && !parser->in_iteration_statement_p) + { + error ("break statement not within loop or switch"); + statement = error_mark_node; + } + else + statement = finish_break_stmt (); + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + break; + + case RID_CONTINUE: + if (!parser->in_iteration_statement_p) + { + error ("continue statement not within a loop"); + statement = error_mark_node; + } + else + statement = finish_continue_stmt (); + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + break; + + case RID_RETURN: + { + tree expr; + + /* If the next token is a `;', then there is no + expression. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + expr = cp_parser_expression (parser); + else + expr = NULL_TREE; + /* Build the return-statement. */ + statement = finish_return_stmt (expr); + /* Look for the final `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + } + break; + + case RID_GOTO: + /* Create the goto-statement. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_MULT)) + { + /* Issue a warning about this use of a GNU extension. */ + if (pedantic) + pedwarn ("ISO C++ forbids computed gotos"); + /* Consume the '*' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the dependent expression. */ + finish_goto_stmt (cp_parser_expression (parser)); + } + else + finish_goto_stmt (cp_parser_identifier (parser)); + /* Look for the final `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + break; + + default: + cp_parser_error (parser, "expected jump-statement"); + break; + } + + return statement; +} + +/* Parse a declaration-statement. + + declaration-statement: + block-declaration */ + +static void +cp_parser_declaration_statement (cp_parser* parser) +{ + /* Parse the block-declaration. */ + cp_parser_block_declaration (parser, /*statement_p=*/true); + + /* Finish off the statement. */ + finish_stmt (); +} + +/* Some dependent statements (like `if (cond) statement'), are + implicitly in their own scope. In other words, if the statement is + a single statement (as opposed to a compound-statement), it is + none-the-less treated as if it were enclosed in braces. Any + declarations appearing in the dependent statement are out of scope + after control passes that point. This function parses a statement, + but ensures that is in its own scope, even if it is not a + compound-statement. + + Returns the new statement. */ + +static tree +cp_parser_implicitly_scoped_statement (cp_parser* parser) +{ + tree statement; + + /* If the token is not a `{', then we must take special action. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) + { + /* Create a compound-statement. */ + statement = begin_compound_stmt (/*has_no_scope=*/false); + /* Parse the dependent-statement. */ + cp_parser_statement (parser, false); + /* Finish the dummy compound-statement. */ + finish_compound_stmt (statement); + } + /* Otherwise, we simply parse the statement directly. */ + else + statement = cp_parser_compound_statement (parser, false); + + /* Return the statement. */ + return statement; +} + +/* For some dependent statements (like `while (cond) statement'), we + have already created a scope. Therefore, even if the dependent + statement is a compound-statement, we do not want to create another + scope. */ + +static void +cp_parser_already_scoped_statement (cp_parser* parser) +{ + /* If the token is not a `{', then we must take special action. */ + if (cp_lexer_next_token_is_not(parser->lexer, CPP_OPEN_BRACE)) + { + tree statement; + + /* Create a compound-statement. */ + statement = begin_compound_stmt (/*has_no_scope=*/true); + /* Parse the dependent-statement. */ + cp_parser_statement (parser, false); + /* Finish the dummy compound-statement. */ + finish_compound_stmt (statement); + } + /* Otherwise, we simply parse the statement directly. */ + else + cp_parser_statement (parser, false); +} + +/* Declarations [gram.dcl.dcl] */ + +/* Parse an optional declaration-sequence. + + declaration-seq: + declaration + declaration-seq declaration */ + +static void +cp_parser_declaration_seq_opt (cp_parser* parser) +{ + while (true) + { + cp_token *token; + + token = cp_lexer_peek_token (parser->lexer); + + if (token->type == CPP_CLOSE_BRACE + || token->type == CPP_EOF) + break; + + if (token->type == CPP_SEMICOLON) + { + /* A declaration consisting of a single semicolon is + invalid. Allow it unless we're being pedantic. */ + if (pedantic && !in_system_header) + pedwarn ("extra `;'"); + cp_lexer_consume_token (parser->lexer); + continue; + } + + /* The C lexer modifies PENDING_LANG_CHANGE when it wants the + parser to enter or exit implicit `extern "C"' blocks. */ + while (pending_lang_change > 0) + { + push_lang_context (lang_name_c); + --pending_lang_change; + } + while (pending_lang_change < 0) + { + pop_lang_context (); + ++pending_lang_change; + } + + /* Parse the declaration itself. */ + cp_parser_declaration (parser); + } +} + +/* Parse a declaration. + + declaration: + block-declaration + function-definition + template-declaration + explicit-instantiation + explicit-specialization + linkage-specification + namespace-definition + + GNU extension: + + declaration: + __extension__ declaration */ + +static void +cp_parser_declaration (cp_parser* parser) +{ + cp_token token1; + cp_token token2; + int saved_pedantic; + + /* Check for the `__extension__' keyword. */ + if (cp_parser_extension_opt (parser, &saved_pedantic)) + { + /* Parse the qualified declaration. */ + cp_parser_declaration (parser); + /* Restore the PEDANTIC flag. */ + pedantic = saved_pedantic; + + return; + } + + /* Try to figure out what kind of declaration is present. */ + token1 = *cp_lexer_peek_token (parser->lexer); + if (token1.type != CPP_EOF) + token2 = *cp_lexer_peek_nth_token (parser->lexer, 2); + + /* If the next token is `extern' and the following token is a string + literal, then we have a linkage specification. */ + if (token1.keyword == RID_EXTERN + && cp_parser_is_string_literal (&token2)) + cp_parser_linkage_specification (parser); + /* If the next token is `template', then we have either a template + declaration, an explicit instantiation, or an explicit + specialization. */ + else if (token1.keyword == RID_TEMPLATE) + { + /* `template <>' indicates a template specialization. */ + if (token2.type == CPP_LESS + && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER) + cp_parser_explicit_specialization (parser); + /* `template <' indicates a template declaration. */ + else if (token2.type == CPP_LESS) + cp_parser_template_declaration (parser, /*member_p=*/false); + /* Anything else must be an explicit instantiation. */ + else + cp_parser_explicit_instantiation (parser); + } + /* If the next token is `export', then we have a template + declaration. */ + else if (token1.keyword == RID_EXPORT) + cp_parser_template_declaration (parser, /*member_p=*/false); + /* If the next token is `extern', 'static' or 'inline' and the one + after that is `template', we have a GNU extended explicit + instantiation directive. */ + else if (cp_parser_allow_gnu_extensions_p (parser) + && (token1.keyword == RID_EXTERN + || token1.keyword == RID_STATIC + || token1.keyword == RID_INLINE) + && token2.keyword == RID_TEMPLATE) + cp_parser_explicit_instantiation (parser); + /* If the next token is `namespace', check for a named or unnamed + namespace definition. */ + else if (token1.keyword == RID_NAMESPACE + && (/* A named namespace definition. */ + (token2.type == CPP_NAME + && (cp_lexer_peek_nth_token (parser->lexer, 3)->type + == CPP_OPEN_BRACE)) + /* An unnamed namespace definition. */ + || token2.type == CPP_OPEN_BRACE)) + cp_parser_namespace_definition (parser); + /* We must have either a block declaration or a function + definition. */ + else + /* Try to parse a block-declaration, or a function-definition. */ + cp_parser_block_declaration (parser, /*statement_p=*/false); +} + +/* Parse a block-declaration. + + block-declaration: + simple-declaration + asm-definition + namespace-alias-definition + using-declaration + using-directive + + GNU Extension: + + block-declaration: + __extension__ block-declaration + label-declaration + + If STATEMENT_P is TRUE, then this block-declaration is occurring as + part of a declaration-statement. */ + +static void +cp_parser_block_declaration (cp_parser *parser, + bool statement_p) +{ + cp_token *token1; + int saved_pedantic; + + /* Check for the `__extension__' keyword. */ + if (cp_parser_extension_opt (parser, &saved_pedantic)) + { + /* Parse the qualified declaration. */ + cp_parser_block_declaration (parser, statement_p); + /* Restore the PEDANTIC flag. */ + pedantic = saved_pedantic; + + return; + } + + /* Peek at the next token to figure out which kind of declaration is + present. */ + token1 = cp_lexer_peek_token (parser->lexer); + + /* If the next keyword is `asm', we have an asm-definition. */ + if (token1->keyword == RID_ASM) + { + if (statement_p) + cp_parser_commit_to_tentative_parse (parser); + cp_parser_asm_definition (parser); + } + /* If the next keyword is `namespace', we have a + namespace-alias-definition. */ + else if (token1->keyword == RID_NAMESPACE) + cp_parser_namespace_alias_definition (parser); + /* If the next keyword is `using', we have either a + using-declaration or a using-directive. */ + else if (token1->keyword == RID_USING) + { + cp_token *token2; + + if (statement_p) + cp_parser_commit_to_tentative_parse (parser); + /* If the token after `using' is `namespace', then we have a + using-directive. */ + token2 = cp_lexer_peek_nth_token (parser->lexer, 2); + if (token2->keyword == RID_NAMESPACE) + cp_parser_using_directive (parser); + /* Otherwise, it's a using-declaration. */ + else + cp_parser_using_declaration (parser); + } + /* If the next keyword is `__label__' we have a label declaration. */ + else if (token1->keyword == RID_LABEL) + { + if (statement_p) + cp_parser_commit_to_tentative_parse (parser); + cp_parser_label_declaration (parser); + } + /* Anything else must be a simple-declaration. */ + else + cp_parser_simple_declaration (parser, !statement_p); +} + +/* Parse a simple-declaration. + + simple-declaration: + decl-specifier-seq [opt] init-declarator-list [opt] ; + + init-declarator-list: + init-declarator + init-declarator-list , init-declarator + + If FUNCTION_DEFINITION_ALLOWED_P is TRUE, then we also recognize a + function-definition as a simple-declaration. */ + +static void +cp_parser_simple_declaration (cp_parser* parser, + bool function_definition_allowed_p) +{ + tree decl_specifiers; + tree attributes; + int declares_class_or_enum; + bool saw_declarator; + + /* Defer access checks until we know what is being declared; the + checks for names appearing in the decl-specifier-seq should be + done as if we were in the scope of the thing being declared. */ + push_deferring_access_checks (dk_deferred); + + /* Parse the decl-specifier-seq. We have to keep track of whether + or not the decl-specifier-seq declares a named class or + enumeration type, since that is the only case in which the + init-declarator-list is allowed to be empty. + + [dcl.dcl] + + In a simple-declaration, the optional init-declarator-list can be + omitted only when declaring a class or enumeration, that is when + the decl-specifier-seq contains either a class-specifier, an + elaborated-type-specifier, or an enum-specifier. */ + decl_specifiers + = cp_parser_decl_specifier_seq (parser, + CP_PARSER_FLAGS_OPTIONAL, + &attributes, + &declares_class_or_enum); + /* We no longer need to defer access checks. */ + stop_deferring_access_checks (); + + /* In a block scope, a valid declaration must always have a + decl-specifier-seq. By not trying to parse declarators, we can + resolve the declaration/expression ambiguity more quickly. */ + if (!function_definition_allowed_p && !decl_specifiers) + { + cp_parser_error (parser, "expected declaration"); + goto done; + } + + /* 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_parser_diagnose_invalid_type_name (parser)) + { + /* If parsing tentatively, we should commit; we really are + looking at a declaration. */ + cp_parser_commit_to_tentative_parse (parser); + /* Give up. */ + goto done; + } + + /* Keep going until we hit the `;' at the end of the simple + declaration. */ + saw_declarator = false; + while (cp_lexer_next_token_is_not (parser->lexer, + CPP_SEMICOLON)) + { + cp_token *token; + bool function_definition_p; + tree decl; + + saw_declarator = true; + /* Parse the init-declarator. */ + decl = cp_parser_init_declarator (parser, decl_specifiers, attributes, + function_definition_allowed_p, + /*member_p=*/false, + declares_class_or_enum, + &function_definition_p); + /* If an error occurred while parsing tentatively, exit quickly. + (That usually happens when in the body of a function; each + statement is treated as a declaration-statement until proven + otherwise.) */ + if (cp_parser_error_occurred (parser)) + goto done; + /* Handle function definitions specially. */ + if (function_definition_p) + { + /* If the next token is a `,', then we are probably + processing something like: + + void f() {}, *p; + + which is erroneous. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + error ("mixing declarations and function-definitions is forbidden"); + /* Otherwise, we're done with the list of declarators. */ + else + { + pop_deferring_access_checks (); + return; + } + } + /* The next token should be either a `,' or a `;'. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's a `,', there are more declarators to come. */ + if (token->type == CPP_COMMA) + cp_lexer_consume_token (parser->lexer); + /* If it's a `;', we are done. */ + else if (token->type == CPP_SEMICOLON) + break; + /* Anything else is an error. */ + else + { + cp_parser_error (parser, "expected `,' or `;'"); + /* Skip tokens until we reach 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); + goto done; + } + /* After the first time around, a function-definition is not + allowed -- even if it was OK at first. For example: + + int i, f() {} + + is not valid. */ + function_definition_allowed_p = false; + } + + /* Issue an error message if no declarators are present, and the + decl-specifier-seq does not itself declare a class or + enumeration. */ + if (!saw_declarator) + { + if (cp_parser_declares_only_class_p (parser)) + shadow_tag (decl_specifiers); + /* Perform any deferred access checks. */ + perform_deferred_access_checks (); + } + + /* Consume the `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + + done: + pop_deferring_access_checks (); +} + +/* Parse a decl-specifier-seq. + + decl-specifier-seq: + decl-specifier-seq [opt] decl-specifier + + decl-specifier: + storage-class-specifier + type-specifier + function-specifier + friend + typedef + + GNU Extension: + + decl-specifier: + attributes + + Returns a TREE_LIST, giving the decl-specifiers in the order they + appear in the source code. The TREE_VALUE of each node is the + decl-specifier. For a keyword (such as `auto' or `friend'), the + TREE_VALUE is simply the corresponding TREE_IDENTIFIER. For the + representation of a type-specifier, see cp_parser_type_specifier. + + If there are attributes, they will be stored in *ATTRIBUTES, + represented as described above cp_parser_attributes. + + If FRIEND_IS_NOT_CLASS_P is non-NULL, and the `friend' specifier + appears, and the entity that will be a friend is not going to be a + class, then *FRIEND_IS_NOT_CLASS_P will be set to TRUE. Note that + even if *FRIEND_IS_NOT_CLASS_P is FALSE, the entity to which + friendship is granted might not be a class. + + *DECLARES_CLASS_OR_ENUM is set to the bitwise or of the following + flags: + + 1: one of the decl-specifiers is an elaborated-type-specifier + (i.e., a type declaration) + 2: one of the decl-specifiers is an enum-specifier or a + class-specifier (i.e., a type definition) + + */ + +static tree +cp_parser_decl_specifier_seq (cp_parser* parser, + cp_parser_flags flags, + tree* attributes, + int* declares_class_or_enum) +{ + tree decl_specs = NULL_TREE; + bool friend_p = false; + bool constructor_possible_p = !parser->in_declarator_p; + + /* Assume no class or enumeration type is declared. */ + *declares_class_or_enum = 0; + + /* Assume there are no attributes. */ + *attributes = NULL_TREE; + + /* Keep reading specifiers until there are no more to read. */ + while (true) + { + tree decl_spec = NULL_TREE; + bool constructor_p; + cp_token *token; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* Handle attributes. */ + if (token->keyword == RID_ATTRIBUTE) + { + /* Parse the attributes. */ + decl_spec = cp_parser_attributes_opt (parser); + /* Add them to the list. */ + *attributes = chainon (*attributes, decl_spec); + continue; + } + /* If the next token is an appropriate keyword, we can simply + add it to the list. */ + switch (token->keyword) + { + case RID_FRIEND: + /* decl-specifier: + friend */ + if (friend_p) + error ("duplicate `friend'"); + else + friend_p = true; + /* The representation of the specifier is simply the + appropriate TREE_IDENTIFIER node. */ + decl_spec = token->value; + /* Consume the token. */ + cp_lexer_consume_token (parser->lexer); + break; + + /* function-specifier: + inline + virtual + explicit */ + case RID_INLINE: + case RID_VIRTUAL: + case RID_EXPLICIT: + decl_spec = cp_parser_function_specifier_opt (parser); + break; + + /* decl-specifier: + typedef */ + case RID_TYPEDEF: + /* The representation of the specifier is simply the + appropriate TREE_IDENTIFIER node. */ + decl_spec = token->value; + /* Consume the token. */ + cp_lexer_consume_token (parser->lexer); + /* A constructor declarator cannot appear in a typedef. */ + constructor_possible_p = false; + /* The "typedef" keyword can only occur in a declaration; we + may as well commit at this point. */ + cp_parser_commit_to_tentative_parse (parser); + break; + + /* storage-class-specifier: + auto + register + static + extern + mutable + + GNU Extension: + thread */ + case RID_AUTO: + case RID_REGISTER: + case RID_STATIC: + case RID_EXTERN: + case RID_MUTABLE: + case RID_THREAD: + decl_spec = cp_parser_storage_class_specifier_opt (parser); + break; + + default: + break; + } + + /* Constructors are a special case. The `S' in `S()' is not a + decl-specifier; it is the beginning of the declarator. */ + constructor_p = (!decl_spec + && constructor_possible_p + && cp_parser_constructor_declarator_p (parser, + friend_p)); + + /* If we don't have a DECL_SPEC yet, then we must be looking at + a type-specifier. */ + if (!decl_spec && !constructor_p) + { + int decl_spec_declares_class_or_enum; + bool is_cv_qualifier; + + decl_spec + = cp_parser_type_specifier (parser, flags, + friend_p, + /*is_declaration=*/true, + &decl_spec_declares_class_or_enum, + &is_cv_qualifier); + + *declares_class_or_enum |= decl_spec_declares_class_or_enum; + + /* If this type-specifier referenced a user-defined type + (a typedef, class-name, etc.), then we can't allow any + more such type-specifiers henceforth. + + [dcl.spec] + + The longest sequence of decl-specifiers that could + possibly be a type name is taken as the + decl-specifier-seq of a declaration. The sequence shall + be self-consistent as described below. + + [dcl.type] + + As a general rule, at most one type-specifier is allowed + in the complete decl-specifier-seq of a declaration. The + only exceptions are the following: + + -- const or volatile can be combined with any other + type-specifier. + + -- signed or unsigned can be combined with char, long, + short, or int. + + -- .. + + Example: + + typedef char* Pc; + void g (const int Pc); + + Here, Pc is *not* part of the decl-specifier seq; it's + the declarator. Therefore, once we see a type-specifier + (other than a cv-qualifier), we forbid any additional + user-defined types. We *do* still allow things like `int + int' to be considered a decl-specifier-seq, and issue the + error message later. */ + if (decl_spec && !is_cv_qualifier) + flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES; + /* A constructor declarator cannot follow a type-specifier. */ + if (decl_spec) + constructor_possible_p = false; + } + + /* If we still do not have a DECL_SPEC, then there are no more + decl-specifiers. */ + if (!decl_spec) + { + /* Issue an error message, unless the entire construct was + optional. */ + if (!(flags & CP_PARSER_FLAGS_OPTIONAL)) + { + cp_parser_error (parser, "expected decl specifier"); + return error_mark_node; + } + + break; + } + + /* Add the DECL_SPEC to the list of specifiers. */ + if (decl_specs == NULL || TREE_VALUE (decl_specs) != error_mark_node) + decl_specs = tree_cons (NULL_TREE, decl_spec, decl_specs); + + /* After we see one decl-specifier, further decl-specifiers are + always optional. */ + flags |= CP_PARSER_FLAGS_OPTIONAL; + } + + /* Don't allow a friend specifier with a class definition. */ + if (friend_p && (*declares_class_or_enum & 2)) + error ("class definition may not be declared a friend"); + + /* We have built up the DECL_SPECS in reverse order. Return them in + the correct order. */ + return nreverse (decl_specs); +} + +/* Parse an (optional) storage-class-specifier. + + storage-class-specifier: + auto + register + static + extern + mutable + + GNU Extension: + + storage-class-specifier: + thread + + Returns an IDENTIFIER_NODE corresponding to the keyword used. */ + +static tree +cp_parser_storage_class_specifier_opt (cp_parser* parser) +{ + switch (cp_lexer_peek_token (parser->lexer)->keyword) + { + case RID_AUTO: + case RID_REGISTER: + case RID_STATIC: + case RID_EXTERN: + case RID_MUTABLE: + case RID_THREAD: + /* Consume the token. */ + return cp_lexer_consume_token (parser->lexer)->value; + + default: + return NULL_TREE; + } +} + +/* Parse an (optional) function-specifier. + + function-specifier: + inline + virtual + explicit + + Returns an IDENTIFIER_NODE corresponding to the keyword used. */ + +static tree +cp_parser_function_specifier_opt (cp_parser* parser) +{ + switch (cp_lexer_peek_token (parser->lexer)->keyword) + { + case RID_INLINE: + case RID_VIRTUAL: + case RID_EXPLICIT: + /* Consume the token. */ + return cp_lexer_consume_token (parser->lexer)->value; + + default: + return NULL_TREE; + } +} + +/* Parse a linkage-specification. + + linkage-specification: + extern string-literal { declaration-seq [opt] } + extern string-literal declaration */ + +static void +cp_parser_linkage_specification (cp_parser* parser) +{ + cp_token *token; + tree linkage; + + /* Look for the `extern' keyword. */ + cp_parser_require_keyword (parser, RID_EXTERN, "`extern'"); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not a string-literal, then there's a problem. */ + if (!cp_parser_is_string_literal (token)) + { + cp_parser_error (parser, "expected language-name"); + return; + } + /* Consume the token. */ + cp_lexer_consume_token (parser->lexer); + + /* Transform the literal into an identifier. If the literal is a + wide-character string, or contains embedded NULs, then we can't + handle it as the user wants. */ + if (token->type == CPP_WSTRING + || (strlen (TREE_STRING_POINTER (token->value)) + != (size_t) (TREE_STRING_LENGTH (token->value) - 1))) + { + cp_parser_error (parser, "invalid linkage-specification"); + /* Assume C++ linkage. */ + linkage = get_identifier ("c++"); + } + /* If it's a simple string constant, things are easier. */ + else + linkage = get_identifier (TREE_STRING_POINTER (token->value)); + + /* We're now using the new linkage. */ + push_lang_context (linkage); + + /* If the next token is a `{', then we're using the first + production. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + /* Consume the `{' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the declarations. */ + cp_parser_declaration_seq_opt (parser); + /* Look for the closing `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); + } + /* Otherwise, there's just one declaration. */ + else + { + bool saved_in_unbraced_linkage_specification_p; + + saved_in_unbraced_linkage_specification_p + = parser->in_unbraced_linkage_specification_p; + parser->in_unbraced_linkage_specification_p = true; + have_extern_spec = true; + cp_parser_declaration (parser); + have_extern_spec = false; + parser->in_unbraced_linkage_specification_p + = saved_in_unbraced_linkage_specification_p; + } + + /* We're done with the linkage-specification. */ + pop_lang_context (); +} + +/* Special member functions [gram.special] */ + +/* Parse a conversion-function-id. + + conversion-function-id: + operator conversion-type-id + + Returns an IDENTIFIER_NODE representing the operator. */ + +static tree +cp_parser_conversion_function_id (cp_parser* parser) +{ + tree type; + tree saved_scope; + tree saved_qualifying_scope; + tree saved_object_scope; + bool pop_p = false; + + /* Look for the `operator' token. */ + if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'")) + return error_mark_node; + /* When we parse the conversion-type-id, the current scope will be + reset. However, we need that information in able to look up the + conversion function later, so we save it here. */ + saved_scope = parser->scope; + saved_qualifying_scope = parser->qualifying_scope; + saved_object_scope = parser->object_scope; + /* We must enter the scope of the class so that the names of + entities declared within the class are available in the + conversion-type-id. For example, consider: + + struct S { + typedef int I; + operator I(); + }; + + S::operator I() { ... } + + In order to see that `I' is a type-name in the definition, we + must be in the scope of `S'. */ + if (saved_scope) + pop_p = push_scope (saved_scope); + /* Parse the conversion-type-id. */ + type = cp_parser_conversion_type_id (parser); + /* Leave the scope of the class, if any. */ + if (pop_p) + pop_scope (saved_scope); + /* Restore the saved scope. */ + parser->scope = saved_scope; + parser->qualifying_scope = saved_qualifying_scope; + parser->object_scope = saved_object_scope; + /* If the TYPE is invalid, indicate failure. */ + if (type == error_mark_node) + return error_mark_node; + return mangle_conv_op_name_for_type (type); +} + +/* Parse a conversion-type-id: + + conversion-type-id: + type-specifier-seq conversion-declarator [opt] + + Returns the TYPE specified. */ + +static tree +cp_parser_conversion_type_id (cp_parser* parser) +{ + tree attributes; + tree type_specifiers; + tree declarator; + + /* Parse the attributes. */ + attributes = cp_parser_attributes_opt (parser); + /* Parse the type-specifiers. */ + type_specifiers = cp_parser_type_specifier_seq (parser); + /* If that didn't work, stop. */ + if (type_specifiers == error_mark_node) + return error_mark_node; + /* Parse the conversion-declarator. */ + declarator = cp_parser_conversion_declarator_opt (parser); + + return grokdeclarator (declarator, type_specifiers, TYPENAME, + /*initialized=*/0, &attributes); +} + +/* Parse an (optional) conversion-declarator. + + conversion-declarator: + ptr-operator conversion-declarator [opt] + + Returns a representation of the declarator. See + cp_parser_declarator for details. */ + +static tree +cp_parser_conversion_declarator_opt (cp_parser* parser) +{ + enum tree_code code; + tree class_type; + tree cv_qualifier_seq; + + /* We don't know if there's a ptr-operator next, or not. */ + cp_parser_parse_tentatively (parser); + /* Try the ptr-operator. */ + code = cp_parser_ptr_operator (parser, &class_type, + &cv_qualifier_seq); + /* If it worked, look for more conversion-declarators. */ + if (cp_parser_parse_definitely (parser)) + { + tree declarator; + + /* Parse another optional declarator. */ + declarator = cp_parser_conversion_declarator_opt (parser); + + /* Create the representation of the declarator. */ + if (code == INDIRECT_REF) + declarator = make_pointer_declarator (cv_qualifier_seq, + declarator); + else + declarator = make_reference_declarator (cv_qualifier_seq, + declarator); + + /* Handle the pointer-to-member case. */ + if (class_type) + declarator = build_nt (SCOPE_REF, class_type, declarator); + + return declarator; + } + + return NULL_TREE; +} + +/* Parse an (optional) ctor-initializer. + + ctor-initializer: + : mem-initializer-list + + Returns TRUE iff the ctor-initializer was actually present. */ + +static bool +cp_parser_ctor_initializer_opt (cp_parser* parser) +{ + /* If the next token is not a `:', then there is no + ctor-initializer. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) + { + /* Do default initialization of any bases and members. */ + if (DECL_CONSTRUCTOR_P (current_function_decl)) + finish_mem_initializers (NULL_TREE); + + return false; + } + + /* Consume the `:' token. */ + cp_lexer_consume_token (parser->lexer); + /* And the mem-initializer-list. */ + cp_parser_mem_initializer_list (parser); + + return true; +} + +/* Parse a mem-initializer-list. + + mem-initializer-list: + mem-initializer + mem-initializer , mem-initializer-list */ + +static void +cp_parser_mem_initializer_list (cp_parser* parser) +{ + tree mem_initializer_list = NULL_TREE; + + /* Let the semantic analysis code know that we are starting the + mem-initializer-list. */ + if (!DECL_CONSTRUCTOR_P (current_function_decl)) + error ("only constructors take base initializers"); + + /* Loop through the list. */ + while (true) + { + tree mem_initializer; + + /* Parse the mem-initializer. */ + mem_initializer = cp_parser_mem_initializer (parser); + /* Add it to the list, unless it was erroneous. */ + if (mem_initializer) + { + TREE_CHAIN (mem_initializer) = mem_initializer_list; + mem_initializer_list = mem_initializer; + } + /* If the next token is not a `,', we're done. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + /* Consume the `,' token. */ + cp_lexer_consume_token (parser->lexer); + } + + /* Perform semantic analysis. */ + if (DECL_CONSTRUCTOR_P (current_function_decl)) + finish_mem_initializers (mem_initializer_list); +} + +/* Parse a mem-initializer. + + mem-initializer: + mem-initializer-id ( expression-list [opt] ) + + GNU extension: + + mem-initializer: + ( expression-list [opt] ) + + Returns a TREE_LIST. The TREE_PURPOSE is the TYPE (for a base + class) or FIELD_DECL (for a non-static data member) to initialize; + the TREE_VALUE is the expression-list. */ + +static tree +cp_parser_mem_initializer (cp_parser* parser) +{ + tree mem_initializer_id; + tree expression_list; + tree member; + + /* Find out what is being initialized. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + pedwarn ("anachronistic old-style base class initializer"); + mem_initializer_id = NULL_TREE; + } + else + mem_initializer_id = cp_parser_mem_initializer_id (parser); + member = expand_member_init (mem_initializer_id); + if (member && !DECL_P (member)) + in_base_initializer = 1; + + expression_list + = cp_parser_parenthesized_expression_list (parser, false, + /*non_constant_p=*/NULL); + if (!expression_list) + expression_list = void_type_node; + + in_base_initializer = 0; + + return member ? build_tree_list (member, expression_list) : NULL_TREE; +} + +/* Parse a mem-initializer-id. + + mem-initializer-id: + :: [opt] nested-name-specifier [opt] class-name + identifier + + Returns a TYPE indicating the class to be initializer for the first + production. Returns an IDENTIFIER_NODE indicating the data member + to be initialized for the second production. */ + +static tree +cp_parser_mem_initializer_id (cp_parser* parser) +{ + bool global_scope_p; + bool nested_name_specifier_p; + bool template_p = false; + tree id; + + /* `typename' is not allowed in this context ([temp.res]). */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME)) + { + error ("keyword `typename' not allowed in this context (a qualified " + "member initializer is implicitly a type)"); + cp_lexer_consume_token (parser->lexer); + } + /* 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. The simplest way to + implement: + + [temp.res] + + The keyword `typename' is not permitted in a base-specifier or + mem-initializer; in these contexts a qualified name that + depends on a template-parameter is implicitly assumed to be a + type name. + + is to assume that we have seen the `typename' keyword at this + point. */ + nested_name_specifier_p + = (cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/true, + /*check_dependency_p=*/true, + /*type_p=*/true, + /*is_declaration=*/true) + != NULL_TREE); + if (nested_name_specifier_p) + template_p = cp_parser_optional_template_keyword (parser); + /* If there is a `::' operator or a nested-name-specifier, then we + are definitely looking for a class-name. */ + if (global_scope_p || nested_name_specifier_p) + return cp_parser_class_name (parser, + /*typename_keyword_p=*/true, + /*template_keyword_p=*/template_p, + /*type_p=*/false, + /*check_dependency_p=*/true, + /*class_head_p=*/false, + /*is_declaration=*/true); + /* Otherwise, we could also be looking for an ordinary identifier. */ + cp_parser_parse_tentatively (parser); + /* Try a class-name. */ + id = cp_parser_class_name (parser, + /*typename_keyword_p=*/true, + /*template_keyword_p=*/false, + /*type_p=*/false, + /*check_dependency_p=*/true, + /*class_head_p=*/false, + /*is_declaration=*/true); + /* If we found one, we're done. */ + if (cp_parser_parse_definitely (parser)) + return id; + /* Otherwise, look for an ordinary identifier. */ + return cp_parser_identifier (parser); +} + +/* Overloading [gram.over] */ + +/* Parse an operator-function-id. + + operator-function-id: + operator operator + + Returns an IDENTIFIER_NODE for the operator which is a + human-readable spelling of the identifier, e.g., `operator +'. */ + +static tree +cp_parser_operator_function_id (cp_parser* parser) +{ + /* Look for the `operator' keyword. */ + if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'")) + return error_mark_node; + /* And then the name of the operator itself. */ + return cp_parser_operator (parser); +} + +/* Parse an operator. + + operator: + new delete new[] delete[] + - * / % ^ & | ~ ! = < > + += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && + || ++ -- , ->* -> () [] + + GNU Extensions: + + operator: + <? >? <?= >?= + + Returns an IDENTIFIER_NODE for the operator which is a + human-readable spelling of the identifier, e.g., `operator +'. */ + +static tree +cp_parser_operator (cp_parser* parser) +{ + tree id = NULL_TREE; + cp_token *token; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* Figure out which operator we have. */ + switch (token->type) + { + case CPP_KEYWORD: + { + enum tree_code op; + + /* The keyword should be either `new' or `delete'. */ + if (token->keyword == RID_NEW) + op = NEW_EXPR; + else if (token->keyword == RID_DELETE) + op = DELETE_EXPR; + else + break; + + /* Consume the `new' or `delete' token. */ + cp_lexer_consume_token (parser->lexer); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's a `[' token then this is the array variant of the + operator. */ + if (token->type == CPP_OPEN_SQUARE) + { + /* Consume the `[' token. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the `]' token. */ + cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"); + id = ansi_opname (op == NEW_EXPR + ? VEC_NEW_EXPR : VEC_DELETE_EXPR); + } + /* Otherwise, we have the non-array variant. */ + else + id = ansi_opname (op); + + return id; + } + + case CPP_PLUS: + id = ansi_opname (PLUS_EXPR); + break; + + case CPP_MINUS: + id = ansi_opname (MINUS_EXPR); + break; + + case CPP_MULT: + id = ansi_opname (MULT_EXPR); + break; + + case CPP_DIV: + id = ansi_opname (TRUNC_DIV_EXPR); + break; + + case CPP_MOD: + id = ansi_opname (TRUNC_MOD_EXPR); + break; + + case CPP_XOR: + id = ansi_opname (BIT_XOR_EXPR); + break; + + case CPP_AND: + id = ansi_opname (BIT_AND_EXPR); + break; + + case CPP_OR: + id = ansi_opname (BIT_IOR_EXPR); + break; + + case CPP_COMPL: + id = ansi_opname (BIT_NOT_EXPR); + break; + + case CPP_NOT: + id = ansi_opname (TRUTH_NOT_EXPR); + break; + + case CPP_EQ: + id = ansi_assopname (NOP_EXPR); + break; + + case CPP_LESS: + id = ansi_opname (LT_EXPR); + break; + + case CPP_GREATER: + id = ansi_opname (GT_EXPR); + break; + + case CPP_PLUS_EQ: + id = ansi_assopname (PLUS_EXPR); + break; + + case CPP_MINUS_EQ: + id = ansi_assopname (MINUS_EXPR); + break; + + case CPP_MULT_EQ: + id = ansi_assopname (MULT_EXPR); + break; + + case CPP_DIV_EQ: + id = ansi_assopname (TRUNC_DIV_EXPR); + break; + + case CPP_MOD_EQ: + id = ansi_assopname (TRUNC_MOD_EXPR); + break; + + case CPP_XOR_EQ: + id = ansi_assopname (BIT_XOR_EXPR); + break; + + case CPP_AND_EQ: + id = ansi_assopname (BIT_AND_EXPR); + break; + + case CPP_OR_EQ: + id = ansi_assopname (BIT_IOR_EXPR); + break; + + case CPP_LSHIFT: + id = ansi_opname (LSHIFT_EXPR); + break; + + case CPP_RSHIFT: + id = ansi_opname (RSHIFT_EXPR); + break; + + case CPP_LSHIFT_EQ: + id = ansi_assopname (LSHIFT_EXPR); + break; + + case CPP_RSHIFT_EQ: + id = ansi_assopname (RSHIFT_EXPR); + break; + + case CPP_EQ_EQ: + id = ansi_opname (EQ_EXPR); + break; + + case CPP_NOT_EQ: + id = ansi_opname (NE_EXPR); + break; + + case CPP_LESS_EQ: + id = ansi_opname (LE_EXPR); + break; + + case CPP_GREATER_EQ: + id = ansi_opname (GE_EXPR); + break; + + case CPP_AND_AND: + id = ansi_opname (TRUTH_ANDIF_EXPR); + break; + + case CPP_OR_OR: + id = ansi_opname (TRUTH_ORIF_EXPR); + break; + + case CPP_PLUS_PLUS: + id = ansi_opname (POSTINCREMENT_EXPR); + break; + + case CPP_MINUS_MINUS: + id = ansi_opname (PREDECREMENT_EXPR); + break; + + case CPP_COMMA: + id = ansi_opname (COMPOUND_EXPR); + break; + + case CPP_DEREF_STAR: + id = ansi_opname (MEMBER_REF); + break; + + case CPP_DEREF: + id = ansi_opname (COMPONENT_REF); + break; + + case CPP_OPEN_PAREN: + /* Consume the `('. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the matching `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + return ansi_opname (CALL_EXPR); + + case CPP_OPEN_SQUARE: + /* Consume the `['. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the matching `]'. */ + cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"); + return ansi_opname (ARRAY_REF); + + /* Extensions. */ + case CPP_MIN: + id = ansi_opname (MIN_EXPR); + break; + + case CPP_MAX: + id = ansi_opname (MAX_EXPR); + break; + + case CPP_MIN_EQ: + id = ansi_assopname (MIN_EXPR); + break; + + case CPP_MAX_EQ: + id = ansi_assopname (MAX_EXPR); + break; + + default: + /* Anything else is an error. */ + break; + } + + /* If we have selected an identifier, we need to consume the + operator token. */ + if (id) + cp_lexer_consume_token (parser->lexer); + /* Otherwise, no valid operator name was present. */ + else + { + cp_parser_error (parser, "expected operator"); + id = error_mark_node; + } + + return id; +} + +/* Parse a template-declaration. + + template-declaration: + export [opt] template < template-parameter-list > declaration + + If MEMBER_P is TRUE, this template-declaration occurs within a + class-specifier. + + The grammar rule given by the standard isn't correct. What + is really meant is: + + template-declaration: + export [opt] template-parameter-list-seq + decl-specifier-seq [opt] init-declarator [opt] ; + export [opt] template-parameter-list-seq + function-definition + + template-parameter-list-seq: + template-parameter-list-seq [opt] + template < template-parameter-list > */ + +static void +cp_parser_template_declaration (cp_parser* parser, bool member_p) +{ + /* Check for `export'. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT)) + { + /* Consume the `export' token. */ + cp_lexer_consume_token (parser->lexer); + /* Warn that we do not support `export'. */ + warning ("keyword `export' not implemented, and will be ignored"); + } + + cp_parser_template_declaration_after_export (parser, member_p); +} + +/* Parse a template-parameter-list. + + template-parameter-list: + template-parameter + template-parameter-list , template-parameter + + Returns a TREE_LIST. Each node represents a template parameter. + The nodes are connected via their TREE_CHAINs. */ + +static tree +cp_parser_template_parameter_list (cp_parser* parser) +{ + tree parameter_list = NULL_TREE; + + while (true) + { + tree parameter; + cp_token *token; + + /* Parse the template-parameter. */ + parameter = cp_parser_template_parameter (parser); + /* Add it to the list. */ + parameter_list = process_template_parm (parameter_list, + parameter); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not a `,', we're done. */ + if (token->type != CPP_COMMA) + break; + /* Otherwise, consume the `,' token. */ + cp_lexer_consume_token (parser->lexer); + } + + return parameter_list; +} + +/* Parse a template-parameter. + + template-parameter: + type-parameter + parameter-declaration + + Returns a TREE_LIST. The TREE_VALUE represents the parameter. The + TREE_PURPOSE is the default value, if any. */ + +static tree +cp_parser_template_parameter (cp_parser* parser) +{ + cp_token *token; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it is `class' or `template', we have a type-parameter. */ + if (token->keyword == RID_TEMPLATE) + return cp_parser_type_parameter (parser); + /* If it is `class' or `typename' we do not know yet whether it is a + type parameter or a non-type parameter. Consider: + + template <typename T, typename T::X X> ... + + or: + + template <class C, class D*> ... + + Here, the first parameter is a type parameter, and the second is + a non-type parameter. We can tell by looking at the token after + the identifier -- if it is a `,', `=', or `>' then we have a type + parameter. */ + if (token->keyword == RID_TYPENAME || token->keyword == RID_CLASS) + { + /* Peek at the token after `class' or `typename'. */ + token = cp_lexer_peek_nth_token (parser->lexer, 2); + /* If it's an identifier, skip it. */ + if (token->type == CPP_NAME) + token = cp_lexer_peek_nth_token (parser->lexer, 3); + /* Now, see if the token looks like the end of a template + parameter. */ + if (token->type == CPP_COMMA + || token->type == CPP_EQ + || token->type == CPP_GREATER) + return cp_parser_type_parameter (parser); + } + + /* Otherwise, it is a non-type parameter. + + [temp.param] + + When parsing a default template-argument for a non-type + template-parameter, the first non-nested `>' is taken as the end + of the template parameter-list rather than a greater-than + operator. */ + return + cp_parser_parameter_declaration (parser, /*template_parm_p=*/true, + /*parenthesized_p=*/NULL); +} + +/* Parse a type-parameter. + + type-parameter: + class identifier [opt] + class identifier [opt] = type-id + typename identifier [opt] + typename identifier [opt] = type-id + template < template-parameter-list > class identifier [opt] + template < template-parameter-list > class identifier [opt] + = id-expression + + Returns a TREE_LIST. The TREE_VALUE is itself a TREE_LIST. The + TREE_PURPOSE is the default-argument, if any. The TREE_VALUE is + the declaration of the parameter. */ + +static tree +cp_parser_type_parameter (cp_parser* parser) +{ + cp_token *token; + tree parameter; + + /* Look for a keyword to tell us what kind of parameter this is. */ + token = cp_parser_require (parser, CPP_KEYWORD, + "`class', `typename', or `template'"); + if (!token) + return error_mark_node; + + switch (token->keyword) + { + case RID_CLASS: + case RID_TYPENAME: + { + tree identifier; + tree default_argument; + + /* If the next token is an identifier, then it names the + parameter. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + identifier = cp_parser_identifier (parser); + else + identifier = NULL_TREE; + + /* Create the parameter. */ + parameter = finish_template_type_parm (class_type_node, identifier); + + /* If the next token is an `=', we have a default argument. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + { + /* Consume the `=' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the default-argument. */ + default_argument = cp_parser_type_id (parser); + } + else + default_argument = NULL_TREE; + + /* Create the combined representation of the parameter and the + default argument. */ + parameter = build_tree_list (default_argument, parameter); + } + break; + + case RID_TEMPLATE: + { + tree parameter_list; + tree identifier; + tree default_argument; + + /* Look for the `<'. */ + cp_parser_require (parser, CPP_LESS, "`<'"); + /* Parse the template-parameter-list. */ + begin_template_parm_list (); + parameter_list + = cp_parser_template_parameter_list (parser); + parameter_list = end_template_parm_list (parameter_list); + /* Look for the `>'. */ + cp_parser_require (parser, CPP_GREATER, "`>'"); + /* Look for the `class' keyword. */ + cp_parser_require_keyword (parser, RID_CLASS, "`class'"); + /* If the next token is an `=', then there is a + default-argument. If the next token is a `>', we are at + the end of the parameter-list. If the next token is a `,', + then we are at the end of this parameter. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ) + && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER) + && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + identifier = cp_parser_identifier (parser); + else + identifier = NULL_TREE; + /* Create the template parameter. */ + parameter = finish_template_template_parm (class_type_node, + identifier); + + /* If the next token is an `=', then there is a + default-argument. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + { + bool is_template; + + /* Consume the `='. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the id-expression. */ + default_argument + = cp_parser_id_expression (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/&is_template, + /*declarator_p=*/false); + if (TREE_CODE (default_argument) == TYPE_DECL) + /* If the id-expression was a template-id that refers to + a template-class, we already have the declaration here, + so no further lookup is needed. */ + ; + else + /* Look up the name. */ + default_argument + = cp_parser_lookup_name (parser, default_argument, + /*is_type=*/false, + /*is_template=*/is_template, + /*is_namespace=*/false, + /*check_dependency=*/true); + /* See if the default argument is valid. */ + default_argument + = check_template_template_default_arg (default_argument); + } + else + default_argument = NULL_TREE; + + /* Create the combined representation of the parameter and the + default argument. */ + parameter = build_tree_list (default_argument, parameter); + } + break; + + default: + /* Anything else is an error. */ + cp_parser_error (parser, + "expected `class', `typename', or `template'"); + parameter = error_mark_node; + } + + return parameter; +} + +/* Parse a template-id. + + template-id: + template-name < template-argument-list [opt] > + + If TEMPLATE_KEYWORD_P is TRUE, then we have just seen the + `template' keyword. In this case, a TEMPLATE_ID_EXPR will be + returned. Otherwise, if the template-name names a function, or set + of functions, returns a TEMPLATE_ID_EXPR. If the template-name + names a class, returns a TYPE_DECL for the specialization. + + If CHECK_DEPENDENCY_P is FALSE, names are looked up in + uninstantiated templates. */ + +static tree +cp_parser_template_id (cp_parser *parser, + bool template_keyword_p, + bool check_dependency_p, + bool is_declaration) +{ + tree template; + tree arguments; + tree template_id; + ptrdiff_t start_of_id; + tree access_check = NULL_TREE; + cp_token *next_token, *next_token_2; + bool is_identifier; + + /* If the next token corresponds to a template-id, there is no need + to reparse it. */ + next_token = cp_lexer_peek_token (parser->lexer); + if (next_token->type == CPP_TEMPLATE_ID) + { + tree value; + tree check; + + /* Get the stored value. */ + value = cp_lexer_consume_token (parser->lexer)->value; + /* Perform any access checks that were deferred. */ + for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check)) + perform_or_defer_access_check (TREE_PURPOSE (check), + TREE_VALUE (check)); + /* Return the stored value. */ + return TREE_VALUE (value); + } + + /* Avoid performing name lookup if there is no possibility of + finding a template-id. */ + if ((next_token->type != CPP_NAME && next_token->keyword != RID_OPERATOR) + || (next_token->type == CPP_NAME + && !cp_parser_nth_token_starts_template_argument_list_p + (parser, 2))) + { + cp_parser_error (parser, "expected template-id"); + return error_mark_node; + } + + /* Remember where the template-id starts. */ + if (cp_parser_parsing_tentatively (parser) + && !cp_parser_committed_to_tentative_parse (parser)) + { + next_token = cp_lexer_peek_token (parser->lexer); + start_of_id = cp_lexer_token_difference (parser->lexer, + parser->lexer->first_token, + next_token); + } + else + start_of_id = -1; + + push_deferring_access_checks (dk_deferred); + + /* Parse the template-name. */ + is_identifier = false; + template = cp_parser_template_name (parser, template_keyword_p, + check_dependency_p, + is_declaration, + &is_identifier); + if (template == error_mark_node || is_identifier) + { + pop_deferring_access_checks (); + return template; + } + + /* If we find the sequence `[:' after a template-name, it's probably + a digraph-typo for `< ::'. Substitute the tokens and check if we can + parse correctly the argument list. */ + next_token = cp_lexer_peek_nth_token (parser->lexer, 1); + next_token_2 = cp_lexer_peek_nth_token (parser->lexer, 2); + if (next_token->type == CPP_OPEN_SQUARE + && next_token->flags & DIGRAPH + && next_token_2->type == CPP_COLON + && !(next_token_2->flags & PREV_WHITE)) + { + cp_parser_parse_tentatively (parser); + /* Change `:' into `::'. */ + next_token_2->type = CPP_SCOPE; + /* Consume the first token (CPP_OPEN_SQUARE - which we pretend it is + CPP_LESS. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the arguments. */ + arguments = cp_parser_enclosed_template_argument_list (parser); + if (!cp_parser_parse_definitely (parser)) + { + /* If we couldn't parse an argument list, then we revert our changes + and return simply an error. Maybe this is not a template-id + after all. */ + next_token_2->type = CPP_COLON; + cp_parser_error (parser, "expected `<'"); + pop_deferring_access_checks (); + return error_mark_node; + } + /* Otherwise, emit an error about the invalid digraph, but continue + parsing because we got our argument list. */ + pedwarn ("`<::' cannot begin a template-argument list"); + inform ("`<:' is an alternate spelling for `['. Insert whitespace " + "between `<' and `::'"); + if (!flag_permissive) + { + static bool hint; + if (!hint) + { + inform ("(if you use `-fpermissive' G++ will accept your code)"); + hint = true; + } + } + } + else + { + /* Look for the `<' that starts the template-argument-list. */ + if (!cp_parser_require (parser, CPP_LESS, "`<'")) + { + pop_deferring_access_checks (); + return error_mark_node; + } + /* Parse the arguments. */ + arguments = cp_parser_enclosed_template_argument_list (parser); + } + + /* Build a representation of the specialization. */ + if (TREE_CODE (template) == IDENTIFIER_NODE) + template_id = build_min_nt (TEMPLATE_ID_EXPR, template, arguments); + else if (DECL_CLASS_TEMPLATE_P (template) + || DECL_TEMPLATE_TEMPLATE_PARM_P (template)) + template_id + = finish_template_type (template, arguments, + cp_lexer_next_token_is (parser->lexer, + CPP_SCOPE)); + else + { + /* If it's not a class-template or a template-template, it should be + a function-template. */ + my_friendly_assert ((DECL_FUNCTION_TEMPLATE_P (template) + || TREE_CODE (template) == OVERLOAD + || BASELINK_P (template)), + 20010716); + + template_id = lookup_template_function (template, arguments); + } + + /* 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 template-id with a CPP_TEMPLATE_ID 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 about problems during instantiation of the + template. */ + if (start_of_id >= 0) + { + cp_token *token; + + /* Find the token that corresponds to the start of the + template-id. */ + token = cp_lexer_advance_token (parser->lexer, + parser->lexer->first_token, + start_of_id); + + /* Reset the contents of the START_OF_ID token. */ + token->type = CPP_TEMPLATE_ID; + token->value = build_tree_list (access_check, template_id); + token->keyword = RID_MAX; + /* Purge all subsequent tokens. */ + cp_lexer_purge_tokens_after (parser->lexer, token); + } + + pop_deferring_access_checks (); + return template_id; +} + +/* Parse a template-name. + + template-name: + identifier + + The standard should actually say: + + template-name: + identifier + operator-function-id + + A defect report has been filed about this issue. + + A conversion-function-id cannot be a template name because they cannot + be part of a template-id. In fact, looking at this code: + + a.operator K<int>() + + the conversion-function-id is "operator K<int>", and K<int> is a type-id. + It is impossible to call a templated conversion-function-id with an + explicit argument list, since the only allowed template parameter is + the type to which it is converting. + + If TEMPLATE_KEYWORD_P is true, then we have just seen the + `template' keyword, in a construction like: + + T::template f<3>() + + In that case `f' is taken to be a template-name, even though there + is no way of knowing for sure. + + Returns the TEMPLATE_DECL for the template, or an OVERLOAD if the + name refers to a set of overloaded functions, at least one of which + is a template, or an IDENTIFIER_NODE with the name of the template, + if TEMPLATE_KEYWORD_P is true. If CHECK_DEPENDENCY_P is FALSE, + names are looked up inside uninstantiated templates. */ + +static tree +cp_parser_template_name (cp_parser* parser, + bool template_keyword_p, + bool check_dependency_p, + bool is_declaration, + bool *is_identifier) +{ + tree identifier; + tree decl; + tree fns; + + /* If the next token is `operator', then we have either an + operator-function-id or a conversion-function-id. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_OPERATOR)) + { + /* We 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. */ + identifier = cp_parser_operator_function_id (parser); + /* If that didn't work, try a conversion-function-id. */ + if (!cp_parser_parse_definitely (parser)) + { + cp_parser_error (parser, "expected template-name"); + return error_mark_node; + } + } + /* Look for the identifier. */ + else + identifier = cp_parser_identifier (parser); + + /* If we didn't find an identifier, we don't have a template-id. */ + if (identifier == error_mark_node) + return error_mark_node; + + /* If the name immediately followed the `template' keyword, then it + is a template-name. However, if the next token is not `<', then + we do not treat it as a template-name, since it is not being used + as part of a template-id. This enables us to handle constructs + like: + + template <typename T> struct S { S(); }; + template <typename T> S<T>::S(); + + correctly. We would treat `S' as a template -- if it were `S<T>' + -- but we do not if there is no `<'. */ + + if (processing_template_decl + && cp_parser_nth_token_starts_template_argument_list_p (parser, 1)) + { + /* In a declaration, in a dependent context, we pretend that the + "template" keyword was present in order to improve error + recovery. For example, given: + + template <typename T> void f(T::X<int>); + + we want to treat "X<int>" as a template-id. */ + if (is_declaration + && !template_keyword_p + && parser->scope && TYPE_P (parser->scope) + && dependent_type_p (parser->scope) + /* Do not do this for dtors (or ctors), since they never + need the template keyword before their name. */ + && !constructor_name_p (identifier, parser->scope)) + { + ptrdiff_t start; + cp_token* token; + /* Explain what went wrong. */ + error ("non-template `%D' used as template", identifier); + inform ("use `%T::template %D' to indicate that it is a template", + parser->scope, identifier); + /* If parsing tentatively, find the location of the "<" + token. */ + if (cp_parser_parsing_tentatively (parser) + && !cp_parser_committed_to_tentative_parse (parser)) + { + cp_parser_simulate_error (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; + /* Parse the template arguments so that we can issue error + messages about them. */ + cp_lexer_consume_token (parser->lexer); + cp_parser_enclosed_template_argument_list (parser); + /* Skip tokens until we find a good place from which to + continue parsing. */ + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/true, + /*consume_paren=*/false); + /* If parsing tentatively, permanently remove the + template argument list. That will prevent duplicate + error messages from being issued about the missing + "template" keyword. */ + if (start >= 0) + { + token = cp_lexer_advance_token (parser->lexer, + parser->lexer->first_token, + start); + cp_lexer_purge_tokens_after (parser->lexer, token); + } + if (is_identifier) + *is_identifier = true; + return identifier; + } + + /* If the "template" keyword is present, then there is generally + no point in doing name-lookup, so we just return IDENTIFIER. + But, if the qualifying scope is non-dependent then we can + (and must) do name-lookup normally. */ + if (template_keyword_p + && (!parser->scope + || (TYPE_P (parser->scope) + && dependent_type_p (parser->scope)))) + return identifier; + } + + /* Look up the name. */ + decl = cp_parser_lookup_name (parser, identifier, + /*is_type=*/false, + /*is_template=*/false, + /*is_namespace=*/false, + check_dependency_p); + decl = maybe_get_template_decl_from_type_decl (decl); + + /* If DECL is a template, then the name was a template-name. */ + if (TREE_CODE (decl) == TEMPLATE_DECL) + ; + else + { + /* The standard does not explicitly indicate whether a name that + names a set of overloaded declarations, some of which are + templates, is a template-name. However, such a name should + be a template-name; otherwise, there is no way to form a + template-id for the overloaded templates. */ + fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl; + if (TREE_CODE (fns) == OVERLOAD) + { + tree fn; + + for (fn = fns; fn; fn = OVL_NEXT (fn)) + if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL) + break; + } + else + { + /* Otherwise, the name does not name a template. */ + cp_parser_error (parser, "expected template-name"); + return error_mark_node; + } + } + + /* If DECL is dependent, and refers to a function, then just return + its name; we will look it up again during template instantiation. */ + if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl)) + { + tree scope = CP_DECL_CONTEXT (get_first_fn (decl)); + if (TYPE_P (scope) && dependent_type_p (scope)) + return identifier; + } + + return decl; +} + +/* Parse a template-argument-list. + + template-argument-list: + template-argument + template-argument-list , template-argument + + Returns a TREE_VEC containing the arguments. */ + +static tree +cp_parser_template_argument_list (cp_parser* parser) +{ + tree fixed_args[10]; + unsigned n_args = 0; + unsigned alloced = 10; + tree *arg_ary = fixed_args; + tree vec; + bool saved_in_template_argument_list_p; + + saved_in_template_argument_list_p = parser->in_template_argument_list_p; + parser->in_template_argument_list_p = true; + do + { + tree argument; + + if (n_args) + /* Consume the comma. */ + cp_lexer_consume_token (parser->lexer); + + /* Parse the template-argument. */ + argument = cp_parser_template_argument (parser); + if (n_args == alloced) + { + alloced *= 2; + + if (arg_ary == fixed_args) + { + arg_ary = xmalloc (sizeof (tree) * alloced); + memcpy (arg_ary, fixed_args, sizeof (tree) * n_args); + } + else + arg_ary = xrealloc (arg_ary, sizeof (tree) * alloced); + } + arg_ary[n_args++] = argument; + } + while (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)); + + vec = make_tree_vec (n_args); + + while (n_args--) + TREE_VEC_ELT (vec, n_args) = arg_ary[n_args]; + + if (arg_ary != fixed_args) + free (arg_ary); + parser->in_template_argument_list_p = saved_in_template_argument_list_p; + return vec; +} + +/* Parse a template-argument. + + template-argument: + assignment-expression + type-id + id-expression + + The representation is that of an assignment-expression, type-id, or + id-expression -- except that the qualified id-expression is + evaluated, so that the value returned is either a DECL or an + OVERLOAD. + + Although the standard says "assignment-expression", it forbids + throw-expressions or assignments in the template argument. + Therefore, we use "conditional-expression" instead. */ + +static tree +cp_parser_template_argument (cp_parser* parser) +{ + tree argument; + bool template_p; + bool address_p; + bool maybe_type_id = false; + cp_token *token; + cp_id_kind idk; + tree qualifying_class; + + /* There's really no way to know what we're looking at, so we just + try each alternative in order. + + [temp.arg] + + In a template-argument, an ambiguity between a type-id and an + expression is resolved to a type-id, regardless of the form of + the corresponding template-parameter. + + Therefore, we try a type-id first. */ + cp_parser_parse_tentatively (parser); + argument = cp_parser_type_id (parser); + /* If there was no error parsing the type-id but the next token is a '>>', + we probably found a typo for '> >'. But there are type-id which are + also valid expressions. For instance: + + struct X { int operator >> (int); }; + template <int V> struct Foo {}; + Foo<X () >> 5> r; + + Here 'X()' is a valid type-id of a function type, but the user just + wanted to write the expression "X() >> 5". Thus, we remember that we + found a valid type-id, but we still try to parse the argument as an + expression to see what happens. */ + if (!cp_parser_error_occurred (parser) + && cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT)) + { + maybe_type_id = true; + cp_parser_abort_tentative_parse (parser); + } + else + { + /* If the next token isn't a `,' or a `>', then this argument wasn't + really finished. This means that the argument is not a valid + type-id. */ + if (!cp_parser_next_token_ends_template_argument_p (parser)) + cp_parser_error (parser, "expected template-argument"); + /* If that worked, we're done. */ + if (cp_parser_parse_definitely (parser)) + return argument; + } + /* We're still not sure what the argument will be. */ + cp_parser_parse_tentatively (parser); + /* Try a template. */ + argument = cp_parser_id_expression (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/true, + &template_p, + /*declarator_p=*/false); + /* If the next token isn't a `,' or a `>', then this argument wasn't + really finished. */ + if (!cp_parser_next_token_ends_template_argument_p (parser)) + cp_parser_error (parser, "expected template-argument"); + if (!cp_parser_error_occurred (parser)) + { + /* Figure out what is being referred to. If the id-expression + was for a class template specialization, then we will have a + TYPE_DECL at this point. There is no need to do name lookup + at this point in that case. */ + if (TREE_CODE (argument) != TYPE_DECL) + argument = cp_parser_lookup_name (parser, argument, + /*is_type=*/false, + /*is_template=*/template_p, + /*is_namespace=*/false, + /*check_dependency=*/true); + if (TREE_CODE (argument) != TEMPLATE_DECL + && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE) + cp_parser_error (parser, "expected template-name"); + } + if (cp_parser_parse_definitely (parser)) + return argument; + /* It must be a non-type argument. There permitted cases are given + in [temp.arg.nontype]: + + -- an integral constant-expression of integral or enumeration + type; or + + -- the name of a non-type template-parameter; or + + -- the name of an object or function with external linkage... + + -- the address of an object or function with external linkage... + + -- a pointer to member... */ + /* Look for a non-type template parameter. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + cp_parser_parse_tentatively (parser); + argument = cp_parser_primary_expression (parser, + &idk, + &qualifying_class); + if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX + || !cp_parser_next_token_ends_template_argument_p (parser)) + cp_parser_simulate_error (parser); + if (cp_parser_parse_definitely (parser)) + return argument; + } + /* If the next token is "&", the argument must be the address of an + object or function with external linkage. */ + address_p = cp_lexer_next_token_is (parser->lexer, CPP_AND); + if (address_p) + cp_lexer_consume_token (parser->lexer); + /* See if we might have an id-expression. */ + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME + || token->keyword == RID_OPERATOR + || token->type == CPP_SCOPE + || token->type == CPP_TEMPLATE_ID + || token->type == CPP_NESTED_NAME_SPECIFIER) + { + cp_parser_parse_tentatively (parser); + argument = cp_parser_primary_expression (parser, + &idk, + &qualifying_class); + if (cp_parser_error_occurred (parser) + || !cp_parser_next_token_ends_template_argument_p (parser)) + cp_parser_abort_tentative_parse (parser); + else + { + if (qualifying_class) + argument = finish_qualified_id_expr (qualifying_class, + argument, + /*done=*/true, + address_p); + if (TREE_CODE (argument) == VAR_DECL) + { + /* A variable without external linkage might still be a + valid constant-expression, so no error is issued here + if the external-linkage check fails. */ + if (!DECL_EXTERNAL_LINKAGE_P (argument)) + cp_parser_simulate_error (parser); + } + else if (is_overloaded_fn (argument)) + /* All overloaded functions are allowed; if the external + linkage test does not pass, an error will be issued + later. */ + ; + else if (address_p + && (TREE_CODE (argument) == OFFSET_REF + || TREE_CODE (argument) == SCOPE_REF)) + /* A pointer-to-member. */ + ; + else + cp_parser_simulate_error (parser); + + if (cp_parser_parse_definitely (parser)) + { + if (address_p) + argument = build_x_unary_op (ADDR_EXPR, argument); + return argument; + } + } + } + /* If the argument started with "&", there are no other valid + alternatives at this point. */ + if (address_p) + { + cp_parser_error (parser, "invalid non-type template argument"); + return error_mark_node; + } + /* If the argument wasn't successfully parsed as a type-id followed + by '>>', the argument can only be a constant expression now. + Otherwise, we try parsing the constant-expression tentatively, + because the argument could really be a type-id. */ + if (maybe_type_id) + cp_parser_parse_tentatively (parser); + argument = cp_parser_constant_expression (parser, + /*allow_non_constant_p=*/false, + /*non_constant_p=*/NULL); + argument = fold_non_dependent_expr (argument); + if (!maybe_type_id) + return argument; + if (!cp_parser_next_token_ends_template_argument_p (parser)) + cp_parser_error (parser, "expected template-argument"); + if (cp_parser_parse_definitely (parser)) + return argument; + /* We did our best to parse the argument as a non type-id, but that + was the only alternative that matched (albeit with a '>' after + it). We can assume it's just a typo from the user, and a + diagnostic will then be issued. */ + return cp_parser_type_id (parser); +} + +/* Parse an explicit-instantiation. + + explicit-instantiation: + template declaration + + Although the standard says `declaration', what it really means is: + + explicit-instantiation: + template decl-specifier-seq [opt] declarator [opt] ; + + Things like `template int S<int>::i = 5, int S<double>::j;' are not + supposed to be allowed. A defect report has been filed about this + issue. + + GNU Extension: + + explicit-instantiation: + storage-class-specifier template + decl-specifier-seq [opt] declarator [opt] ; + function-specifier template + decl-specifier-seq [opt] declarator [opt] ; */ + +static void +cp_parser_explicit_instantiation (cp_parser* parser) +{ + int declares_class_or_enum; + tree decl_specifiers; + tree attributes; + tree extension_specifier = NULL_TREE; + + /* Look for an (optional) storage-class-specifier or + function-specifier. */ + if (cp_parser_allow_gnu_extensions_p (parser)) + { + extension_specifier + = cp_parser_storage_class_specifier_opt (parser); + if (!extension_specifier) + extension_specifier = cp_parser_function_specifier_opt (parser); + } + + /* Look for the `template' keyword. */ + cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'"); + /* Let the front end know that we are processing an explicit + instantiation. */ + begin_explicit_instantiation (); + /* [temp.explicit] says that we are supposed to ignore access + control while processing explicit instantiation directives. */ + push_deferring_access_checks (dk_no_check); + /* Parse a decl-specifier-seq. */ + decl_specifiers + = cp_parser_decl_specifier_seq (parser, + CP_PARSER_FLAGS_OPTIONAL, + &attributes, + &declares_class_or_enum); + /* If there was exactly one decl-specifier, and it declared a class, + and there's no declarator, then we have an explicit type + instantiation. */ + if (declares_class_or_enum && cp_parser_declares_only_class_p (parser)) + { + tree type; + + type = check_tag_decl (decl_specifiers); + /* Turn access control back on for names used during + template instantiation. */ + pop_deferring_access_checks (); + if (type) + do_type_instantiation (type, extension_specifier, /*complain=*/1); + } + else + { + tree declarator; + tree decl; + + /* Parse the declarator. */ + declarator + = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + /*ctor_dtor_or_conv_p=*/NULL, + /*parenthesized_p=*/NULL); + cp_parser_check_for_definition_in_return_type (declarator, + declares_class_or_enum); + if (declarator != error_mark_node) + { + decl = grokdeclarator (declarator, decl_specifiers, + NORMAL, 0, NULL); + /* Turn access control back on for names used during + template instantiation. */ + pop_deferring_access_checks (); + /* Do the explicit instantiation. */ + do_decl_instantiation (decl, extension_specifier); + } + else + { + pop_deferring_access_checks (); + /* Skip the body of the explicit instantiation. */ + cp_parser_skip_to_end_of_statement (parser); + } + } + /* We're done with the instantiation. */ + end_explicit_instantiation (); + + cp_parser_consume_semicolon_at_end_of_statement (parser); +} + +/* Parse an explicit-specialization. + + explicit-specialization: + template < > declaration + + Although the standard says `declaration', what it really means is: + + explicit-specialization: + template <> decl-specifier [opt] init-declarator [opt] ; + template <> function-definition + template <> explicit-specialization + template <> template-declaration */ + +static void +cp_parser_explicit_specialization (cp_parser* parser) +{ + /* Look for the `template' keyword. */ + cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'"); + /* Look for the `<'. */ + cp_parser_require (parser, CPP_LESS, "`<'"); + /* Look for the `>'. */ + cp_parser_require (parser, CPP_GREATER, "`>'"); + /* We have processed another parameter list. */ + ++parser->num_template_parameter_lists; + /* Let the front end know that we are beginning a specialization. */ + begin_specialization (); + + /* If the next keyword is `template', we need to figure out whether + or not we're looking a template-declaration. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + { + if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS + && cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_GREATER) + cp_parser_template_declaration_after_export (parser, + /*member_p=*/false); + else + cp_parser_explicit_specialization (parser); + } + else + /* Parse the dependent declaration. */ + cp_parser_single_declaration (parser, + /*member_p=*/false, + /*friend_p=*/NULL); + + /* We're done with the specialization. */ + end_specialization (); + /* We're done with this parameter list. */ + --parser->num_template_parameter_lists; +} + +/* Parse a type-specifier. + + type-specifier: + simple-type-specifier + class-specifier + enum-specifier + elaborated-type-specifier + cv-qualifier + + GNU Extension: + + type-specifier: + __complex__ + + Returns a representation of the type-specifier. If the + type-specifier is a keyword (like `int' or `const', or + `__complex__') then the corresponding IDENTIFIER_NODE is returned. + For a class-specifier, enum-specifier, or elaborated-type-specifier + a TREE_TYPE is returned; otherwise, a TYPE_DECL is returned. + + If IS_FRIEND is TRUE then this type-specifier is being declared a + `friend'. If IS_DECLARATION is TRUE, then this type-specifier is + appearing in a decl-specifier-seq. + + If DECLARES_CLASS_OR_ENUM is non-NULL, and the type-specifier is a + class-specifier, enum-specifier, or elaborated-type-specifier, then + *DECLARES_CLASS_OR_ENUM is set to a nonzero value. The value is 1 + if a type is declared; 2 if it is defined. Otherwise, it is set to + zero. + + If IS_CV_QUALIFIER is non-NULL, and the type-specifier is a + cv-qualifier, then IS_CV_QUALIFIER is set to TRUE. Otherwise, it + is set to FALSE. */ + +static tree +cp_parser_type_specifier (cp_parser* parser, + cp_parser_flags flags, + bool is_friend, + bool is_declaration, + int* declares_class_or_enum, + bool* is_cv_qualifier) +{ + tree type_spec = NULL_TREE; + cp_token *token; + enum rid keyword; + + /* Assume this type-specifier does not declare a new type. */ + if (declares_class_or_enum) + *declares_class_or_enum = 0; + /* And that it does not specify a cv-qualifier. */ + if (is_cv_qualifier) + *is_cv_qualifier = false; + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + /* If we're looking at a keyword, we can use that to guide the + production we choose. */ + keyword = token->keyword; + switch (keyword) + { + /* Any of these indicate either a class-specifier, or an + elaborated-type-specifier. */ + case RID_CLASS: + case RID_STRUCT: + case RID_UNION: + case RID_ENUM: + /* Parse tentatively so that we can back up if we don't find a + class-specifier or enum-specifier. */ + cp_parser_parse_tentatively (parser); + /* Look for the class-specifier or enum-specifier. */ + if (keyword == RID_ENUM) + type_spec = cp_parser_enum_specifier (parser); + else + type_spec = cp_parser_class_specifier (parser); + + /* If that worked, we're done. */ + if (cp_parser_parse_definitely (parser)) + { + if (declares_class_or_enum) + *declares_class_or_enum = 2; + return type_spec; + } + + /* Fall through. */ + + case RID_TYPENAME: + /* Look for an elaborated-type-specifier. */ + type_spec = cp_parser_elaborated_type_specifier (parser, + is_friend, + is_declaration); + /* We're declaring a class or enum -- unless we're using + `typename'. */ + if (declares_class_or_enum && keyword != RID_TYPENAME) + *declares_class_or_enum = 1; + return type_spec; + + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + type_spec = cp_parser_cv_qualifier_opt (parser); + /* Even though we call a routine that looks for an optional + qualifier, we know that there should be one. */ + my_friendly_assert (type_spec != NULL, 20000328); + /* This type-specifier was a cv-qualified. */ + if (is_cv_qualifier) + *is_cv_qualifier = true; + + return type_spec; + + case RID_COMPLEX: + /* The `__complex__' keyword is a GNU extension. */ + return cp_lexer_consume_token (parser->lexer)->value; + + default: + break; + } + + /* If we do not already have a type-specifier, assume we are looking + at a simple-type-specifier. */ + type_spec = cp_parser_simple_type_specifier (parser, flags, + /*identifier_p=*/true); + + /* If we didn't find a type-specifier, and a type-specifier was not + optional in this context, issue an error message. */ + if (!type_spec && !(flags & CP_PARSER_FLAGS_OPTIONAL)) + { + cp_parser_error (parser, "expected type specifier"); + return error_mark_node; + } + + return type_spec; +} + +/* Parse a simple-type-specifier. + + simple-type-specifier: + :: [opt] nested-name-specifier [opt] type-name + :: [opt] nested-name-specifier template template-id + char + wchar_t + bool + short + int + long + signed + unsigned + float + double + void + + GNU Extension: + + simple-type-specifier: + __typeof__ unary-expression + __typeof__ ( type-id ) + + For the various keywords, the value returned is simply the + TREE_IDENTIFIER representing the keyword if IDENTIFIER_P is true. + For the first two productions, and if IDENTIFIER_P is false, the + value returned is the indicated TYPE_DECL. */ + +static tree +cp_parser_simple_type_specifier (cp_parser* parser, cp_parser_flags flags, + bool identifier_p) +{ + tree type = NULL_TREE; + cp_token *token; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + /* If we're looking at a keyword, things are easy. */ + switch (token->keyword) + { + case RID_CHAR: + type = char_type_node; + break; + case RID_WCHAR: + type = wchar_type_node; + break; + case RID_BOOL: + type = boolean_type_node; + break; + case RID_SHORT: + type = short_integer_type_node; + break; + case RID_INT: + type = integer_type_node; + break; + case RID_LONG: + type = long_integer_type_node; + break; + case RID_SIGNED: + type = integer_type_node; + break; + case RID_UNSIGNED: + type = unsigned_type_node; + break; + case RID_FLOAT: + type = float_type_node; + break; + case RID_DOUBLE: + type = double_type_node; + break; + case RID_VOID: + type = void_type_node; + break; + + case RID_TYPEOF: + { + tree operand; + + /* Consume the `typeof' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the operand to `typeof'. */ + operand = cp_parser_sizeof_operand (parser, RID_TYPEOF); + /* If it is not already a TYPE, take its type. */ + if (!TYPE_P (operand)) + operand = finish_typeof (operand); + + return operand; + } + + default: + break; + } + + /* If the type-specifier was for a built-in type, we're done. */ + if (type) + { + tree id; + + /* Consume the token. */ + id = cp_lexer_consume_token (parser->lexer)->value; + + /* There is no valid C++ program where a non-template type is + followed by a "<". That usually indicates that the user thought + that the type was a template. */ + cp_parser_check_for_invalid_template_id (parser, type); + + return identifier_p ? id : TYPE_NAME (type); + } + + /* The type-specifier must be a user-defined type. */ + if (!(flags & CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES)) + { + bool qualified_p; + bool global_p; + + /* Don't gobble tokens or issue error messages if this is an + optional type-specifier. */ + if (flags & CP_PARSER_FLAGS_OPTIONAL) + cp_parser_parse_tentatively (parser); + + /* Look for the optional `::' operator. */ + global_p + = (cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false) + != NULL_TREE); + /* Look for the nested-name specifier. */ + qualified_p + = (cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/false, + /*check_dependency_p=*/true, + /*type_p=*/false, + /*is_declaration=*/false) + != NULL_TREE); + /* If we have seen a nested-name-specifier, and the next token + is `template', then we are using the template-id production. */ + if (parser->scope + && cp_parser_optional_template_keyword (parser)) + { + /* Look for the template-id. */ + type = cp_parser_template_id (parser, + /*template_keyword_p=*/true, + /*check_dependency_p=*/true, + /*is_declaration=*/false); + /* If the template-id did not name a type, we are out of + luck. */ + if (TREE_CODE (type) != TYPE_DECL) + { + cp_parser_error (parser, "expected template-id for type"); + type = NULL_TREE; + } + } + /* Otherwise, look for a type-name. */ + else + type = cp_parser_type_name (parser); + /* Keep track of all name-lookups performed in class scopes. */ + if (type + && !global_p + && !qualified_p + && TREE_CODE (type) == TYPE_DECL + && TREE_CODE (DECL_NAME (type)) == IDENTIFIER_NODE) + maybe_note_name_used_in_class (DECL_NAME (type), type); + /* If it didn't work out, we don't have a TYPE. */ + if ((flags & CP_PARSER_FLAGS_OPTIONAL) + && !cp_parser_parse_definitely (parser)) + type = NULL_TREE; + } + + /* If we didn't get a type-name, issue an error message. */ + if (!type && !(flags & CP_PARSER_FLAGS_OPTIONAL)) + { + cp_parser_error (parser, "expected type-name"); + return error_mark_node; + } + + /* There is no valid C++ program where a non-template type is + followed by a "<". That usually indicates that the user thought + that the type was a template. */ + if (type && type != error_mark_node) + cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type)); + + return type; +} + +/* Parse a type-name. + + type-name: + class-name + enum-name + typedef-name + + enum-name: + identifier + + typedef-name: + identifier + + Returns a TYPE_DECL for the the type. */ + +static tree +cp_parser_type_name (cp_parser* parser) +{ + tree type_decl; + tree identifier; + + /* We can't know yet whether it is a class-name or not. */ + cp_parser_parse_tentatively (parser); + /* Try a class-name. */ + type_decl = cp_parser_class_name (parser, + /*typename_keyword_p=*/false, + /*template_keyword_p=*/false, + /*type_p=*/false, + /*check_dependency_p=*/true, + /*class_head_p=*/false, + /*is_declaration=*/false); + /* If it's not a class-name, keep looking. */ + if (!cp_parser_parse_definitely (parser)) + { + /* It must be a typedef-name or an enum-name. */ + identifier = cp_parser_identifier (parser); + if (identifier == error_mark_node) + return error_mark_node; + + /* Look up the type-name. */ + type_decl = cp_parser_lookup_name_simple (parser, identifier); + /* Issue an error if we did not find a type-name. */ + if (TREE_CODE (type_decl) != TYPE_DECL) + { + if (!cp_parser_simulate_error (parser)) + cp_parser_name_lookup_error (parser, identifier, type_decl, + "is not a type"); + type_decl = error_mark_node; + } + /* Remember that the name was used in the definition of the + current class so that we can check later to see if the + meaning would have been different after the class was + entirely defined. */ + else if (type_decl != error_mark_node + && !parser->scope) + maybe_note_name_used_in_class (identifier, type_decl); + } + + return type_decl; +} + + +/* Parse an elaborated-type-specifier. Note that the grammar given + here incorporates the resolution to DR68. + + elaborated-type-specifier: + class-key :: [opt] nested-name-specifier [opt] identifier + class-key :: [opt] nested-name-specifier [opt] template [opt] template-id + enum :: [opt] nested-name-specifier [opt] identifier + typename :: [opt] nested-name-specifier identifier + typename :: [opt] nested-name-specifier template [opt] + template-id + + GNU extension: + + elaborated-type-specifier: + class-key attributes :: [opt] nested-name-specifier [opt] identifier + class-key attributes :: [opt] nested-name-specifier [opt] + template [opt] template-id + enum attributes :: [opt] nested-name-specifier [opt] identifier + + If IS_FRIEND is TRUE, then this elaborated-type-specifier is being + declared `friend'. If IS_DECLARATION is TRUE, then this + elaborated-type-specifier appears in a decl-specifiers-seq, i.e., + something is being declared. + + Returns the TYPE specified. */ + +static tree +cp_parser_elaborated_type_specifier (cp_parser* parser, + bool is_friend, + bool is_declaration) +{ + enum tag_types tag_type; + tree identifier; + tree type = NULL_TREE; + tree attributes = NULL_TREE; + + /* See if we're looking at the `enum' keyword. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ENUM)) + { + /* Consume the `enum' token. */ + cp_lexer_consume_token (parser->lexer); + /* Remember that it's an enumeration type. */ + tag_type = enum_type; + /* Parse the attributes. */ + attributes = cp_parser_attributes_opt (parser); + } + /* Or, it might be `typename'. */ + else if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_TYPENAME)) + { + /* Consume the `typename' token. */ + cp_lexer_consume_token (parser->lexer); + /* Remember that it's a `typename' type. */ + tag_type = typename_type; + /* The `typename' keyword is only allowed in templates. */ + if (!processing_template_decl) + pedwarn ("using `typename' outside of template"); + } + /* Otherwise it must be a class-key. */ + else + { + tag_type = cp_parser_class_key (parser); + if (tag_type == none_type) + return error_mark_node; + /* Parse the attributes. */ + attributes = cp_parser_attributes_opt (parser); + } + + /* Look for the `::' operator. */ + cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false); + /* Look for the nested-name-specifier. */ + if (tag_type == typename_type) + { + if (cp_parser_nested_name_specifier (parser, + /*typename_keyword_p=*/true, + /*check_dependency_p=*/true, + /*type_p=*/true, + is_declaration) + == error_mark_node) + return error_mark_node; + } + else + /* Even though `typename' is not present, the proposed resolution + to Core Issue 180 says that in `class A<T>::B', `B' should be + considered a type-name, even if `A<T>' is dependent. */ + cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/true, + /*check_dependency_p=*/true, + /*type_p=*/true, + is_declaration); + /* For everything but enumeration types, consider a template-id. */ + if (tag_type != enum_type) + { + bool template_p = false; + tree decl; + + /* Allow the `template' keyword. */ + template_p = cp_parser_optional_template_keyword (parser); + /* If we didn't see `template', we don't know if there's a + template-id or not. */ + if (!template_p) + cp_parser_parse_tentatively (parser); + /* Parse the template-id. */ + decl = cp_parser_template_id (parser, template_p, + /*check_dependency_p=*/true, + is_declaration); + /* If we didn't find a template-id, look for an ordinary + identifier. */ + if (!template_p && !cp_parser_parse_definitely (parser)) + ; + /* If DECL is a TEMPLATE_ID_EXPR, and the `typename' keyword is + in effect, then we must assume that, upon instantiation, the + template will correspond to a class. */ + else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR + && tag_type == typename_type) + type = make_typename_type (parser->scope, decl, + /*complain=*/1); + else + type = TREE_TYPE (decl); + } + + /* For an enumeration type, consider only a plain identifier. */ + if (!type) + { + identifier = cp_parser_identifier (parser); + + if (identifier == error_mark_node) + { + parser->scope = NULL_TREE; + return error_mark_node; + } + + /* For a `typename', we needn't call xref_tag. */ + if (tag_type == typename_type) + return make_typename_type (parser->scope, identifier, + /*complain=*/1); + /* Look up a qualified name in the usual way. */ + if (parser->scope) + { + tree decl; + + /* In an elaborated-type-specifier, names are assumed to name + types, so we set IS_TYPE to TRUE when calling + cp_parser_lookup_name. */ + decl = cp_parser_lookup_name (parser, identifier, + /*is_type=*/true, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/true); + + /* If we are parsing friend declaration, DECL may be a + TEMPLATE_DECL tree node here. However, we need to check + whether this TEMPLATE_DECL results in valid code. Consider + the following example: + + namespace N { + template <class T> class C {}; + } + class X { + template <class T> friend class N::C; // #1, valid code + }; + template <class T> class Y { + friend class N::C; // #2, invalid code + }; + + For both case #1 and #2, we arrive at a TEMPLATE_DECL after + name lookup of `N::C'. We see that friend declaration must + be template for the code to be valid. Note that + processing_template_decl does not work here since it is + always 1 for the above two cases. */ + + decl = (cp_parser_maybe_treat_template_as_class + (decl, /*tag_name_p=*/is_friend + && parser->num_template_parameter_lists)); + + if (TREE_CODE (decl) != TYPE_DECL) + { + error ("expected type-name"); + return error_mark_node; + } + + if (TREE_CODE (TREE_TYPE (decl)) != TYPENAME_TYPE) + check_elaborated_type_specifier + (tag_type, decl, + (parser->num_template_parameter_lists + || DECL_SELF_REFERENCE_P (decl))); + + type = TREE_TYPE (decl); + } + else + { + /* An elaborated-type-specifier sometimes introduces a new type and + sometimes names an existing type. Normally, the rule is that it + introduces a new type only if there is not an existing type of + the same name already in scope. For example, given: + + struct S {}; + void f() { struct S s; } + + the `struct S' in the body of `f' is the same `struct S' as in + the global scope; the existing definition is used. However, if + there were no global declaration, this would introduce a new + local class named `S'. + + An exception to this rule applies to the following code: + + namespace N { struct S; } + + Here, the elaborated-type-specifier names a new type + unconditionally; even if there is already an `S' in the + containing scope this declaration names a new type. + This exception only applies if the elaborated-type-specifier + forms the complete declaration: + + [class.name] + + A declaration consisting solely of `class-key identifier ;' is + either a redeclaration of the name in the current scope or a + forward declaration of the identifier as a class name. It + introduces the name into the current scope. + + We are in this situation precisely when the next token is a `;'. + + An exception to the exception is that a `friend' declaration does + *not* name a new type; i.e., given: + + struct S { friend struct T; }; + + `T' is not a new type in the scope of `S'. + + Also, `new struct S' or `sizeof (struct S)' never results in the + definition of a new type; a new type can only be declared in a + declaration context. */ + + /* Warn about attributes. They are ignored. */ + if (attributes) + warning ("type attributes are honored only at type definition"); + + type = xref_tag (tag_type, identifier, + (is_friend + || !is_declaration + || cp_lexer_next_token_is_not (parser->lexer, + CPP_SEMICOLON)), + parser->num_template_parameter_lists); + } + } + if (tag_type != enum_type) + cp_parser_check_class_key (tag_type, type); + + /* A "<" cannot follow an elaborated type specifier. If that + happens, the user was probably trying to form a template-id. */ + cp_parser_check_for_invalid_template_id (parser, type); + + return type; +} + +/* Parse an enum-specifier. + + enum-specifier: + enum identifier [opt] { enumerator-list [opt] } + + Returns an ENUM_TYPE representing the enumeration. */ + +static tree +cp_parser_enum_specifier (cp_parser* parser) +{ + cp_token *token; + tree identifier = NULL_TREE; + tree type; + + /* Look for the `enum' keyword. */ + if (!cp_parser_require_keyword (parser, RID_ENUM, "`enum'")) + return error_mark_node; + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + /* See if it is an identifier. */ + if (token->type == CPP_NAME) + identifier = cp_parser_identifier (parser); + + /* Look for the `{'. */ + if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'")) + return error_mark_node; + + /* At this point, we're going ahead with the enum-specifier, even + if some other problem occurs. */ + cp_parser_commit_to_tentative_parse (parser); + + /* Issue an error message if type-definitions are forbidden here. */ + cp_parser_check_type_definition (parser); + + /* Create the new type. */ + type = start_enum (identifier ? identifier : make_anon_name ()); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not a `}', then there are some enumerators. */ + if (token->type != CPP_CLOSE_BRACE) + cp_parser_enumerator_list (parser, type); + /* Look for the `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); + + /* Finish up the enumeration. */ + finish_enum (type); + + return type; +} + +/* Parse an enumerator-list. The enumerators all have the indicated + TYPE. + + enumerator-list: + enumerator-definition + enumerator-list , enumerator-definition */ + +static void +cp_parser_enumerator_list (cp_parser* parser, tree type) +{ + while (true) + { + cp_token *token; + + /* Parse an enumerator-definition. */ + cp_parser_enumerator_definition (parser, type); + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not a `,', then we've reached the end of the + list. */ + if (token->type != CPP_COMMA) + break; + /* Otherwise, consume the `,' and keep going. */ + cp_lexer_consume_token (parser->lexer); + /* If the next token is a `}', there is a trailing comma. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) + { + if (pedantic && !in_system_header) + pedwarn ("comma at end of enumerator list"); + break; + } + } +} + +/* Parse an enumerator-definition. The enumerator has the indicated + TYPE. + + enumerator-definition: + enumerator + enumerator = constant-expression + + enumerator: + identifier */ + +static void +cp_parser_enumerator_definition (cp_parser* parser, tree type) +{ + cp_token *token; + tree identifier; + tree value; + + /* Look for the identifier. */ + identifier = cp_parser_identifier (parser); + if (identifier == error_mark_node) + return; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's an `=', then there's an explicit value. */ + if (token->type == CPP_EQ) + { + /* Consume the `=' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the value. */ + value = cp_parser_constant_expression (parser, + /*allow_non_constant_p=*/false, + NULL); + } + else + value = NULL_TREE; + + /* Create the enumerator. */ + build_enumerator (identifier, value, type); +} + +/* Parse a namespace-name. + + namespace-name: + original-namespace-name + namespace-alias + + Returns the NAMESPACE_DECL for the namespace. */ + +static tree +cp_parser_namespace_name (cp_parser* parser) +{ + tree identifier; + tree namespace_decl; + + /* Get the name of the namespace. */ + identifier = cp_parser_identifier (parser); + if (identifier == error_mark_node) + return error_mark_node; + + /* Look up the identifier in the currently active scope. Look only + for namespaces, due to: + + [basic.lookup.udir] + + When looking up a namespace-name in a using-directive or alias + definition, only namespace names are considered. + + And: + + [basic.lookup.qual] + + During the lookup of a name preceding the :: scope resolution + operator, object, function, and enumerator names are ignored. + + (Note that cp_parser_class_or_namespace_name only calls this + function if the token after the name is the scope resolution + operator.) */ + namespace_decl = cp_parser_lookup_name (parser, identifier, + /*is_type=*/false, + /*is_template=*/false, + /*is_namespace=*/true, + /*check_dependency=*/true); + /* If it's not a namespace, issue an error. */ + if (namespace_decl == error_mark_node + || TREE_CODE (namespace_decl) != NAMESPACE_DECL) + { + cp_parser_error (parser, "expected namespace-name"); + namespace_decl = error_mark_node; + } + + return namespace_decl; +} + +/* Parse a namespace-definition. + + namespace-definition: + named-namespace-definition + unnamed-namespace-definition + + named-namespace-definition: + original-namespace-definition + extension-namespace-definition + + original-namespace-definition: + namespace identifier { namespace-body } + + extension-namespace-definition: + namespace original-namespace-name { namespace-body } + + unnamed-namespace-definition: + namespace { namespace-body } */ + +static void +cp_parser_namespace_definition (cp_parser* parser) +{ + tree identifier; + + /* Look for the `namespace' keyword. */ + cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'"); + + /* Get the name of the namespace. We do not attempt to distinguish + between an original-namespace-definition and an + extension-namespace-definition at this point. The semantic + analysis routines are responsible for that. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + identifier = cp_parser_identifier (parser); + else + identifier = NULL_TREE; + + /* Look for the `{' to start the namespace. */ + cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"); + /* Start the namespace. */ + push_namespace (identifier); + /* Parse the body of the namespace. */ + cp_parser_namespace_body (parser); + /* Finish the namespace. */ + pop_namespace (); + /* Look for the final `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); +} + +/* Parse a namespace-body. + + namespace-body: + declaration-seq [opt] */ + +static void +cp_parser_namespace_body (cp_parser* parser) +{ + cp_parser_declaration_seq_opt (parser); +} + +/* Parse a namespace-alias-definition. + + namespace-alias-definition: + namespace identifier = qualified-namespace-specifier ; */ + +static void +cp_parser_namespace_alias_definition (cp_parser* parser) +{ + tree identifier; + tree namespace_specifier; + + /* Look for the `namespace' keyword. */ + cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'"); + /* Look for the identifier. */ + identifier = cp_parser_identifier (parser); + if (identifier == error_mark_node) + return; + /* Look for the `=' token. */ + cp_parser_require (parser, CPP_EQ, "`='"); + /* Look for the qualified-namespace-specifier. */ + namespace_specifier + = cp_parser_qualified_namespace_specifier (parser); + /* Look for the `;' token. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + + /* Register the alias in the symbol table. */ + do_namespace_alias (identifier, namespace_specifier); +} + +/* Parse a qualified-namespace-specifier. + + qualified-namespace-specifier: + :: [opt] nested-name-specifier [opt] namespace-name + + Returns a NAMESPACE_DECL corresponding to the specified + namespace. */ + +static tree +cp_parser_qualified_namespace_specifier (cp_parser* parser) +{ + /* Look for the optional `::'. */ + cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false); + + /* Look for the optional nested-name-specifier. */ + cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/false, + /*check_dependency_p=*/true, + /*type_p=*/false, + /*is_declaration=*/true); + + return cp_parser_namespace_name (parser); +} + +/* Parse a using-declaration. + + using-declaration: + using typename [opt] :: [opt] nested-name-specifier unqualified-id ; + using :: unqualified-id ; */ + +static void +cp_parser_using_declaration (cp_parser* parser) +{ + cp_token *token; + bool typename_p = false; + bool global_scope_p; + tree decl; + tree identifier; + tree scope; + tree qscope; + + /* Look for the `using' keyword. */ + cp_parser_require_keyword (parser, RID_USING, "`using'"); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* See if it's `typename'. */ + if (token->keyword == RID_TYPENAME) + { + /* Remember that we've seen it. */ + typename_p = true; + /* Consume the `typename' token. */ + cp_lexer_consume_token (parser->lexer); + } + + /* Look for the optional global scope qualification. */ + global_scope_p + = (cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false) + != NULL_TREE); + + /* If we saw `typename', or didn't see `::', then there must be a + nested-name-specifier present. */ + if (typename_p || !global_scope_p) + qscope = cp_parser_nested_name_specifier (parser, typename_p, + /*check_dependency_p=*/true, + /*type_p=*/false, + /*is_declaration=*/true); + /* Otherwise, we could be in either of the two productions. In that + case, treat the nested-name-specifier as optional. */ + else + qscope = cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/false, + /*check_dependency_p=*/true, + /*type_p=*/false, + /*is_declaration=*/true); + if (!qscope) + qscope = global_namespace; + + /* Parse the unqualified-id. */ + identifier = cp_parser_unqualified_id (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/true, + /*declarator_p=*/true); + + /* The function we call to handle a using-declaration is different + depending on what scope we are in. */ + if (identifier == error_mark_node) + ; + else if (TREE_CODE (identifier) != IDENTIFIER_NODE + && TREE_CODE (identifier) != BIT_NOT_EXPR) + /* [namespace.udecl] + + A using declaration shall not name a template-id. */ + error ("a template-id may not appear in a using-declaration"); + else + { + scope = current_scope (); + if (scope && TYPE_P (scope)) + { + /* Create the USING_DECL. */ + decl = do_class_using_decl (build_nt (SCOPE_REF, + parser->scope, + identifier)); + /* Add it to the list of members in this class. */ + finish_member_declaration (decl); + } + else + { + decl = cp_parser_lookup_name_simple (parser, identifier); + if (decl == error_mark_node) + cp_parser_name_lookup_error (parser, identifier, decl, NULL); + else if (scope) + do_local_using_decl (decl, qscope, identifier); + else + do_toplevel_using_decl (decl, qscope, identifier); + } + } + + /* Look for the final `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); +} + +/* Parse a using-directive. + + using-directive: + using namespace :: [opt] nested-name-specifier [opt] + namespace-name ; */ + +static void +cp_parser_using_directive (cp_parser* parser) +{ + tree namespace_decl; + tree attribs; + + /* Look for the `using' keyword. */ + cp_parser_require_keyword (parser, RID_USING, "`using'"); + /* And the `namespace' keyword. */ + cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'"); + /* Look for the optional `::' operator. */ + cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false); + /* And the optional nested-name-specifier. */ + cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/false, + /*check_dependency_p=*/true, + /*type_p=*/false, + /*is_declaration=*/true); + /* Get the namespace being used. */ + namespace_decl = cp_parser_namespace_name (parser); + /* And any specified attributes. */ + attribs = cp_parser_attributes_opt (parser); + /* Update the symbol table. */ + parse_using_directive (namespace_decl, attribs); + /* Look for the final `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); +} + +/* Parse an asm-definition. + + asm-definition: + asm ( string-literal ) ; + + GNU Extension: + + asm-definition: + asm volatile [opt] ( string-literal ) ; + asm volatile [opt] ( string-literal : asm-operand-list [opt] ) ; + asm volatile [opt] ( string-literal : asm-operand-list [opt] + : asm-operand-list [opt] ) ; + asm volatile [opt] ( string-literal : asm-operand-list [opt] + : asm-operand-list [opt] + : asm-operand-list [opt] ) ; */ + +static void +cp_parser_asm_definition (cp_parser* parser) +{ + cp_token *token; + tree string; + tree outputs = NULL_TREE; + tree inputs = NULL_TREE; + tree clobbers = NULL_TREE; + tree asm_stmt; + bool volatile_p = false; + bool extended_p = false; + + /* Look for the `asm' keyword. */ + cp_parser_require_keyword (parser, RID_ASM, "`asm'"); + /* See if the next token is `volatile'. */ + if (cp_parser_allow_gnu_extensions_p (parser) + && cp_lexer_next_token_is_keyword (parser->lexer, RID_VOLATILE)) + { + /* Remember that we saw the `volatile' keyword. */ + volatile_p = true; + /* Consume the token. */ + cp_lexer_consume_token (parser->lexer); + } + /* Look for the opening `('. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + /* Look for the string. */ + token = cp_parser_require (parser, CPP_STRING, "asm body"); + if (!token) + return; + string = token->value; + /* If we're allowing GNU extensions, check for the extended assembly + syntax. Unfortunately, the `:' tokens need not be separated by + a space in C, and so, for compatibility, we tolerate that here + too. Doing that means that we have to treat the `::' operator as + two `:' tokens. */ + if (cp_parser_allow_gnu_extensions_p (parser) + && at_function_scope_p () + && (cp_lexer_next_token_is (parser->lexer, CPP_COLON) + || cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))) + { + bool inputs_p = false; + bool clobbers_p = false; + + /* The extended syntax was used. */ + extended_p = true; + + /* Look for outputs. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + /* Consume the `:'. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the output-operands. */ + if (cp_lexer_next_token_is_not (parser->lexer, + CPP_COLON) + && cp_lexer_next_token_is_not (parser->lexer, + CPP_SCOPE) + && cp_lexer_next_token_is_not (parser->lexer, + CPP_CLOSE_PAREN)) + outputs = cp_parser_asm_operand_list (parser); + } + /* If the next token is `::', there are no outputs, and the + next token is the beginning of the inputs. */ + else if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) + { + /* Consume the `::' token. */ + cp_lexer_consume_token (parser->lexer); + /* The inputs are coming next. */ + inputs_p = true; + } + + /* Look for inputs. */ + if (inputs_p + || cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + if (!inputs_p) + /* Consume the `:'. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the output-operands. */ + if (cp_lexer_next_token_is_not (parser->lexer, + CPP_COLON) + && cp_lexer_next_token_is_not (parser->lexer, + CPP_SCOPE) + && cp_lexer_next_token_is_not (parser->lexer, + CPP_CLOSE_PAREN)) + inputs = cp_parser_asm_operand_list (parser); + } + else if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) + /* The clobbers are coming next. */ + clobbers_p = true; + + /* Look for clobbers. */ + if (clobbers_p + || cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + if (!clobbers_p) + /* Consume the `:'. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the clobbers. */ + if (cp_lexer_next_token_is_not (parser->lexer, + CPP_CLOSE_PAREN)) + clobbers = cp_parser_asm_clobber_list (parser); + } + } + /* Look for the closing `)'. */ + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, true, false, + /*consume_paren=*/true); + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + + /* Create the ASM_STMT. */ + if (at_function_scope_p ()) + { + asm_stmt = + finish_asm_stmt (volatile_p + ? ridpointers[(int) RID_VOLATILE] : NULL_TREE, + string, outputs, inputs, clobbers); + /* If the extended syntax was not used, mark the ASM_STMT. */ + if (!extended_p) + ASM_INPUT_P (asm_stmt) = 1; + } + else + assemble_asm (string); +} + +/* Declarators [gram.dcl.decl] */ + +/* Parse an init-declarator. + + init-declarator: + declarator initializer [opt] + + GNU Extension: + + init-declarator: + declarator asm-specification [opt] attributes [opt] initializer [opt] + + function-definition: + decl-specifier-seq [opt] declarator ctor-initializer [opt] + function-body + decl-specifier-seq [opt] declarator function-try-block + + GNU Extension: + + function-definition: + __extension__ function-definition + + The DECL_SPECIFIERS and PREFIX_ATTRIBUTES apply to this declarator. + Returns a representation of the entity declared. If MEMBER_P is TRUE, + then this declarator appears in a class scope. The new DECL created + by this declarator is returned. + + If FUNCTION_DEFINITION_ALLOWED_P then we handle the declarator and + for a function-definition here as well. If the declarator is a + declarator for a function-definition, *FUNCTION_DEFINITION_P will + be TRUE upon return. By that point, the function-definition will + have been completely parsed. + + FUNCTION_DEFINITION_P may be NULL if FUNCTION_DEFINITION_ALLOWED_P + is FALSE. */ + +static tree +cp_parser_init_declarator (cp_parser* parser, + tree decl_specifiers, + tree prefix_attributes, + bool function_definition_allowed_p, + bool member_p, + int declares_class_or_enum, + bool* function_definition_p) +{ + cp_token *token; + tree declarator; + tree attributes; + tree asm_specification; + tree initializer; + tree decl = NULL_TREE; + tree scope; + bool is_initialized; + bool is_parenthesized_init; + bool is_non_constant_init; + int ctor_dtor_or_conv_p; + bool friend_p; + bool pop_p = false; + + /* Assume that this is not the declarator for a function + definition. */ + if (function_definition_p) + *function_definition_p = false; + + /* Defer access checks while parsing the declarator; we cannot know + what names are accessible until we know what is being + declared. */ + resume_deferring_access_checks (); + + /* Parse the declarator. */ + declarator + = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + &ctor_dtor_or_conv_p, + /*parenthesized_p=*/NULL); + /* Gather up the deferred checks. */ + stop_deferring_access_checks (); + + /* If the DECLARATOR was erroneous, there's no need to go + further. */ + if (declarator == error_mark_node) + return error_mark_node; + + cp_parser_check_for_definition_in_return_type (declarator, + declares_class_or_enum); + + /* Figure out what scope the entity declared by the DECLARATOR is + located in. `grokdeclarator' sometimes changes the scope, so + we compute it now. */ + scope = get_scope_of_declarator (declarator); + + /* If we're allowing GNU extensions, look for an asm-specification + and attributes. */ + if (cp_parser_allow_gnu_extensions_p (parser)) + { + /* Look for an asm-specification. */ + asm_specification = cp_parser_asm_specification_opt (parser); + /* And attributes. */ + attributes = cp_parser_attributes_opt (parser); + } + else + { + asm_specification = NULL_TREE; + attributes = NULL_TREE; + } + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* Check to see if the token indicates the start of a + function-definition. */ + if (cp_parser_token_starts_function_definition_p (token)) + { + if (!function_definition_allowed_p) + { + /* If a function-definition should not appear here, issue an + error message. */ + cp_parser_error (parser, + "a function-definition is not allowed here"); + return error_mark_node; + } + else + { + /* Neither attributes nor an asm-specification are allowed + on a function-definition. */ + if (asm_specification) + error ("an asm-specification is not allowed on a function-definition"); + if (attributes) + error ("attributes are not allowed on a function-definition"); + /* This is a function-definition. */ + *function_definition_p = true; + + /* Parse the function definition. */ + if (member_p) + decl = cp_parser_save_member_function_body (parser, + decl_specifiers, + declarator, + prefix_attributes); + else + decl + = (cp_parser_function_definition_from_specifiers_and_declarator + (parser, decl_specifiers, prefix_attributes, declarator)); + + return decl; + } + } + + /* [dcl.dcl] + + Only in function declarations for constructors, destructors, and + type conversions can the decl-specifier-seq be omitted. + + We explicitly postpone this check past the point where we handle + function-definitions because we tolerate function-definitions + that are missing their return types in some modes. */ + if (!decl_specifiers && ctor_dtor_or_conv_p <= 0) + { + cp_parser_error (parser, + "expected constructor, destructor, or type conversion"); + return error_mark_node; + } + + /* An `=' or an `(' indicates an initializer. */ + is_initialized = (token->type == CPP_EQ + || token->type == CPP_OPEN_PAREN); + /* If the init-declarator isn't initialized and isn't followed by a + `,' or `;', it's not a valid init-declarator. */ + if (!is_initialized + && token->type != CPP_COMMA + && token->type != CPP_SEMICOLON) + { + cp_parser_error (parser, "expected init-declarator"); + return error_mark_node; + } + + /* Because start_decl has side-effects, we should only call it if we + know we're going ahead. By this point, we know that we cannot + possibly be looking at any other construct. */ + cp_parser_commit_to_tentative_parse (parser); + + /* If the decl specifiers were bad, issue an error now that we're + sure this was intended to be a declarator. Then continue + declaring the variable(s), as int, to try to cut down on further + errors. */ + if (decl_specifiers != NULL + && TREE_VALUE (decl_specifiers) == error_mark_node) + { + cp_parser_error (parser, "invalid type in declaration"); + TREE_VALUE (decl_specifiers) = integer_type_node; + } + + /* Check to see whether or not this declaration is a friend. */ + friend_p = cp_parser_friend_p (decl_specifiers); + + /* Check that the number of template-parameter-lists is OK. */ + if (!cp_parser_check_declarator_template_parameters (parser, declarator)) + return error_mark_node; + + /* Enter the newly declared entry in the symbol table. If we're + processing a declaration in a class-specifier, we wait until + after processing the initializer. */ + if (!member_p) + { + if (parser->in_unbraced_linkage_specification_p) + { + decl_specifiers = tree_cons (error_mark_node, + get_identifier ("extern"), + decl_specifiers); + have_extern_spec = false; + } + decl = start_decl (declarator, decl_specifiers, + is_initialized, attributes, prefix_attributes); + } + + /* Enter the SCOPE. That way unqualified names appearing in the + initializer will be looked up in SCOPE. */ + if (scope) + pop_p = push_scope (scope); + + /* Perform deferred access control checks, now that we know in which + SCOPE the declared entity resides. */ + if (!member_p && decl) + { + tree saved_current_function_decl = NULL_TREE; + + /* If the entity being declared is a function, pretend that we + are in its scope. If it is a `friend', it may have access to + things that would not otherwise be accessible. */ + if (TREE_CODE (decl) == FUNCTION_DECL) + { + saved_current_function_decl = current_function_decl; + current_function_decl = decl; + } + + /* Perform the access control checks for the declarator and the + the decl-specifiers. */ + perform_deferred_access_checks (); + + /* Restore the saved value. */ + if (TREE_CODE (decl) == FUNCTION_DECL) + current_function_decl = saved_current_function_decl; + } + + /* Parse the initializer. */ + if (is_initialized) + initializer = cp_parser_initializer (parser, + &is_parenthesized_init, + &is_non_constant_init); + else + { + initializer = NULL_TREE; + is_parenthesized_init = false; + is_non_constant_init = true; + } + + /* The old parser allows attributes to appear after a parenthesized + initializer. Mark Mitchell proposed removing this functionality + on the GCC mailing lists on 2002-08-13. This parser accepts the + attributes -- but ignores them. */ + if (cp_parser_allow_gnu_extensions_p (parser) && is_parenthesized_init) + if (cp_parser_attributes_opt (parser)) + warning ("attributes after parenthesized initializer ignored"); + + /* Leave the SCOPE, now that we have processed the initializer. It + is important to do this before calling cp_finish_decl because it + makes decisions about whether to create DECL_STMTs or not based + on the current scope. */ + if (pop_p) + pop_scope (scope); + + /* For an in-class declaration, use `grokfield' to create the + declaration. */ + if (member_p) + { + decl = grokfield (declarator, decl_specifiers, + initializer, /*asmspec=*/NULL_TREE, + /*attributes=*/NULL_TREE); + if (decl && TREE_CODE (decl) == FUNCTION_DECL) + cp_parser_save_default_args (parser, decl); + } + + /* Finish processing the declaration. But, skip friend + declarations. */ + if (!friend_p && decl) + cp_finish_decl (decl, + initializer, + asm_specification, + /* If the initializer is in parentheses, then this is + a direct-initialization, which means that an + `explicit' constructor is OK. Otherwise, an + `explicit' constructor cannot be used. */ + ((is_parenthesized_init || !is_initialized) + ? 0 : LOOKUP_ONLYCONVERTING)); + + /* Remember whether or not variables were initialized by + constant-expressions. */ + if (decl && TREE_CODE (decl) == VAR_DECL + && is_initialized && !is_non_constant_init) + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true; + + return decl; +} + +/* Parse a declarator. + + declarator: + direct-declarator + ptr-operator declarator + + abstract-declarator: + ptr-operator abstract-declarator [opt] + direct-abstract-declarator + + GNU Extensions: + + declarator: + attributes [opt] direct-declarator + attributes [opt] ptr-operator declarator + + abstract-declarator: + attributes [opt] ptr-operator abstract-declarator [opt] + attributes [opt] direct-abstract-declarator + + Returns a representation of the declarator. If the declarator has + the form `* declarator', then an INDIRECT_REF is returned, whose + only operand is the sub-declarator. Analogously, `& declarator' is + represented as an ADDR_EXPR. For `X::* declarator', a SCOPE_REF is + used. The first operand is the TYPE for `X'. The second operand + is an INDIRECT_REF whose operand is the sub-declarator. + + Otherwise, the representation is as for a direct-declarator. + + (It would be better to define a structure type to represent + declarators, rather than abusing `tree' nodes to represent + declarators. That would be much clearer and save some memory. + There is no reason for declarators to be garbage-collected, for + example; they are created during parser and no longer needed after + `grokdeclarator' has been called.) + + For a ptr-operator that has the optional cv-qualifier-seq, + cv-qualifiers will be stored in the TREE_TYPE of the INDIRECT_REF + node. + + If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to + detect constructor, destructor or conversion operators. It is set + to -1 if the declarator is a name, and +1 if it is a + function. Otherwise it is set to zero. Usually you just want to + test for >0, but internally the negative value is used. + + (The reason for CTOR_DTOR_OR_CONV_P is that a declaration must have + a decl-specifier-seq unless it declares a constructor, destructor, + or conversion. It might seem that we could check this condition in + semantic analysis, rather than parsing, but that makes it difficult + to handle something like `f()'. We want to notice that there are + no decl-specifiers, and therefore realize that this is an + expression, not a declaration.) + + If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to true iff + the declarator is a direct-declarator of the form "(...)". */ + +static tree +cp_parser_declarator (cp_parser* parser, + cp_parser_declarator_kind dcl_kind, + int* ctor_dtor_or_conv_p, + bool* parenthesized_p) +{ + cp_token *token; + tree declarator; + enum tree_code code; + tree cv_qualifier_seq; + tree class_type; + tree attributes = NULL_TREE; + + /* Assume this is not a constructor, destructor, or type-conversion + operator. */ + if (ctor_dtor_or_conv_p) + *ctor_dtor_or_conv_p = 0; + + if (cp_parser_allow_gnu_extensions_p (parser)) + attributes = cp_parser_attributes_opt (parser); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + /* Check for the ptr-operator production. */ + cp_parser_parse_tentatively (parser); + /* Parse the ptr-operator. */ + code = cp_parser_ptr_operator (parser, + &class_type, + &cv_qualifier_seq); + /* If that worked, then we have a ptr-operator. */ + if (cp_parser_parse_definitely (parser)) + { + /* If a ptr-operator was found, then this declarator was not + parenthesized. */ + if (parenthesized_p) + *parenthesized_p = true; + /* The dependent declarator is optional if we are parsing an + abstract-declarator. */ + if (dcl_kind != CP_PARSER_DECLARATOR_NAMED) + cp_parser_parse_tentatively (parser); + + /* Parse the dependent declarator. */ + declarator = cp_parser_declarator (parser, dcl_kind, + /*ctor_dtor_or_conv_p=*/NULL, + /*parenthesized_p=*/NULL); + + /* If we are parsing an abstract-declarator, we must handle the + case where the dependent declarator is absent. */ + if (dcl_kind != CP_PARSER_DECLARATOR_NAMED + && !cp_parser_parse_definitely (parser)) + declarator = NULL_TREE; + + /* Build the representation of the ptr-operator. */ + if (code == INDIRECT_REF) + declarator = make_pointer_declarator (cv_qualifier_seq, + declarator); + else + declarator = make_reference_declarator (cv_qualifier_seq, + declarator); + /* Handle the pointer-to-member case. */ + if (class_type) + declarator = build_nt (SCOPE_REF, class_type, declarator); + } + /* Everything else is a direct-declarator. */ + else + { + if (parenthesized_p) + *parenthesized_p = cp_lexer_next_token_is (parser->lexer, + CPP_OPEN_PAREN); + declarator = cp_parser_direct_declarator (parser, dcl_kind, + ctor_dtor_or_conv_p); + } + + if (attributes && declarator != error_mark_node) + declarator = tree_cons (attributes, declarator, NULL_TREE); + + return declarator; +} + +/* Parse a direct-declarator or direct-abstract-declarator. + + direct-declarator: + declarator-id + direct-declarator ( parameter-declaration-clause ) + cv-qualifier-seq [opt] + exception-specification [opt] + direct-declarator [ constant-expression [opt] ] + ( declarator ) + + direct-abstract-declarator: + direct-abstract-declarator [opt] + ( parameter-declaration-clause ) + cv-qualifier-seq [opt] + exception-specification [opt] + direct-abstract-declarator [opt] [ constant-expression [opt] ] + ( abstract-declarator ) + + Returns a representation of the declarator. DCL_KIND is + CP_PARSER_DECLARATOR_ABSTRACT, if we are parsing a + direct-abstract-declarator. It is CP_PARSER_DECLARATOR_NAMED, if + we are parsing a direct-declarator. It is + CP_PARSER_DECLARATOR_EITHER, if we can accept either - in the case + of ambiguity we prefer an abstract declarator, as per + [dcl.ambig.res]. CTOR_DTOR_OR_CONV_P is as for + cp_parser_declarator. + + For the declarator-id production, the representation is as for an + id-expression, except that a qualified name is represented as a + SCOPE_REF. A function-declarator is represented as a CALL_EXPR; + see the documentation of the FUNCTION_DECLARATOR_* macros for + information about how to find the various declarator components. + An array-declarator is represented as an ARRAY_REF. The + direct-declarator is the first operand; the constant-expression + indicating the size of the array is the second operand. */ + +static tree +cp_parser_direct_declarator (cp_parser* parser, + cp_parser_declarator_kind dcl_kind, + int* ctor_dtor_or_conv_p) +{ + cp_token *token; + tree declarator = NULL_TREE; + tree scope = NULL_TREE; + bool saved_default_arg_ok_p = parser->default_arg_ok_p; + bool saved_in_declarator_p = parser->in_declarator_p; + bool first = true; + bool pop_p = false; + + while (true) + { + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_OPEN_PAREN) + { + /* This is either a parameter-declaration-clause, or a + parenthesized declarator. When we know we are parsing a + named declarator, it must be a parenthesized declarator + if FIRST is true. For instance, `(int)' is a + parameter-declaration-clause, with an omitted + direct-abstract-declarator. But `((*))', is a + parenthesized abstract declarator. Finally, when T is a + template parameter `(T)' is a + parameter-declaration-clause, and not a parenthesized + named declarator. + + We first try and parse a parameter-declaration-clause, + and then try a nested declarator (if FIRST is true). + + It is not an error for it not to be a + parameter-declaration-clause, even when FIRST is + false. Consider, + + int i (int); + int i (3); + + The first is the declaration of a function while the + second is a the definition of a variable, including its + initializer. + + Having seen only the parenthesis, we cannot know which of + these two alternatives should be selected. Even more + complex are examples like: + + int i (int (a)); + int i (int (3)); + + The former is a function-declaration; the latter is a + variable initialization. + + Thus again, we try a parameter-declaration-clause, and if + that fails, we back out and return. */ + + if (!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED) + { + tree params; + unsigned saved_num_template_parameter_lists; + + cp_parser_parse_tentatively (parser); + + /* Consume the `('. */ + cp_lexer_consume_token (parser->lexer); + if (first) + { + /* If this is going to be an abstract declarator, we're + in a declarator and we can't have default args. */ + parser->default_arg_ok_p = false; + parser->in_declarator_p = true; + } + + /* Inside the function parameter list, surrounding + template-parameter-lists do not apply. */ + saved_num_template_parameter_lists + = parser->num_template_parameter_lists; + parser->num_template_parameter_lists = 0; + + /* Parse the parameter-declaration-clause. */ + params = cp_parser_parameter_declaration_clause (parser); + + parser->num_template_parameter_lists + = saved_num_template_parameter_lists; + + /* If all went well, parse the cv-qualifier-seq and the + exception-specification. */ + if (cp_parser_parse_definitely (parser)) + { + tree cv_qualifiers; + tree exception_specification; + + if (ctor_dtor_or_conv_p) + *ctor_dtor_or_conv_p = *ctor_dtor_or_conv_p < 0; + first = false; + /* Consume the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + + /* Parse the cv-qualifier-seq. */ + cv_qualifiers = cp_parser_cv_qualifier_seq_opt (parser); + /* And the exception-specification. */ + exception_specification + = cp_parser_exception_specification_opt (parser); + + /* Create the function-declarator. */ + declarator = make_call_declarator (declarator, + params, + cv_qualifiers, + exception_specification); + /* Any subsequent parameter lists are to do with + return type, so are not those of the declared + function. */ + parser->default_arg_ok_p = false; + + /* Repeat the main loop. */ + continue; + } + } + + /* If this is the first, we can try a parenthesized + declarator. */ + if (first) + { + bool saved_in_type_id_in_expr_p; + + parser->default_arg_ok_p = saved_default_arg_ok_p; + parser->in_declarator_p = saved_in_declarator_p; + + /* Consume the `('. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the nested declarator. */ + saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; + parser->in_type_id_in_expr_p = true; + declarator + = cp_parser_declarator (parser, dcl_kind, ctor_dtor_or_conv_p, + /*parenthesized_p=*/NULL); + parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; + first = false; + /* Expect a `)'. */ + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + declarator = error_mark_node; + if (declarator == error_mark_node) + break; + + goto handle_declarator; + } + /* Otherwise, we must be done. */ + else + break; + } + else if ((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED) + && token->type == CPP_OPEN_SQUARE) + { + /* Parse an array-declarator. */ + tree bounds; + + if (ctor_dtor_or_conv_p) + *ctor_dtor_or_conv_p = 0; + + first = false; + parser->default_arg_ok_p = false; + parser->in_declarator_p = true; + /* Consume the `['. */ + cp_lexer_consume_token (parser->lexer); + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If the next token is `]', then there is no + constant-expression. */ + if (token->type != CPP_CLOSE_SQUARE) + { + bool non_constant_p; + + bounds + = cp_parser_constant_expression (parser, + /*allow_non_constant=*/true, + &non_constant_p); + if (!non_constant_p) + bounds = fold_non_dependent_expr (bounds); + } + else + bounds = NULL_TREE; + /* Look for the closing `]'. */ + if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'")) + { + declarator = error_mark_node; + break; + } + + declarator = build_nt (ARRAY_REF, declarator, bounds); + } + else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT) + { + /* Parse a declarator-id */ + if (dcl_kind == CP_PARSER_DECLARATOR_EITHER) + cp_parser_parse_tentatively (parser); + declarator = cp_parser_declarator_id (parser); + if (dcl_kind == CP_PARSER_DECLARATOR_EITHER) + { + if (!cp_parser_parse_definitely (parser)) + declarator = error_mark_node; + else if (TREE_CODE (declarator) != IDENTIFIER_NODE) + { + cp_parser_error (parser, "expected unqualified-id"); + declarator = error_mark_node; + } + } + + if (declarator == error_mark_node) + break; + + if (TREE_CODE (declarator) == SCOPE_REF + && !current_scope ()) + { + tree scope = TREE_OPERAND (declarator, 0); + + /* In the declaration of a member of a template class + outside of the class itself, the SCOPE will sometimes + be a TYPENAME_TYPE. For example, given: + + template <typename T> + int S<T>::R::i = 3; + + the SCOPE will be a TYPENAME_TYPE for `S<T>::R'. In + this context, we must resolve S<T>::R to an ordinary + type, rather than a typename type. + + The reason we normally avoid resolving TYPENAME_TYPEs + is that a specialization of `S' might render + `S<T>::R' not a type. However, if `S' is + specialized, then this `i' will not be used, so there + is no harm in resolving the types here. */ + if (TREE_CODE (scope) == TYPENAME_TYPE) + { + tree type; + + /* Resolve the TYPENAME_TYPE. */ + type = resolve_typename_type (scope, + /*only_current_p=*/false); + /* If that failed, the declarator is invalid. */ + if (type == error_mark_node) + error ("`%T::%D' is not a type", + TYPE_CONTEXT (scope), + TYPE_IDENTIFIER (scope)); + /* Build a new DECLARATOR. */ + declarator = build_nt (SCOPE_REF, + type, + TREE_OPERAND (declarator, 1)); + } + } + + /* Check to see whether the declarator-id names a constructor, + destructor, or conversion. */ + if (declarator && ctor_dtor_or_conv_p + && ((TREE_CODE (declarator) == SCOPE_REF + && CLASS_TYPE_P (TREE_OPERAND (declarator, 0))) + || (TREE_CODE (declarator) != SCOPE_REF + && at_class_scope_p ()))) + { + tree unqualified_name; + tree class_type; + + /* Get the unqualified part of the name. */ + if (TREE_CODE (declarator) == SCOPE_REF) + { + class_type = TREE_OPERAND (declarator, 0); + unqualified_name = TREE_OPERAND (declarator, 1); + } + else + { + class_type = current_class_type; + unqualified_name = declarator; + } + + /* See if it names ctor, dtor or conv. */ + if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR + || IDENTIFIER_TYPENAME_P (unqualified_name) + || constructor_name_p (unqualified_name, class_type) + || (TREE_CODE (unqualified_name) == TYPE_DECL + && same_type_p (TREE_TYPE (unqualified_name), + class_type))) + *ctor_dtor_or_conv_p = -1; + } + + handle_declarator:; + scope = get_scope_of_declarator (declarator); + if (scope) + /* Any names that appear after the declarator-id for a + member are looked up in the containing scope. */ + pop_p = push_scope (scope); + parser->in_declarator_p = true; + if ((ctor_dtor_or_conv_p && *ctor_dtor_or_conv_p) + || (declarator + && (TREE_CODE (declarator) == SCOPE_REF + || TREE_CODE (declarator) == IDENTIFIER_NODE))) + /* Default args are only allowed on function + declarations. */ + parser->default_arg_ok_p = saved_default_arg_ok_p; + else + parser->default_arg_ok_p = false; + + first = false; + } + /* We're done. */ + else + break; + } + + /* For an abstract declarator, we might wind up with nothing at this + point. That's an error; the declarator is not optional. */ + if (!declarator) + cp_parser_error (parser, "expected declarator"); + + /* If we entered a scope, we must exit it now. */ + if (pop_p) + pop_scope (scope); + + parser->default_arg_ok_p = saved_default_arg_ok_p; + parser->in_declarator_p = saved_in_declarator_p; + + return declarator; +} + +/* Parse a ptr-operator. + + ptr-operator: + * cv-qualifier-seq [opt] + & + :: [opt] nested-name-specifier * cv-qualifier-seq [opt] + + GNU Extension: + + ptr-operator: + & cv-qualifier-seq [opt] + + Returns INDIRECT_REF if a pointer, or pointer-to-member, was + used. Returns ADDR_EXPR if a reference was used. In the + case of a pointer-to-member, *TYPE is filled in with the + TYPE containing the member. *CV_QUALIFIER_SEQ is filled in + with the cv-qualifier-seq, or NULL_TREE, if there are no + cv-qualifiers. Returns ERROR_MARK if an error occurred. */ + +static enum tree_code +cp_parser_ptr_operator (cp_parser* parser, + tree* type, + tree* cv_qualifier_seq) +{ + enum tree_code code = ERROR_MARK; + cp_token *token; + + /* Assume that it's not a pointer-to-member. */ + *type = NULL_TREE; + /* And that there are no cv-qualifiers. */ + *cv_qualifier_seq = NULL_TREE; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's a `*' or `&' we have a pointer or reference. */ + if (token->type == CPP_MULT || token->type == CPP_AND) + { + /* Remember which ptr-operator we were processing. */ + code = (token->type == CPP_AND ? ADDR_EXPR : INDIRECT_REF); + + /* Consume the `*' or `&'. */ + cp_lexer_consume_token (parser->lexer); + + /* A `*' can be followed by a cv-qualifier-seq, and so can a + `&', if we are allowing GNU extensions. (The only qualifier + that can legally appear after `&' is `restrict', but that is + enforced during semantic analysis. */ + if (code == INDIRECT_REF + || cp_parser_allow_gnu_extensions_p (parser)) + *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser); + } + else + { + /* Try the pointer-to-member case. */ + cp_parser_parse_tentatively (parser); + /* Look for the optional `::' operator. */ + cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false); + /* Look for the nested-name specifier. */ + cp_parser_nested_name_specifier (parser, + /*typename_keyword_p=*/false, + /*check_dependency_p=*/true, + /*type_p=*/false, + /*is_declaration=*/false); + /* If we found it, and the next token is a `*', then we are + indeed looking at a pointer-to-member operator. */ + if (!cp_parser_error_occurred (parser) + && cp_parser_require (parser, CPP_MULT, "`*'")) + { + /* The type of which the member is a member is given by the + current SCOPE. */ + *type = parser->scope; + /* The next name will not be qualified. */ + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + /* Indicate that the `*' operator was used. */ + code = INDIRECT_REF; + /* Look for the optional cv-qualifier-seq. */ + *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser); + } + /* If that didn't work we don't have a ptr-operator. */ + if (!cp_parser_parse_definitely (parser)) + cp_parser_error (parser, "expected ptr-operator"); + } + + return code; +} + +/* Parse an (optional) cv-qualifier-seq. + + cv-qualifier-seq: + cv-qualifier cv-qualifier-seq [opt] + + Returns a TREE_LIST. The TREE_VALUE of each node is the + representation of a cv-qualifier. */ + +static tree +cp_parser_cv_qualifier_seq_opt (cp_parser* parser) +{ + tree cv_qualifiers = NULL_TREE; + + while (true) + { + tree cv_qualifier; + + /* Look for the next cv-qualifier. */ + cv_qualifier = cp_parser_cv_qualifier_opt (parser); + /* If we didn't find one, we're done. */ + if (!cv_qualifier) + break; + + /* Add this cv-qualifier to the list. */ + cv_qualifiers + = tree_cons (NULL_TREE, cv_qualifier, cv_qualifiers); + } + + /* We built up the list in reverse order. */ + return nreverse (cv_qualifiers); +} + +/* Parse an (optional) cv-qualifier. + + cv-qualifier: + const + volatile + + GNU Extension: + + cv-qualifier: + __restrict__ */ + +static tree +cp_parser_cv_qualifier_opt (cp_parser* parser) +{ + cp_token *token; + tree cv_qualifier = NULL_TREE; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* See if it's a cv-qualifier. */ + switch (token->keyword) + { + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + /* Save the value of the token. */ + cv_qualifier = token->value; + /* Consume the token. */ + cp_lexer_consume_token (parser->lexer); + break; + + default: + break; + } + + return cv_qualifier; +} + +/* Parse a declarator-id. + + declarator-id: + id-expression + :: [opt] nested-name-specifier [opt] type-name + + In the `id-expression' case, the value returned is as for + cp_parser_id_expression if the id-expression was an unqualified-id. + If the id-expression was a qualified-id, then a SCOPE_REF is + returned. The first operand is the scope (either a NAMESPACE_DECL + or TREE_TYPE), but the second is still just a representation of an + unqualified-id. */ + +static tree +cp_parser_declarator_id (cp_parser* parser) +{ + tree id_expression; + + /* The expression must be an id-expression. Assume that qualified + names are the names of types so that: + + template <class T> + int S<T>::R::i = 3; + + will work; we must treat `S<T>::R' as the name of a type. + Similarly, assume that qualified names are templates, where + required, so that: + + template <class T> + int S<T>::R<T>::i = 3; + + will work, too. */ + id_expression = cp_parser_id_expression (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/false, + /*template_p=*/NULL, + /*declarator_p=*/true); + /* If the name was qualified, create a SCOPE_REF to represent + that. */ + if (parser->scope) + { + id_expression = build_nt (SCOPE_REF, parser->scope, id_expression); + parser->scope = NULL_TREE; + } + + return id_expression; +} + +/* Parse a type-id. + + type-id: + type-specifier-seq abstract-declarator [opt] + + Returns the TYPE specified. */ + +static tree +cp_parser_type_id (cp_parser* parser) +{ + tree type_specifier_seq; + tree abstract_declarator; + + /* Parse the type-specifier-seq. */ + type_specifier_seq + = cp_parser_type_specifier_seq (parser); + if (type_specifier_seq == error_mark_node) + return error_mark_node; + + /* There might or might not be an abstract declarator. */ + cp_parser_parse_tentatively (parser); + /* Look for the declarator. */ + abstract_declarator + = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL, + /*parenthesized_p=*/NULL); + /* Check to see if there really was a declarator. */ + if (!cp_parser_parse_definitely (parser)) + abstract_declarator = NULL_TREE; + + return groktypename (build_tree_list (type_specifier_seq, + abstract_declarator)); +} + +/* Parse a type-specifier-seq. + + type-specifier-seq: + type-specifier type-specifier-seq [opt] + + GNU extension: + + type-specifier-seq: + attributes type-specifier-seq [opt] + + Returns a TREE_LIST. Either the TREE_VALUE of each node is a + type-specifier, or the TREE_PURPOSE is a list of attributes. */ + +static tree +cp_parser_type_specifier_seq (cp_parser* parser) +{ + bool seen_type_specifier = false; + tree type_specifier_seq = NULL_TREE; + + /* Parse the type-specifiers and attributes. */ + while (true) + { + tree type_specifier; + + /* Check for attributes first. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + { + type_specifier_seq = tree_cons (cp_parser_attributes_opt (parser), + NULL_TREE, + type_specifier_seq); + continue; + } + + /* After the first type-specifier, others are optional. */ + if (seen_type_specifier) + cp_parser_parse_tentatively (parser); + /* Look for the type-specifier. */ + type_specifier = cp_parser_type_specifier (parser, + CP_PARSER_FLAGS_NONE, + /*is_friend=*/false, + /*is_declaration=*/false, + NULL, + NULL); + /* If the first type-specifier could not be found, this is not a + type-specifier-seq at all. */ + if (!seen_type_specifier && type_specifier == error_mark_node) + return error_mark_node; + /* If subsequent type-specifiers could not be found, the + type-specifier-seq is complete. */ + else if (seen_type_specifier && !cp_parser_parse_definitely (parser)) + break; + + /* Add the new type-specifier to the list. */ + type_specifier_seq + = tree_cons (NULL_TREE, type_specifier, type_specifier_seq); + seen_type_specifier = true; + } + + /* We built up the list in reverse order. */ + return nreverse (type_specifier_seq); +} + +/* Parse a parameter-declaration-clause. + + parameter-declaration-clause: + parameter-declaration-list [opt] ... [opt] + parameter-declaration-list , ... + + Returns a representation for the parameter declarations. Each node + is a TREE_LIST. (See cp_parser_parameter_declaration for the exact + representation.) If the parameter-declaration-clause ends with an + ellipsis, PARMLIST_ELLIPSIS_P will hold of the first node in the + list. A return value of NULL_TREE indicates a + parameter-declaration-clause consisting only of an ellipsis. */ + +static tree +cp_parser_parameter_declaration_clause (cp_parser* parser) +{ + tree parameters; + cp_token *token; + bool ellipsis_p; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* Check for trivial parameter-declaration-clauses. */ + if (token->type == CPP_ELLIPSIS) + { + /* Consume the `...' token. */ + cp_lexer_consume_token (parser->lexer); + return NULL_TREE; + } + else if (token->type == CPP_CLOSE_PAREN) + /* There are no parameters. */ + { +#ifndef NO_IMPLICIT_EXTERN_C + if (in_system_header && current_class_type == NULL + && current_lang_name == lang_name_c) + return NULL_TREE; + else +#endif + return void_list_node; + } + /* Check for `(void)', too, which is a special case. */ + else if (token->keyword == RID_VOID + && (cp_lexer_peek_nth_token (parser->lexer, 2)->type + == CPP_CLOSE_PAREN)) + { + /* Consume the `void' token. */ + cp_lexer_consume_token (parser->lexer); + /* There are no parameters. */ + return void_list_node; + } + + /* Parse the parameter-declaration-list. */ + parameters = cp_parser_parameter_declaration_list (parser); + /* If a parse error occurred while parsing the + parameter-declaration-list, then the entire + parameter-declaration-clause is erroneous. */ + if (parameters == error_mark_node) + return error_mark_node; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's a `,', the clause should terminate with an ellipsis. */ + if (token->type == CPP_COMMA) + { + /* Consume the `,'. */ + cp_lexer_consume_token (parser->lexer); + /* Expect an ellipsis. */ + ellipsis_p + = (cp_parser_require (parser, CPP_ELLIPSIS, "`...'") != NULL); + } + /* It might also be `...' if the optional trailing `,' was + omitted. */ + else if (token->type == CPP_ELLIPSIS) + { + /* Consume the `...' token. */ + cp_lexer_consume_token (parser->lexer); + /* And remember that we saw it. */ + ellipsis_p = true; + } + else + ellipsis_p = false; + + /* Finish the parameter list. */ + return finish_parmlist (parameters, ellipsis_p); +} + +/* Parse a parameter-declaration-list. + + parameter-declaration-list: + parameter-declaration + parameter-declaration-list , parameter-declaration + + Returns a representation of the parameter-declaration-list, as for + cp_parser_parameter_declaration_clause. However, the + `void_list_node' is never appended to the list. */ + +static tree +cp_parser_parameter_declaration_list (cp_parser* parser) +{ + tree parameters = NULL_TREE; + + /* Look for more parameters. */ + while (true) + { + tree parameter; + bool parenthesized_p; + /* Parse the parameter. */ + parameter + = cp_parser_parameter_declaration (parser, + /*template_parm_p=*/false, + &parenthesized_p); + + /* If a parse error occurred parsing the parameter declaration, + then the entire parameter-declaration-list is erroneous. */ + if (parameter == error_mark_node) + { + parameters = error_mark_node; + break; + } + /* Add the new parameter to the list. */ + TREE_CHAIN (parameter) = parameters; + parameters = parameter; + + /* Peek at the next token. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN) + || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + /* The parameter-declaration-list is complete. */ + break; + else if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + cp_token *token; + + /* Peek at the next token. */ + token = cp_lexer_peek_nth_token (parser->lexer, 2); + /* If it's an ellipsis, then the list is complete. */ + if (token->type == CPP_ELLIPSIS) + break; + /* Otherwise, there must be more parameters. Consume the + `,'. */ + cp_lexer_consume_token (parser->lexer); + /* When parsing something like: + + int i(float f, double d) + + we can tell after seeing the declaration for "f" that we + are not looking at an initialization of a variable "i", + but rather at the declaration of a function "i". + + Due to the fact that the parsing of template arguments + (as specified to a template-id) requires backtracking we + cannot use this technique when inside a template argument + list. */ + if (!parser->in_template_argument_list_p + && !parser->in_type_id_in_expr_p + && cp_parser_parsing_tentatively (parser) + && !cp_parser_committed_to_tentative_parse (parser) + /* However, a parameter-declaration of the form + "foat(f)" (which is a valid declaration of a + parameter "f") can also be interpreted as an + expression (the conversion of "f" to "float"). */ + && !parenthesized_p) + cp_parser_commit_to_tentative_parse (parser); + } + else + { + cp_parser_error (parser, "expected `,' or `...'"); + if (!cp_parser_parsing_tentatively (parser) + || cp_parser_committed_to_tentative_parse (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/false); + break; + } + } + + /* We built up the list in reverse order; straighten it out now. */ + return nreverse (parameters); +} + +/* Parse a parameter declaration. + + parameter-declaration: + decl-specifier-seq declarator + decl-specifier-seq declarator = assignment-expression + decl-specifier-seq abstract-declarator [opt] + decl-specifier-seq abstract-declarator [opt] = assignment-expression + + If TEMPLATE_PARM_P is TRUE, then this parameter-declaration + declares a template parameter. (In that case, a non-nested `>' + token encountered during the parsing of the assignment-expression + is not interpreted as a greater-than operator.) + + Returns a TREE_LIST representing the parameter-declaration. The + TREE_PURPOSE is the default argument expression, or NULL_TREE if + there is no default argument. The TREE_VALUE is a representation + of the decl-specifier-seq and declarator. In particular, the + TREE_VALUE will be a TREE_LIST whose TREE_PURPOSE represents the + decl-specifier-seq and whose TREE_VALUE represents the declarator. + If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to true iff + the declarator is of the form "(p)". */ + +static tree +cp_parser_parameter_declaration (cp_parser *parser, + bool template_parm_p, + bool *parenthesized_p) +{ + int declares_class_or_enum; + bool greater_than_is_operator_p; + tree decl_specifiers; + tree attributes; + tree declarator; + tree default_argument; + tree parameter; + cp_token *token; + const char *saved_message; + + /* In a template parameter, `>' is not an operator. + + [temp.param] + + When parsing a default template-argument for a non-type + template-parameter, the first non-nested `>' is taken as the end + of the template parameter-list rather than a greater-than + operator. */ + greater_than_is_operator_p = !template_parm_p; + + /* Type definitions may not appear in parameter types. */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = "types may not be defined in parameter types"; + + /* Parse the declaration-specifiers. */ + decl_specifiers + = cp_parser_decl_specifier_seq (parser, + CP_PARSER_FLAGS_NONE, + &attributes, + &declares_class_or_enum); + /* If an error occurred, there's no reason to attempt to parse the + rest of the declaration. */ + if (cp_parser_error_occurred (parser)) + { + parser->type_definition_forbidden_message = saved_message; + return error_mark_node; + } + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If the next token is a `)', `,', `=', `>', or `...', then there + is no declarator. */ + if (token->type == CPP_CLOSE_PAREN + || token->type == CPP_COMMA + || token->type == CPP_EQ + || token->type == CPP_ELLIPSIS + || token->type == CPP_GREATER) + { + declarator = NULL_TREE; + if (parenthesized_p) + *parenthesized_p = false; + } + /* Otherwise, there should be a declarator. */ + else + { + bool saved_default_arg_ok_p = parser->default_arg_ok_p; + parser->default_arg_ok_p = false; + + /* After seeing a decl-specifier-seq, if the next token is not a + "(", there is no possibility that the code is a valid + expression. Therefore, if parsing tentatively, we commit at + this point. */ + if (!parser->in_template_argument_list_p + /* In an expression context, having seen: + + (int((char ... + + we cannot be sure whether we are looking at a + function-type (taking a "char" as a parameter) or a cast + of some object of type "char" to "int". */ + && !parser->in_type_id_in_expr_p + && cp_parser_parsing_tentatively (parser) + && !cp_parser_committed_to_tentative_parse (parser) + && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) + cp_parser_commit_to_tentative_parse (parser); + /* Parse the declarator. */ + declarator = cp_parser_declarator (parser, + CP_PARSER_DECLARATOR_EITHER, + /*ctor_dtor_or_conv_p=*/NULL, + parenthesized_p); + parser->default_arg_ok_p = saved_default_arg_ok_p; + /* After the declarator, allow more attributes. */ + attributes = chainon (attributes, cp_parser_attributes_opt (parser)); + } + + /* The restriction on defining new types applies only to the type + of the parameter, not to the default argument. */ + parser->type_definition_forbidden_message = saved_message; + + /* If the next token is `=', then process a default argument. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + { + bool saved_greater_than_is_operator_p; + /* Consume the `='. */ + cp_lexer_consume_token (parser->lexer); + + /* If we are defining a class, then the tokens that make up the + default argument must be saved and processed later. */ + if (!template_parm_p && at_class_scope_p () + && TYPE_BEING_DEFINED (current_class_type)) + { + unsigned depth = 0; + + /* Create a DEFAULT_ARG to represented the unparsed default + argument. */ + default_argument = make_node (DEFAULT_ARG); + DEFARG_TOKENS (default_argument) = cp_token_cache_new (); + + /* Add tokens until we have processed the entire default + argument. */ + while (true) + { + bool done = false; + cp_token *token; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* What we do depends on what token we have. */ + switch (token->type) + { + /* In valid code, a default argument must be + immediately followed by a `,' `)', or `...'. */ + case CPP_COMMA: + case CPP_CLOSE_PAREN: + case CPP_ELLIPSIS: + /* If we run into a non-nested `;', `}', or `]', + then the code is invalid -- but the default + argument is certainly over. */ + case CPP_SEMICOLON: + case CPP_CLOSE_BRACE: + case CPP_CLOSE_SQUARE: + if (depth == 0) + done = true; + /* Update DEPTH, if necessary. */ + else if (token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_BRACE + || token->type == CPP_CLOSE_SQUARE) + --depth; + break; + + case CPP_OPEN_PAREN: + case CPP_OPEN_SQUARE: + case CPP_OPEN_BRACE: + ++depth; + break; + + case CPP_GREATER: + /* If we see a non-nested `>', and `>' is not an + operator, then it marks the end of the default + argument. */ + if (!depth && !greater_than_is_operator_p) + done = true; + break; + + /* If we run out of tokens, issue an error message. */ + case CPP_EOF: + error ("file ends in default argument"); + done = true; + break; + + case CPP_NAME: + case CPP_SCOPE: + /* In these cases, we should look for template-ids. + For example, if the default argument is + `X<int, double>()', we need to do name lookup to + figure out whether or not `X' is a template; if + so, the `,' does not end the default argument. + + That is not yet done. */ + break; + + default: + break; + } + + /* If we've reached the end, stop. */ + if (done) + break; + + /* Add the token to the token block. */ + token = cp_lexer_consume_token (parser->lexer); + cp_token_cache_push_token (DEFARG_TOKENS (default_argument), + token); + } + } + /* Outside of a class definition, we can just parse the + assignment-expression. */ + else + { + bool saved_local_variables_forbidden_p; + + /* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is + set correctly. */ + saved_greater_than_is_operator_p + = parser->greater_than_is_operator_p; + parser->greater_than_is_operator_p = greater_than_is_operator_p; + /* Local variable names (and the `this' keyword) may not + appear in a default argument. */ + saved_local_variables_forbidden_p + = parser->local_variables_forbidden_p; + parser->local_variables_forbidden_p = true; + /* Parse the assignment-expression. */ + default_argument = cp_parser_assignment_expression (parser); + /* Restore saved state. */ + parser->greater_than_is_operator_p + = saved_greater_than_is_operator_p; + parser->local_variables_forbidden_p + = saved_local_variables_forbidden_p; + } + if (!parser->default_arg_ok_p) + { + if (!flag_pedantic_errors) + warning ("deprecated use of default argument for parameter of non-function"); + else + { + error ("default arguments are only permitted for function parameters"); + default_argument = NULL_TREE; + } + } + } + else + default_argument = NULL_TREE; + + /* Create the representation of the parameter. */ + if (attributes) + decl_specifiers = tree_cons (attributes, NULL_TREE, decl_specifiers); + parameter = build_tree_list (default_argument, + build_tree_list (decl_specifiers, + declarator)); + + return parameter; +} + +/* Parse a function-body. + + function-body: + compound_statement */ + +static void +cp_parser_function_body (cp_parser *parser) +{ + cp_parser_compound_statement (parser, false); +} + +/* Parse a ctor-initializer-opt followed by a function-body. Return + true if a ctor-initializer was present. */ + +static bool +cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser) +{ + tree body; + bool ctor_initializer_p; + + /* Begin the function body. */ + body = begin_function_body (); + /* Parse the optional ctor-initializer. */ + ctor_initializer_p = cp_parser_ctor_initializer_opt (parser); + /* Parse the function-body. */ + cp_parser_function_body (parser); + /* Finish the function body. */ + finish_function_body (body); + + return ctor_initializer_p; +} + +/* Parse an initializer. + + initializer: + = initializer-clause + ( expression-list ) + + Returns a expression representing the initializer. If no + initializer is present, NULL_TREE is returned. + + *IS_PARENTHESIZED_INIT is set to TRUE if the `( expression-list )' + production is used, and zero otherwise. *IS_PARENTHESIZED_INIT is + set to FALSE if there is no initializer present. If there is an + initializer, and it is not a constant-expression, *NON_CONSTANT_P + is set to true; otherwise it is set to false. */ + +static tree +cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init, + bool* non_constant_p) +{ + cp_token *token; + tree init; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + /* Let our caller know whether or not this initializer was + parenthesized. */ + *is_parenthesized_init = (token->type == CPP_OPEN_PAREN); + /* Assume that the initializer is constant. */ + *non_constant_p = false; + + if (token->type == CPP_EQ) + { + /* Consume the `='. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the initializer-clause. */ + init = cp_parser_initializer_clause (parser, non_constant_p); + } + else if (token->type == CPP_OPEN_PAREN) + init = cp_parser_parenthesized_expression_list (parser, false, + non_constant_p); + else + { + /* Anything else is an error. */ + cp_parser_error (parser, "expected initializer"); + init = error_mark_node; + } + + return init; +} + +/* Parse an initializer-clause. + + initializer-clause: + assignment-expression + { initializer-list , [opt] } + { } + + Returns an expression representing the initializer. + + If the `assignment-expression' production is used the value + returned is simply a representation for the expression. + + Otherwise, a CONSTRUCTOR is returned. The CONSTRUCTOR_ELTS will be + the elements of the initializer-list (or NULL_TREE, if the last + production is used). The TREE_TYPE for the CONSTRUCTOR will be + NULL_TREE. There is no way to detect whether or not the optional + trailing `,' was provided. NON_CONSTANT_P is as for + cp_parser_initializer. */ + +static tree +cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) +{ + tree initializer; + + /* If it is not a `{', then we are looking at an + assignment-expression. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) + { + initializer + = cp_parser_constant_expression (parser, + /*allow_non_constant_p=*/true, + non_constant_p); + if (!*non_constant_p) + initializer = fold_non_dependent_expr (initializer); + } + else + { + /* Consume the `{' token. */ + cp_lexer_consume_token (parser->lexer); + /* Create a CONSTRUCTOR to represent the braced-initializer. */ + initializer = make_node (CONSTRUCTOR); + /* Mark it with TREE_HAS_CONSTRUCTOR. This should not be + necessary, but check_initializer depends upon it, for + now. */ + TREE_HAS_CONSTRUCTOR (initializer) = 1; + /* If it's not a `}', then there is a non-trivial initializer. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE)) + { + /* Parse the initializer list. */ + CONSTRUCTOR_ELTS (initializer) + = cp_parser_initializer_list (parser, non_constant_p); + /* A trailing `,' token is allowed. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + } + /* Now, there should be a trailing `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); + } + + return initializer; +} + +/* Parse an initializer-list. + + initializer-list: + initializer-clause + initializer-list , initializer-clause + + GNU Extension: + + initializer-list: + identifier : initializer-clause + initializer-list, identifier : initializer-clause + + Returns a TREE_LIST. The TREE_VALUE of each node is an expression + for the initializer. If the TREE_PURPOSE is non-NULL, it is the + IDENTIFIER_NODE naming the field to initialize. NON_CONSTANT_P is + as for cp_parser_initializer. */ + +static tree +cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) +{ + tree initializers = NULL_TREE; + + /* Assume all of the expressions are constant. */ + *non_constant_p = false; + + /* Parse the rest of the list. */ + while (true) + { + cp_token *token; + tree identifier; + tree initializer; + bool clause_non_constant_p; + + /* If the next token is an identifier and the following one is a + colon, we are looking at the GNU designated-initializer + syntax. */ + if (cp_parser_allow_gnu_extensions_p (parser) + && cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) + { + /* Consume the identifier. */ + identifier = cp_lexer_consume_token (parser->lexer)->value; + /* Consume the `:'. */ + cp_lexer_consume_token (parser->lexer); + } + else + identifier = NULL_TREE; + + /* Parse the initializer. */ + initializer = cp_parser_initializer_clause (parser, + &clause_non_constant_p); + /* If any clause is non-constant, so is the entire initializer. */ + if (clause_non_constant_p) + *non_constant_p = true; + /* Add it to the list. */ + initializers = tree_cons (identifier, initializer, initializers); + + /* If the next token is not a comma, we have reached the end of + the list. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + + /* Peek at the next token. */ + token = cp_lexer_peek_nth_token (parser->lexer, 2); + /* If the next token is a `}', then we're still done. An + initializer-clause can have a trailing `,' after the + initializer-list and before the closing `}'. */ + if (token->type == CPP_CLOSE_BRACE) + break; + + /* Consume the `,' token. */ + cp_lexer_consume_token (parser->lexer); + } + + /* The initializers were built up in reverse order, so we need to + reverse them now. */ + return nreverse (initializers); +} + +/* Classes [gram.class] */ + +/* Parse a class-name. + + class-name: + identifier + template-id + + TYPENAME_KEYWORD_P is true iff the `typename' keyword has been used + to indicate that names looked up in dependent types should be + assumed to be types. TEMPLATE_KEYWORD_P is true iff the `template' + keyword has been used to indicate that the name that appears next + is a template. TYPE_P is true iff the next name should be treated + as class-name, even if it is declared to be some other kind of name + as well. If CHECK_DEPENDENCY_P is FALSE, names are looked up in + dependent scopes. If CLASS_HEAD_P is TRUE, this class is the class + being defined in a class-head. + + Returns the TYPE_DECL representing the class. */ + +static tree +cp_parser_class_name (cp_parser *parser, + bool typename_keyword_p, + bool template_keyword_p, + bool type_p, + bool check_dependency_p, + bool class_head_p, + bool is_declaration) +{ + tree decl; + tree scope; + bool typename_p; + cp_token *token; + + /* All class-names start with an identifier. */ + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_NAME && token->type != CPP_TEMPLATE_ID) + { + cp_parser_error (parser, "expected class-name"); + return error_mark_node; + } + + /* PARSER->SCOPE can be cleared when parsing the template-arguments + to a template-id, so we save it here. */ + scope = parser->scope; + if (scope == error_mark_node) + return error_mark_node; + + /* Any name names a type if we're following the `typename' keyword + in a qualified name where the enclosing scope is type-dependent. */ + typename_p = (typename_keyword_p && scope && TYPE_P (scope) + && dependent_type_p (scope)); + /* Handle the common case (an identifier, but not a template-id) + efficiently. */ + if (token->type == CPP_NAME + && !cp_parser_nth_token_starts_template_argument_list_p (parser, 2)) + { + tree identifier; + + /* Look for the identifier. */ + identifier = cp_parser_identifier (parser); + /* If the next token isn't an identifier, we are certainly not + looking at a class-name. */ + if (identifier == error_mark_node) + decl = error_mark_node; + /* If we know this is a type-name, there's no need to look it + up. */ + else if (typename_p) + decl = identifier; + else + { + /* If the next token is a `::', then the name must be a type + name. + + [basic.lookup.qual] + + During the lookup for a name preceding the :: scope + resolution operator, object, function, and enumerator + names are ignored. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) + type_p = true; + /* Look up the name. */ + decl = cp_parser_lookup_name (parser, identifier, + type_p, + /*is_template=*/false, + /*is_namespace=*/false, + check_dependency_p); + } + } + else + { + /* Try a template-id. */ + decl = cp_parser_template_id (parser, template_keyword_p, + check_dependency_p, + is_declaration); + if (decl == error_mark_node) + return error_mark_node; + } + + decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p); + + /* If this is a typename, create a TYPENAME_TYPE. */ + if (typename_p && decl != error_mark_node) + { + decl = make_typename_type (scope, decl, /*complain=*/1); + if (decl != error_mark_node) + decl = TYPE_NAME (decl); + } + + /* Check to see that it is really the name of a class. */ + if (TREE_CODE (decl) == TEMPLATE_ID_EXPR + && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE + && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) + /* Situations like this: + + template <typename T> struct A { + typename T::template X<int>::I i; + }; + + are problematic. Is `T::template X<int>' a class-name? The + standard does not seem to be definitive, but there is no other + valid interpretation of the following `::'. Therefore, those + names are considered class-names. */ + decl = TYPE_NAME (make_typename_type (scope, decl, tf_error)); + else if (decl == error_mark_node + || TREE_CODE (decl) != TYPE_DECL + || !IS_AGGR_TYPE (TREE_TYPE (decl))) + { + cp_parser_error (parser, "expected class-name"); + return error_mark_node; + } + + return decl; +} + +/* Parse a class-specifier. + + class-specifier: + class-head { member-specification [opt] } + + Returns the TREE_TYPE representing the class. */ + +static tree +cp_parser_class_specifier (cp_parser* parser) +{ + cp_token *token; + tree type; + tree attributes; + int has_trailing_semicolon; + bool nested_name_specifier_p; + unsigned saved_num_template_parameter_lists; + bool pop_p = false; + + push_deferring_access_checks (dk_no_deferred); + + /* Parse the class-head. */ + type = cp_parser_class_head (parser, + &nested_name_specifier_p, + &attributes); + /* If the class-head was a semantic disaster, skip the entire body + of the class. */ + if (!type) + { + cp_parser_skip_to_end_of_block_or_statement (parser); + pop_deferring_access_checks (); + return error_mark_node; + } + + /* Look for the `{'. */ + if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'")) + { + pop_deferring_access_checks (); + return error_mark_node; + } + + /* Issue an error message if type-definitions are forbidden here. */ + cp_parser_check_type_definition (parser); + /* Remember that we are defining one more class. */ + ++parser->num_classes_being_defined; + /* Inside the class, surrounding template-parameter-lists do not + apply. */ + saved_num_template_parameter_lists + = parser->num_template_parameter_lists; + parser->num_template_parameter_lists = 0; + + /* Start the class. */ + if (nested_name_specifier_p) + pop_p = push_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (type))); + type = begin_class_definition (type); + if (type == error_mark_node) + /* If the type is erroneous, skip the entire body of the class. */ + cp_parser_skip_to_closing_brace (parser); + else + /* Parse the member-specification. */ + cp_parser_member_specification_opt (parser); + /* Look for the trailing `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); + /* We get better error messages by noticing a common problem: a + missing trailing `;'. */ + token = cp_lexer_peek_token (parser->lexer); + has_trailing_semicolon = (token->type == CPP_SEMICOLON); + /* Look for trailing attributes to apply to this class. */ + if (cp_parser_allow_gnu_extensions_p (parser)) + { + tree sub_attr = cp_parser_attributes_opt (parser); + attributes = chainon (attributes, sub_attr); + } + if (type != error_mark_node) + type = finish_struct (type, attributes); + if (pop_p) + pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (type))); + /* If this class is not itself within the scope of another class, + then we need to parse the bodies of all of the queued function + definitions. Note that the queued functions defined in a class + are not always processed immediately following the + class-specifier for that class. Consider: + + struct A { + struct B { void f() { sizeof (A); } }; + }; + + If `f' were processed before the processing of `A' were + completed, there would be no way to compute the size of `A'. + Note that the nesting we are interested in here is lexical -- + not the semantic nesting given by TYPE_CONTEXT. In particular, + for: + + struct A { struct B; }; + struct A::B { void f() { } }; + + there is no need to delay the parsing of `A::B::f'. */ + if (--parser->num_classes_being_defined == 0) + { + tree queue_entry; + tree fn; + + /* In a first pass, parse default arguments to the functions. + Then, in a second pass, parse the bodies of the functions. + This two-phased approach handles cases like: + + struct S { + void f() { g(); } + void g(int i = 3); + }; + + */ + for (TREE_PURPOSE (parser->unparsed_functions_queues) + = nreverse (TREE_PURPOSE (parser->unparsed_functions_queues)); + (queue_entry = TREE_PURPOSE (parser->unparsed_functions_queues)); + TREE_PURPOSE (parser->unparsed_functions_queues) + = TREE_CHAIN (TREE_PURPOSE (parser->unparsed_functions_queues))) + { + fn = TREE_VALUE (queue_entry); + /* Make sure that any template parameters are in scope. */ + maybe_begin_member_template_processing (fn); + /* If there are default arguments that have not yet been processed, + take care of them now. */ + cp_parser_late_parsing_default_args (parser, fn); + /* Remove any template parameters from the symbol table. */ + maybe_end_member_template_processing (); + } + /* Now parse the body of the functions. */ + for (TREE_VALUE (parser->unparsed_functions_queues) + = nreverse (TREE_VALUE (parser->unparsed_functions_queues)); + (queue_entry = TREE_VALUE (parser->unparsed_functions_queues)); + TREE_VALUE (parser->unparsed_functions_queues) + = TREE_CHAIN (TREE_VALUE (parser->unparsed_functions_queues))) + { + /* Figure out which function we need to process. */ + fn = TREE_VALUE (queue_entry); + + /* A hack to prevent garbage collection. */ + function_depth++; + + /* Parse the function. */ + cp_parser_late_parsing_for_member (parser, fn); + function_depth--; + } + + } + + /* Put back any saved access checks. */ + pop_deferring_access_checks (); + + /* Restore the count of active template-parameter-lists. */ + parser->num_template_parameter_lists + = saved_num_template_parameter_lists; + + return type; +} + +/* Parse a class-head. + + class-head: + class-key identifier [opt] base-clause [opt] + class-key nested-name-specifier identifier base-clause [opt] + class-key nested-name-specifier [opt] template-id + base-clause [opt] + + GNU Extensions: + class-key attributes identifier [opt] base-clause [opt] + class-key attributes nested-name-specifier identifier base-clause [opt] + class-key attributes nested-name-specifier [opt] template-id + base-clause [opt] + + Returns the TYPE of the indicated class. Sets + *NESTED_NAME_SPECIFIER_P to TRUE iff one of the productions + involving a nested-name-specifier was used, and FALSE otherwise. + + Returns NULL_TREE if the class-head is syntactically valid, but + semantically invalid in a way that means we should skip the entire + body of the class. */ + +static tree +cp_parser_class_head (cp_parser* parser, + bool* nested_name_specifier_p, + tree *attributes_p) +{ + cp_token *token; + tree nested_name_specifier; + enum tag_types class_key; + tree id = NULL_TREE; + tree type = NULL_TREE; + tree attributes; + bool template_id_p = false; + bool qualified_p = false; + bool invalid_nested_name_p = false; + bool invalid_explicit_specialization_p = false; + bool pop_p = false; + unsigned num_templates; + + /* Assume no nested-name-specifier will be present. */ + *nested_name_specifier_p = false; + /* Assume no template parameter lists will be used in defining the + type. */ + num_templates = 0; + + /* Look for the class-key. */ + class_key = cp_parser_class_key (parser); + if (class_key == none_type) + return error_mark_node; + + /* Parse the attributes. */ + attributes = cp_parser_attributes_opt (parser); + + /* If the next token is `::', that is invalid -- but sometimes + people do try to write: + + struct ::S {}; + + Handle this gracefully by accepting the extra qualifier, and then + issuing an error about it later if this really is a + class-head. If it turns out just to be an elaborated type + specifier, remain silent. */ + if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false)) + qualified_p = true; + + push_deferring_access_checks (dk_no_check); + + /* Determine the name of the class. Begin by looking for an + optional nested-name-specifier. */ + nested_name_specifier + = cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/false, + /*check_dependency_p=*/false, + /*type_p=*/false, + /*is_declaration=*/false); + /* If there was a nested-name-specifier, then there *must* be an + identifier. */ + if (nested_name_specifier) + { + /* Although the grammar says `identifier', it really means + `class-name' or `template-name'. You are only allowed to + define a class that has already been declared with this + syntax. + + The proposed resolution for Core Issue 180 says that whever + you see `class T::X' you should treat `X' as a type-name. + + It is OK to define an inaccessible class; for example: + + class A { class B; }; + class A::B {}; + + We do not know if we will see a class-name, or a + template-name. We look for a class-name first, in case the + class-name is a template-id; if we looked for the + template-name first we would stop after the template-name. */ + cp_parser_parse_tentatively (parser); + type = cp_parser_class_name (parser, + /*typename_keyword_p=*/false, + /*template_keyword_p=*/false, + /*type_p=*/true, + /*check_dependency_p=*/false, + /*class_head_p=*/true, + /*is_declaration=*/false); + /* If that didn't work, ignore the nested-name-specifier. */ + if (!cp_parser_parse_definitely (parser)) + { + invalid_nested_name_p = true; + id = cp_parser_identifier (parser); + if (id == error_mark_node) + id = NULL_TREE; + } + /* If we could not find a corresponding TYPE, treat this + declaration like an unqualified declaration. */ + if (type == error_mark_node) + nested_name_specifier = NULL_TREE; + /* Otherwise, count the number of templates used in TYPE and its + containing scopes. */ + else + { + tree scope; + + for (scope = TREE_TYPE (type); + scope && TREE_CODE (scope) != NAMESPACE_DECL; + scope = (TYPE_P (scope) + ? TYPE_CONTEXT (scope) + : DECL_CONTEXT (scope))) + if (TYPE_P (scope) + && CLASS_TYPE_P (scope) + && CLASSTYPE_TEMPLATE_INFO (scope) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)) + && !CLASSTYPE_TEMPLATE_SPECIALIZATION (scope)) + ++num_templates; + } + } + /* Otherwise, the identifier is optional. */ + else + { + /* We don't know whether what comes next is a template-id, + an identifier, or nothing at all. */ + cp_parser_parse_tentatively (parser); + /* Check for a template-id. */ + id = cp_parser_template_id (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/true, + /*is_declaration=*/true); + /* If that didn't work, it could still be an identifier. */ + if (!cp_parser_parse_definitely (parser)) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + id = cp_parser_identifier (parser); + else + id = NULL_TREE; + } + else + { + template_id_p = true; + ++num_templates; + } + } + + pop_deferring_access_checks (); + + if (id) + cp_parser_check_for_invalid_template_id (parser, id); + + /* If it's not a `:' or a `{' then we can't really be looking at a + class-head, since a class-head only appears as part of a + class-specifier. We have to detect this situation before calling + xref_tag, since that has irreversible side-effects. */ + if (!cp_parser_next_token_starts_class_definition_p (parser)) + { + cp_parser_error (parser, "expected `{' or `:'"); + return error_mark_node; + } + + /* At this point, we're going ahead with the class-specifier, even + if some other problem occurs. */ + cp_parser_commit_to_tentative_parse (parser); + /* Issue the error about the overly-qualified name now. */ + if (qualified_p) + cp_parser_error (parser, + "global qualification of class name is invalid"); + else if (invalid_nested_name_p) + cp_parser_error (parser, + "qualified name does not name a class"); + else if (nested_name_specifier) + { + tree scope; + /* Figure out in what scope the declaration is being placed. */ + scope = current_scope (); + if (!scope) + scope = current_namespace; + /* If that scope does not contain the scope in which the + class was originally declared, the program is invalid. */ + if (scope && !is_ancestor (scope, nested_name_specifier)) + { + error ("declaration of `%D' in `%D' which does not " + "enclose `%D'", type, scope, nested_name_specifier); + type = NULL_TREE; + goto done; + } + /* [dcl.meaning] + + A declarator-id shall not be qualified exception of the + definition of a ... nested class outside of its class + ... [or] a the definition or explicit instantiation of a + class member of a namespace outside of its namespace. */ + if (scope == nested_name_specifier) + { + pedwarn ("extra qualification ignored"); + nested_name_specifier = NULL_TREE; + num_templates = 0; + } + } + /* An explicit-specialization must be preceded by "template <>". If + it is not, try to recover gracefully. */ + if (at_namespace_scope_p () + && parser->num_template_parameter_lists == 0 + && template_id_p) + { + error ("an explicit specialization must be preceded by 'template <>'"); + invalid_explicit_specialization_p = true; + /* Take the same action that would have been taken by + cp_parser_explicit_specialization. */ + ++parser->num_template_parameter_lists; + begin_specialization (); + } + /* There must be no "return" statements between this point and the + end of this function; set "type "to the correct return value and + use "goto done;" to return. */ + /* Make sure that the right number of template parameters were + present. */ + if (!cp_parser_check_template_parameters (parser, num_templates)) + { + /* If something went wrong, there is no point in even trying to + process the class-definition. */ + type = NULL_TREE; + goto done; + } + + /* Look up the type. */ + if (template_id_p) + { + type = TREE_TYPE (id); + maybe_process_partial_specialization (type); + } + else if (!nested_name_specifier) + { + /* If the class was unnamed, create a dummy name. */ + if (!id) + id = make_anon_name (); + type = xref_tag (class_key, id, /*globalize=*/false, + parser->num_template_parameter_lists); + } + else + { + tree class_type; + bool pop_p = false; + + /* Given: + + template <typename T> struct S { struct T }; + template <typename T> struct S<T>::T { }; + + we will get a TYPENAME_TYPE when processing the definition of + `S::T'. We need to resolve it to the actual type before we + try to define it. */ + if (TREE_CODE (TREE_TYPE (type)) == TYPENAME_TYPE) + { + class_type = resolve_typename_type (TREE_TYPE (type), + /*only_current_p=*/false); + if (class_type != error_mark_node) + type = TYPE_NAME (class_type); + else + { + cp_parser_error (parser, "could not resolve typename type"); + type = error_mark_node; + } + } + + maybe_process_partial_specialization (TREE_TYPE (type)); + class_type = current_class_type; + /* Enter the scope indicated by the nested-name-specifier. */ + if (nested_name_specifier) + pop_p = push_scope (nested_name_specifier); + /* Get the canonical version of this type. */ + type = TYPE_MAIN_DECL (TREE_TYPE (type)); + if (PROCESSING_REAL_TEMPLATE_DECL_P () + && !CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (type))) + type = push_template_decl (type); + type = TREE_TYPE (type); + if (nested_name_specifier) + { + *nested_name_specifier_p = true; + if (pop_p) + pop_scope (nested_name_specifier); + } + } + /* Indicate whether this class was declared as a `class' or as a + `struct'. */ + if (TREE_CODE (type) == RECORD_TYPE) + CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type); + cp_parser_check_class_key (class_key, type); + + /* Enter the scope containing the class; the names of base classes + should be looked up in that context. For example, given: + + struct A { struct B {}; struct C; }; + struct A::C : B {}; + + is valid. */ + if (nested_name_specifier) + pop_p = push_scope (nested_name_specifier); + /* Now, look for the base-clause. */ + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_COLON) + { + tree bases; + + /* Get the list of base-classes. */ + bases = cp_parser_base_clause (parser); + /* Process them. */ + xref_basetypes (type, bases); + } + /* Leave the scope given by the nested-name-specifier. We will + enter the class scope itself while processing the members. */ + if (pop_p) + pop_scope (nested_name_specifier); + + done: + if (invalid_explicit_specialization_p) + { + end_specialization (); + --parser->num_template_parameter_lists; + } + *attributes_p = attributes; + return type; +} + +/* Parse a class-key. + + class-key: + class + struct + union + + Returns the kind of class-key specified, or none_type to indicate + error. */ + +static enum tag_types +cp_parser_class_key (cp_parser* parser) +{ + cp_token *token; + enum tag_types tag_type; + + /* Look for the class-key. */ + token = cp_parser_require (parser, CPP_KEYWORD, "class-key"); + if (!token) + return none_type; + + /* Check to see if the TOKEN is a class-key. */ + tag_type = cp_parser_token_is_class_key (token); + if (!tag_type) + cp_parser_error (parser, "expected class-key"); + return tag_type; +} + +/* Parse an (optional) member-specification. + + member-specification: + member-declaration member-specification [opt] + access-specifier : member-specification [opt] */ + +static void +cp_parser_member_specification_opt (cp_parser* parser) +{ + while (true) + { + cp_token *token; + enum rid keyword; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's a `}', or EOF then we've seen all the members. */ + if (token->type == CPP_CLOSE_BRACE || token->type == CPP_EOF) + break; + + /* See if this token is a keyword. */ + keyword = token->keyword; + switch (keyword) + { + case RID_PUBLIC: + case RID_PROTECTED: + case RID_PRIVATE: + /* Consume the access-specifier. */ + cp_lexer_consume_token (parser->lexer); + /* Remember which access-specifier is active. */ + current_access_specifier = token->value; + /* Look for the `:'. */ + cp_parser_require (parser, CPP_COLON, "`:'"); + break; + + default: + /* Otherwise, the next construction must be a + member-declaration. */ + cp_parser_member_declaration (parser); + } + } +} + +/* Parse a member-declaration. + + member-declaration: + decl-specifier-seq [opt] member-declarator-list [opt] ; + function-definition ; [opt] + :: [opt] nested-name-specifier template [opt] unqualified-id ; + using-declaration + template-declaration + + member-declarator-list: + member-declarator + member-declarator-list , member-declarator + + member-declarator: + declarator pure-specifier [opt] + declarator constant-initializer [opt] + identifier [opt] : constant-expression + + GNU Extensions: + + member-declaration: + __extension__ member-declaration + + member-declarator: + declarator attributes [opt] pure-specifier [opt] + declarator attributes [opt] constant-initializer [opt] + identifier [opt] attributes [opt] : constant-expression */ + +static void +cp_parser_member_declaration (cp_parser* parser) +{ + tree decl_specifiers; + tree prefix_attributes; + tree decl; + int declares_class_or_enum; + bool friend_p; + cp_token *token; + int saved_pedantic; + + /* Check for the `__extension__' keyword. */ + if (cp_parser_extension_opt (parser, &saved_pedantic)) + { + /* Recurse. */ + cp_parser_member_declaration (parser); + /* Restore the old value of the PEDANTIC flag. */ + pedantic = saved_pedantic; + + return; + } + + /* Check for a template-declaration. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + { + /* Parse the template-declaration. */ + cp_parser_template_declaration (parser, /*member_p=*/true); + + return; + } + + /* Check for a using-declaration. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING)) + { + /* Parse the using-declaration. */ + cp_parser_using_declaration (parser); + + return; + } + + /* Parse the decl-specifier-seq. */ + decl_specifiers + = cp_parser_decl_specifier_seq (parser, + CP_PARSER_FLAGS_OPTIONAL, + &prefix_attributes, + &declares_class_or_enum); + /* Check for an invalid type-name. */ + if (cp_parser_diagnose_invalid_type_name (parser)) + return; + /* If there is no declarator, then the decl-specifier-seq should + specify a type. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + /* If there was no decl-specifier-seq, and the next token is a + `;', then we have something like: + + struct S { ; }; + + [class.mem] + + Each member-declaration shall declare at least one member + name of the class. */ + if (!decl_specifiers) + { + if (pedantic) + pedwarn ("extra semicolon"); + } + else + { + tree type; + + /* See if this declaration is a friend. */ + friend_p = cp_parser_friend_p (decl_specifiers); + /* If there were decl-specifiers, check to see if there was + a class-declaration. */ + type = check_tag_decl (decl_specifiers); + /* Nested classes have already been added to the class, but + a `friend' needs to be explicitly registered. */ + if (friend_p) + { + /* If the `friend' keyword was present, the friend must + be introduced with a class-key. */ + if (!declares_class_or_enum) + error ("a class-key must be used when declaring a friend"); + /* In this case: + + template <typename T> struct A { + friend struct A<T>::B; + }; + + A<T>::B will be represented by a TYPENAME_TYPE, and + therefore not recognized by check_tag_decl. */ + if (!type) + { + tree specifier; + + for (specifier = decl_specifiers; + specifier; + specifier = TREE_CHAIN (specifier)) + { + tree s = TREE_VALUE (specifier); + + if (TREE_CODE (s) == IDENTIFIER_NODE) + get_global_value_if_present (s, &type); + if (TREE_CODE (s) == TYPE_DECL) + s = TREE_TYPE (s); + if (TYPE_P (s)) + { + type = s; + break; + } + } + } + if (!type || !TYPE_P (type)) + error ("friend declaration does not name a class or " + "function"); + else + make_friend_class (current_class_type, type, + /*complain=*/true); + } + /* If there is no TYPE, an error message will already have + been issued. */ + else if (!type) + ; + /* An anonymous aggregate has to be handled specially; such + a declaration really declares a data member (with a + particular type), as opposed to a nested class. */ + else if (ANON_AGGR_TYPE_P (type)) + { + /* Remove constructors and such from TYPE, now that we + know it is an anonymous aggregate. */ + fixup_anonymous_aggr (type); + /* And make the corresponding data member. */ + decl = build_decl (FIELD_DECL, NULL_TREE, type); + /* Add it to the class. */ + finish_member_declaration (decl); + } + else + cp_parser_check_access_in_redeclaration (TYPE_NAME (type)); + } + } + else + { + /* See if these declarations will be friends. */ + friend_p = cp_parser_friend_p (decl_specifiers); + + /* Keep going until we hit the `;' at the end of the + declaration. */ + while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + { + tree attributes = NULL_TREE; + tree first_attribute; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + /* Check for a bitfield declaration. */ + if (token->type == CPP_COLON + || (token->type == CPP_NAME + && cp_lexer_peek_nth_token (parser->lexer, 2)->type + == CPP_COLON)) + { + tree identifier; + tree width; + + /* Get the name of the bitfield. Note that we cannot just + check TOKEN here because it may have been invalidated by + the call to cp_lexer_peek_nth_token above. */ + if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON) + identifier = cp_parser_identifier (parser); + else + identifier = NULL_TREE; + + /* Consume the `:' token. */ + cp_lexer_consume_token (parser->lexer); + /* Get the width of the bitfield. */ + width + = cp_parser_constant_expression (parser, + /*allow_non_constant=*/false, + NULL); + + /* Look for attributes that apply to the bitfield. */ + attributes = cp_parser_attributes_opt (parser); + /* Remember which attributes are prefix attributes and + which are not. */ + first_attribute = attributes; + /* Combine the attributes. */ + attributes = chainon (prefix_attributes, attributes); + + /* Create the bitfield declaration. */ + decl = grokbitfield (identifier, + decl_specifiers, + width); + /* Apply the attributes. */ + cplus_decl_attributes (&decl, attributes, /*flags=*/0); + } + else + { + tree declarator; + tree initializer; + tree asm_specification; + int ctor_dtor_or_conv_p; + + /* Parse the declarator. */ + declarator + = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + &ctor_dtor_or_conv_p, + /*parenthesized_p=*/NULL); + + /* If something went wrong parsing the declarator, make sure + that we at least consume some tokens. */ + if (declarator == error_mark_node) + { + /* Skip to the end of the statement. */ + cp_parser_skip_to_end_of_statement (parser); + /* If the next token is not a semicolon, that is + probably because we just skipped over the body of + a function. So, we consume a semicolon if + present, but do not issue an error message if it + is not present. */ + if (cp_lexer_next_token_is (parser->lexer, + CPP_SEMICOLON)) + cp_lexer_consume_token (parser->lexer); + return; + } + + cp_parser_check_for_definition_in_return_type + (declarator, declares_class_or_enum); + + /* Look for an asm-specification. */ + asm_specification = cp_parser_asm_specification_opt (parser); + /* Look for attributes that apply to the declaration. */ + attributes = cp_parser_attributes_opt (parser); + /* Remember which attributes are prefix attributes and + which are not. */ + first_attribute = attributes; + /* Combine the attributes. */ + attributes = chainon (prefix_attributes, attributes); + + /* If it's an `=', then we have a constant-initializer or a + pure-specifier. It is not correct to parse the + initializer before registering the member declaration + since the member declaration should be in scope while + its initializer is processed. However, the rest of the + front end does not yet provide an interface that allows + us to handle this correctly. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + { + /* In [class.mem]: + + A pure-specifier shall be used only in the declaration of + a virtual function. + + A member-declarator can contain a constant-initializer + only if it declares a static member of integral or + enumeration type. + + Therefore, if the DECLARATOR is for a function, we look + for a pure-specifier; otherwise, we look for a + constant-initializer. When we call `grokfield', it will + perform more stringent semantics checks. */ + if (TREE_CODE (declarator) == CALL_EXPR) + initializer = cp_parser_pure_specifier (parser); + else + /* Parse the initializer. */ + initializer = cp_parser_constant_initializer (parser); + } + /* Otherwise, there is no initializer. */ + else + initializer = NULL_TREE; + + /* See if we are probably looking at a function + definition. We are certainly not looking at at a + member-declarator. Calling `grokfield' has + side-effects, so we must not do it unless we are sure + that we are looking at a member-declarator. */ + if (cp_parser_token_starts_function_definition_p + (cp_lexer_peek_token (parser->lexer))) + { + /* The grammar does not allow a pure-specifier to be + used when a member function is defined. (It is + possible that this fact is an oversight in the + standard, since a pure function may be defined + outside of the class-specifier. */ + if (initializer) + error ("pure-specifier on function-definition"); + decl = cp_parser_save_member_function_body (parser, + decl_specifiers, + declarator, + attributes); + /* If the member was not a friend, declare it here. */ + if (!friend_p) + finish_member_declaration (decl); + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If the next token is a semicolon, consume it. */ + if (token->type == CPP_SEMICOLON) + cp_lexer_consume_token (parser->lexer); + return; + } + else + { + /* Create the declaration. */ + decl = grokfield (declarator, decl_specifiers, + initializer, asm_specification, + attributes); + /* Any initialization must have been from a + constant-expression. */ + if (decl && TREE_CODE (decl) == VAR_DECL && initializer) + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1; + } + } + + /* Reset PREFIX_ATTRIBUTES. */ + while (attributes && TREE_CHAIN (attributes) != first_attribute) + attributes = TREE_CHAIN (attributes); + if (attributes) + TREE_CHAIN (attributes) = NULL_TREE; + + /* If there is any qualification still in effect, clear it + now; we will be starting fresh with the next declarator. */ + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + /* If it's a `,', then there are more declarators. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + /* If the next token isn't a `;', then we have a parse error. */ + else if (cp_lexer_next_token_is_not (parser->lexer, + CPP_SEMICOLON)) + { + cp_parser_error (parser, "expected `;'"); + /* Skip tokens until we find a `;'. */ + cp_parser_skip_to_end_of_statement (parser); + + break; + } + + if (decl) + { + /* Add DECL to the list of members. */ + if (!friend_p) + finish_member_declaration (decl); + + if (TREE_CODE (decl) == FUNCTION_DECL) + cp_parser_save_default_args (parser, decl); + } + } + } + + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); +} + +/* Parse a pure-specifier. + + pure-specifier: + = 0 + + Returns INTEGER_ZERO_NODE if a pure specifier is found. + Otherwise, ERROR_MARK_NODE is returned. */ + +static tree +cp_parser_pure_specifier (cp_parser* parser) +{ + cp_token *token; + + /* Look for the `=' token. */ + if (!cp_parser_require (parser, CPP_EQ, "`='")) + return error_mark_node; + /* Look for the `0' token. */ + token = cp_parser_require (parser, CPP_NUMBER, "`0'"); + /* Unfortunately, this will accept `0L' and `0x00' as well. We need + to get information from the lexer about how the number was + spelled in order to fix this problem. */ + if (!token || !integer_zerop (token->value)) + return error_mark_node; + + return integer_zero_node; +} + +/* Parse a constant-initializer. + + constant-initializer: + = constant-expression + + Returns a representation of the constant-expression. */ + +static tree +cp_parser_constant_initializer (cp_parser* parser) +{ + /* Look for the `=' token. */ + if (!cp_parser_require (parser, CPP_EQ, "`='")) + return error_mark_node; + + /* It is invalid to write: + + struct S { static const int i = { 7 }; }; + + */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + cp_parser_error (parser, + "a brace-enclosed initializer is not allowed here"); + /* Consume the opening brace. */ + cp_lexer_consume_token (parser->lexer); + /* Skip the initializer. */ + cp_parser_skip_to_closing_brace (parser); + /* Look for the trailing `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); + + return error_mark_node; + } + + return cp_parser_constant_expression (parser, + /*allow_non_constant=*/false, + NULL); +} + +/* Derived classes [gram.class.derived] */ + +/* Parse a base-clause. + + base-clause: + : base-specifier-list + + base-specifier-list: + base-specifier + base-specifier-list , base-specifier + + Returns a TREE_LIST representing the base-classes, in the order in + which they were declared. The representation of each node is as + described by cp_parser_base_specifier. + + In the case that no bases are specified, this function will return + NULL_TREE, not ERROR_MARK_NODE. */ + +static tree +cp_parser_base_clause (cp_parser* parser) +{ + tree bases = NULL_TREE; + + /* Look for the `:' that begins the list. */ + cp_parser_require (parser, CPP_COLON, "`:'"); + + /* Scan the base-specifier-list. */ + while (true) + { + cp_token *token; + tree base; + + /* Look for the base-specifier. */ + base = cp_parser_base_specifier (parser); + /* Add BASE to the front of the list. */ + if (base != error_mark_node) + { + TREE_CHAIN (base) = bases; + bases = base; + } + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not a comma, then the list is complete. */ + if (token->type != CPP_COMMA) + break; + /* Consume the `,'. */ + cp_lexer_consume_token (parser->lexer); + } + + /* PARSER->SCOPE may still be non-NULL at this point, if the last + base class had a qualified name. However, the next name that + appears is certainly not qualified. */ + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + + return nreverse (bases); +} + +/* Parse a base-specifier. + + base-specifier: + :: [opt] nested-name-specifier [opt] class-name + virtual access-specifier [opt] :: [opt] nested-name-specifier + [opt] class-name + access-specifier virtual [opt] :: [opt] nested-name-specifier + [opt] class-name + + Returns a TREE_LIST. The TREE_PURPOSE will be one of + ACCESS_{DEFAULT,PUBLIC,PROTECTED,PRIVATE}_[VIRTUAL]_NODE to + indicate the specifiers provided. The TREE_VALUE will be a TYPE + (or the ERROR_MARK_NODE) indicating the type that was specified. */ + +static tree +cp_parser_base_specifier (cp_parser* parser) +{ + cp_token *token; + bool done = false; + bool virtual_p = false; + bool duplicate_virtual_error_issued_p = false; + bool duplicate_access_error_issued_p = false; + bool class_scope_p, template_p; + tree access = access_default_node; + tree type; + + /* Process the optional `virtual' and `access-specifier'. */ + while (!done) + { + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* Process `virtual'. */ + switch (token->keyword) + { + case RID_VIRTUAL: + /* If `virtual' appears more than once, issue an error. */ + if (virtual_p && !duplicate_virtual_error_issued_p) + { + cp_parser_error (parser, + "`virtual' specified more than once in base-specified"); + duplicate_virtual_error_issued_p = true; + } + + virtual_p = true; + + /* Consume the `virtual' token. */ + cp_lexer_consume_token (parser->lexer); + + break; + + case RID_PUBLIC: + case RID_PROTECTED: + case RID_PRIVATE: + /* If more than one access specifier appears, issue an + error. */ + if (access != access_default_node + && !duplicate_access_error_issued_p) + { + cp_parser_error (parser, + "more than one access specifier in base-specified"); + duplicate_access_error_issued_p = true; + } + + access = ridpointers[(int) token->keyword]; + + /* Consume the access-specifier. */ + cp_lexer_consume_token (parser->lexer); + + break; + + default: + done = true; + break; + } + } + /* It is not uncommon to see programs mechanically, errouneously, use + the 'typename' keyword to denote (dependent) qualified types + as base classes. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME)) + { + if (!processing_template_decl) + error ("keyword `typename' not allowed outside of templates"); + else + error ("keyword `typename' not allowed in this context " + "(the base class is implicitly a type)"); + cp_lexer_consume_token (parser->lexer); + } + + /* Look for the optional `::' operator. */ + cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false); + /* Look for the nested-name-specifier. The simplest way to + implement: + + [temp.res] + + The keyword `typename' is not permitted in a base-specifier or + mem-initializer; in these contexts a qualified name that + depends on a template-parameter is implicitly assumed to be a + type name. + + is to pretend that we have seen the `typename' keyword at this + point. */ + cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/true, + /*check_dependency_p=*/true, + /*type_p=*/true, + /*is_declaration=*/true); + /* If the base class is given by a qualified name, assume that names + we see are type names or templates, as appropriate. */ + class_scope_p = (parser->scope && TYPE_P (parser->scope)); + template_p = class_scope_p && cp_parser_optional_template_keyword (parser); + + /* Finally, look for the class-name. */ + type = cp_parser_class_name (parser, + class_scope_p, + template_p, + /*type_p=*/true, + /*check_dependency_p=*/true, + /*class_head_p=*/false, + /*is_declaration=*/true); + + if (type == error_mark_node) + return error_mark_node; + + return finish_base_specifier (TREE_TYPE (type), access, virtual_p); +} + +/* Exception handling [gram.exception] */ + +/* Parse an (optional) exception-specification. + + exception-specification: + throw ( type-id-list [opt] ) + + Returns a TREE_LIST representing the exception-specification. The + TREE_VALUE of each node is a type. */ + +static tree +cp_parser_exception_specification_opt (cp_parser* parser) +{ + cp_token *token; + tree type_id_list; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not `throw', then there's no exception-specification. */ + if (!cp_parser_is_keyword (token, RID_THROW)) + return NULL_TREE; + + /* Consume the `throw'. */ + cp_lexer_consume_token (parser->lexer); + + /* Look for the `('. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not a `)', then there is a type-id-list. */ + if (token->type != CPP_CLOSE_PAREN) + { + const char *saved_message; + + /* Types may not be defined in an exception-specification. */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = "types may not be defined in an exception-specification"; + /* Parse the type-id-list. */ + type_id_list = cp_parser_type_id_list (parser); + /* Restore the saved message. */ + parser->type_definition_forbidden_message = saved_message; + } + else + type_id_list = empty_except_spec; + + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + + return type_id_list; +} + +/* Parse an (optional) type-id-list. + + type-id-list: + type-id + type-id-list , type-id + + Returns a TREE_LIST. The TREE_VALUE of each node is a TYPE, + in the order that the types were presented. */ + +static tree +cp_parser_type_id_list (cp_parser* parser) +{ + tree types = NULL_TREE; + + while (true) + { + cp_token *token; + tree type; + + /* Get the next type-id. */ + type = cp_parser_type_id (parser); + /* Add it to the list. */ + types = add_exception_specifier (types, type, /*complain=*/1); + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it is not a `,', we are done. */ + if (token->type != CPP_COMMA) + break; + /* Consume the `,'. */ + cp_lexer_consume_token (parser->lexer); + } + + return nreverse (types); +} + +/* Parse a try-block. + + try-block: + try compound-statement handler-seq */ + +static tree +cp_parser_try_block (cp_parser* parser) +{ + tree try_block; + + cp_parser_require_keyword (parser, RID_TRY, "`try'"); + try_block = begin_try_block (); + cp_parser_compound_statement (parser, false); + finish_try_block (try_block); + cp_parser_handler_seq (parser); + finish_handler_sequence (try_block); + + return try_block; +} + +/* Parse a function-try-block. + + function-try-block: + try ctor-initializer [opt] function-body handler-seq */ + +static bool +cp_parser_function_try_block (cp_parser* parser) +{ + tree try_block; + bool ctor_initializer_p; + + /* Look for the `try' keyword. */ + if (!cp_parser_require_keyword (parser, RID_TRY, "`try'")) + return false; + /* Let the rest of the front-end know where we are. */ + try_block = begin_function_try_block (); + /* Parse the function-body. */ + ctor_initializer_p + = cp_parser_ctor_initializer_opt_and_function_body (parser); + /* We're done with the `try' part. */ + finish_function_try_block (try_block); + /* Parse the handlers. */ + cp_parser_handler_seq (parser); + /* We're done with the handlers. */ + finish_function_handler_sequence (try_block); + + return ctor_initializer_p; +} + +/* Parse a handler-seq. + + handler-seq: + handler handler-seq [opt] */ + +static void +cp_parser_handler_seq (cp_parser* parser) +{ + while (true) + { + cp_token *token; + + /* Parse the handler. */ + cp_parser_handler (parser); + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not `catch' then there are no more handlers. */ + if (!cp_parser_is_keyword (token, RID_CATCH)) + break; + } +} + +/* Parse a handler. + + handler: + catch ( exception-declaration ) compound-statement */ + +static void +cp_parser_handler (cp_parser* parser) +{ + tree handler; + tree declaration; + + cp_parser_require_keyword (parser, RID_CATCH, "`catch'"); + handler = begin_handler (); + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + declaration = cp_parser_exception_declaration (parser); + finish_handler_parms (declaration, handler); + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + cp_parser_compound_statement (parser, false); + finish_handler (handler); +} + +/* Parse an exception-declaration. + + exception-declaration: + type-specifier-seq declarator + type-specifier-seq abstract-declarator + type-specifier-seq + ... + + Returns a VAR_DECL for the declaration, or NULL_TREE if the + ellipsis variant is used. */ + +static tree +cp_parser_exception_declaration (cp_parser* parser) +{ + tree type_specifiers; + tree declarator; + const char *saved_message; + + /* If it's an ellipsis, it's easy to handle. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + /* Consume the `...' token. */ + cp_lexer_consume_token (parser->lexer); + return NULL_TREE; + } + + /* Types may not be defined in exception-declarations. */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = "types may not be defined in exception-declarations"; + + /* Parse the type-specifier-seq. */ + type_specifiers = cp_parser_type_specifier_seq (parser); + /* If it's a `)', then there is no declarator. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) + declarator = NULL_TREE; + else + declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER, + /*ctor_dtor_or_conv_p=*/NULL, + /*parenthesized_p=*/NULL); + + /* Restore the saved message. */ + parser->type_definition_forbidden_message = saved_message; + + return start_handler_parms (type_specifiers, declarator); +} + +/* Parse a throw-expression. + + throw-expression: + throw assignment-expression [opt] + + Returns a THROW_EXPR representing the throw-expression. */ + +static tree +cp_parser_throw_expression (cp_parser* parser) +{ + tree expression; + cp_token* token; + + cp_parser_require_keyword (parser, RID_THROW, "`throw'"); + token = cp_lexer_peek_token (parser->lexer); + /* Figure out whether or not there is an assignment-expression + following the "throw" keyword. */ + if (token->type == CPP_COMMA + || token->type == CPP_SEMICOLON + || token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_SQUARE + || token->type == CPP_CLOSE_BRACE + || token->type == CPP_COLON) + expression = NULL_TREE; + else + expression = cp_parser_assignment_expression (parser); + + return build_throw (expression); +} + +/* GNU Extensions */ + +/* Parse an (optional) asm-specification. + + asm-specification: + asm ( string-literal ) + + If the asm-specification is present, returns a STRING_CST + corresponding to the string-literal. Otherwise, returns + NULL_TREE. */ + +static tree +cp_parser_asm_specification_opt (cp_parser* parser) +{ + cp_token *token; + tree asm_specification; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If the next token isn't the `asm' keyword, then there's no + asm-specification. */ + if (!cp_parser_is_keyword (token, RID_ASM)) + return NULL_TREE; + + /* Consume the `asm' token. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the `('. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + + /* Look for the string-literal. */ + token = cp_parser_require (parser, CPP_STRING, "string-literal"); + if (token) + asm_specification = token->value; + else + asm_specification = NULL_TREE; + + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`('"); + + return asm_specification; +} + +/* Parse an asm-operand-list. + + asm-operand-list: + asm-operand + asm-operand-list , asm-operand + + asm-operand: + string-literal ( expression ) + [ string-literal ] string-literal ( expression ) + + Returns a TREE_LIST representing the operands. The TREE_VALUE of + each node is the expression. The TREE_PURPOSE is itself a + TREE_LIST whose TREE_PURPOSE is a STRING_CST for the bracketed + string-literal (or NULL_TREE if not present) and whose TREE_VALUE + is a STRING_CST for the string literal before the parenthesis. */ + +static tree +cp_parser_asm_operand_list (cp_parser* parser) +{ + tree asm_operands = NULL_TREE; + + while (true) + { + tree string_literal; + tree expression; + tree name; + cp_token *token; + + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + { + /* Consume the `[' token. */ + cp_lexer_consume_token (parser->lexer); + /* Read the operand name. */ + name = cp_parser_identifier (parser); + if (name != error_mark_node) + name = build_string (IDENTIFIER_LENGTH (name), + IDENTIFIER_POINTER (name)); + /* Look for the closing `]'. */ + cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"); + } + else + name = NULL_TREE; + /* Look for the string-literal. */ + token = cp_parser_require (parser, CPP_STRING, "string-literal"); + string_literal = token ? token->value : error_mark_node; + /* Look for the `('. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + /* Parse the expression. */ + expression = cp_parser_expression (parser); + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* Add this operand to the list. */ + asm_operands = tree_cons (build_tree_list (name, string_literal), + expression, + asm_operands); + /* If the next token is not a `,', there are no more + operands. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + /* Consume the `,'. */ + cp_lexer_consume_token (parser->lexer); + } + + return nreverse (asm_operands); +} + +/* Parse an asm-clobber-list. + + asm-clobber-list: + string-literal + asm-clobber-list , string-literal + + Returns a TREE_LIST, indicating the clobbers in the order that they + appeared. The TREE_VALUE of each node is a STRING_CST. */ + +static tree +cp_parser_asm_clobber_list (cp_parser* parser) +{ + tree clobbers = NULL_TREE; + + while (true) + { + cp_token *token; + tree string_literal; + + /* Look for the string literal. */ + token = cp_parser_require (parser, CPP_STRING, "string-literal"); + string_literal = token ? token->value : error_mark_node; + /* Add it to the list. */ + clobbers = tree_cons (NULL_TREE, string_literal, clobbers); + /* If the next token is not a `,', then the list is + complete. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + /* Consume the `,' token. */ + cp_lexer_consume_token (parser->lexer); + } + + return clobbers; +} + +/* Parse an (optional) series of attributes. + + attributes: + attributes attribute + + attribute: + __attribute__ (( attribute-list [opt] )) + + The return value is as for cp_parser_attribute_list. */ + +static tree +cp_parser_attributes_opt (cp_parser* parser) +{ + tree attributes = NULL_TREE; + + while (true) + { + cp_token *token; + tree attribute_list; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's not `__attribute__', then we're done. */ + if (token->keyword != RID_ATTRIBUTE) + break; + + /* Consume the `__attribute__' keyword. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the two `(' tokens. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_CLOSE_PAREN) + /* Parse the attribute-list. */ + attribute_list = cp_parser_attribute_list (parser); + else + /* If the next token is a `)', then there is no attribute + list. */ + attribute_list = NULL; + + /* Look for the two `)' tokens. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + + /* Add these new attributes to the list. */ + attributes = chainon (attributes, attribute_list); + } + + return attributes; +} + +/* Parse an attribute-list. + + attribute-list: + attribute + attribute-list , attribute + + attribute: + identifier + identifier ( identifier ) + identifier ( identifier , expression-list ) + identifier ( expression-list ) + + Returns a TREE_LIST. Each node corresponds to an attribute. THe + TREE_PURPOSE of each node is the identifier indicating which + attribute is in use. The TREE_VALUE represents the arguments, if + any. */ + +static tree +cp_parser_attribute_list (cp_parser* parser) +{ + tree attribute_list = NULL_TREE; + + while (true) + { + cp_token *token; + tree identifier; + tree attribute; + + /* Look for the identifier. We also allow keywords here; for + example `__attribute__ ((const))' is legal. */ + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_NAME + && token->type != CPP_KEYWORD) + return error_mark_node; + /* Consume the token. */ + token = cp_lexer_consume_token (parser->lexer); + + /* Save away the identifier that indicates which attribute this is. */ + identifier = token->value; + attribute = build_tree_list (identifier, NULL_TREE); + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's an `(', then parse the attribute arguments. */ + if (token->type == CPP_OPEN_PAREN) + { + tree arguments; + + arguments = (cp_parser_parenthesized_expression_list + (parser, true, /*non_constant_p=*/NULL)); + /* Save the identifier and arguments away. */ + TREE_VALUE (attribute) = arguments; + } + + /* Add this attribute to the list. */ + TREE_CHAIN (attribute) = attribute_list; + attribute_list = attribute; + + /* Now, look for more attributes. */ + token = cp_lexer_peek_token (parser->lexer); + /* If the next token isn't a `,', we're done. */ + if (token->type != CPP_COMMA) + break; + + /* Consume the comma and keep going. */ + cp_lexer_consume_token (parser->lexer); + } + + /* We built up the list in reverse order. */ + return nreverse (attribute_list); +} + +/* Parse an optional `__extension__' keyword. Returns TRUE if it is + present, and FALSE otherwise. *SAVED_PEDANTIC is set to the + current value of the PEDANTIC flag, regardless of whether or not + the `__extension__' keyword is present. The caller is responsible + for restoring the value of the PEDANTIC flag. */ + +static bool +cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic) +{ + /* Save the old value of the PEDANTIC flag. */ + *saved_pedantic = pedantic; + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTENSION)) + { + /* Consume the `__extension__' token. */ + cp_lexer_consume_token (parser->lexer); + /* We're not being pedantic while the `__extension__' keyword is + in effect. */ + pedantic = 0; + + return true; + } + + return false; +} + +/* Parse a label declaration. + + label-declaration: + __label__ label-declarator-seq ; + + label-declarator-seq: + identifier , label-declarator-seq + identifier */ + +static void +cp_parser_label_declaration (cp_parser* parser) +{ + /* Look for the `__label__' keyword. */ + cp_parser_require_keyword (parser, RID_LABEL, "`__label__'"); + + while (true) + { + tree identifier; + + /* Look for an identifier. */ + identifier = cp_parser_identifier (parser); + /* Declare it as a lobel. */ + finish_label_decl (identifier); + /* If the next token is a `;', stop. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + break; + /* Look for the `,' separating the label declarations. */ + cp_parser_require (parser, CPP_COMMA, "`,'"); + } + + /* Look for the final `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); +} + +/* Support Functions */ + +/* Looks up NAME in the current scope, as given by PARSER->SCOPE. + NAME should have one of the representations used for an + id-expression. If NAME is the ERROR_MARK_NODE, the ERROR_MARK_NODE + is returned. If PARSER->SCOPE is a dependent type, then a + SCOPE_REF is returned. + + If NAME is a TEMPLATE_ID_EXPR, then it will be immediately + returned; the name was already resolved when the TEMPLATE_ID_EXPR + was formed. Abstractly, such entities should not be passed to this + function, because they do not need to be looked up, but it is + simpler to check for this special case here, rather than at the + call-sites. + + In cases not explicitly covered above, this function returns a + DECL, OVERLOAD, or baselink representing the result of the lookup. + If there was no entity with the indicated NAME, the ERROR_MARK_NODE + is returned. + + If IS_TYPE is TRUE, bindings that do not refer to types are + ignored. + + If IS_TEMPLATE is TRUE, bindings that do not refer to templates are + ignored. + + If IS_NAMESPACE is TRUE, bindings that do not refer to namespaces + are ignored. + + If CHECK_DEPENDENCY is TRUE, names are not looked up in dependent + types. */ + +static tree +cp_parser_lookup_name (cp_parser *parser, tree name, + bool is_type, bool is_template, bool is_namespace, + bool check_dependency) +{ + tree decl; + tree object_type = parser->context->object_type; + + /* Now that we have looked up the name, the OBJECT_TYPE (if any) is + no longer valid. Note that if we are parsing tentatively, and + the parse fails, OBJECT_TYPE will be automatically restored. */ + parser->context->object_type = NULL_TREE; + + if (name == error_mark_node) + return error_mark_node; + + /* A template-id has already been resolved; there is no lookup to + do. */ + if (TREE_CODE (name) == TEMPLATE_ID_EXPR) + return name; + if (BASELINK_P (name)) + { + my_friendly_assert ((TREE_CODE (BASELINK_FUNCTIONS (name)) + == TEMPLATE_ID_EXPR), + 20020909); + return name; + } + + /* A BIT_NOT_EXPR is used to represent a destructor. By this point, + it should already have been checked to make sure that the name + used matches the type being destroyed. */ + if (TREE_CODE (name) == BIT_NOT_EXPR) + { + tree type; + + /* Figure out to which type this destructor applies. */ + if (parser->scope) + type = parser->scope; + else if (object_type) + type = object_type; + else + type = current_class_type; + /* If that's not a class type, there is no destructor. */ + if (!type || !CLASS_TYPE_P (type)) + return error_mark_node; + if (!CLASSTYPE_DESTRUCTORS (type)) + return error_mark_node; + /* If it was a class type, return the destructor. */ + return CLASSTYPE_DESTRUCTORS (type); + } + + /* By this point, the NAME should be an ordinary identifier. If + the id-expression was a qualified name, the qualifying scope is + stored in PARSER->SCOPE at this point. */ + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, + 20000619); + + /* Perform the lookup. */ + if (parser->scope) + { + bool dependent_p; + + if (parser->scope == error_mark_node) + return error_mark_node; + + /* If the SCOPE is dependent, the lookup must be deferred until + the template is instantiated -- unless we are explicitly + looking up names in uninstantiated templates. Even then, we + cannot look up the name if the scope is not a class type; it + might, for example, be a template type parameter. */ + dependent_p = (TYPE_P (parser->scope) + && !(parser->in_declarator_p + && currently_open_class (parser->scope)) + && dependent_type_p (parser->scope)); + if ((check_dependency || !CLASS_TYPE_P (parser->scope)) + && dependent_p) + { + if (is_type) + /* The resolution to Core Issue 180 says that `struct A::B' + should be considered a type-name, even if `A' is + dependent. */ + decl = TYPE_NAME (make_typename_type (parser->scope, + name, + /*complain=*/1)); + else if (is_template) + decl = make_unbound_class_template (parser->scope, + name, + /*complain=*/1); + else + decl = build_nt (SCOPE_REF, parser->scope, name); + } + else + { + bool pop_p = false; + + /* If PARSER->SCOPE is a dependent type, then it must be a + class type, and we must not be checking dependencies; + otherwise, we would have processed this lookup above. So + that PARSER->SCOPE is not considered a dependent base by + lookup_member, we must enter the scope here. */ + if (dependent_p) + pop_p = push_scope (parser->scope); + /* If the PARSER->SCOPE is a a template specialization, it + may be instantiated during name lookup. In that case, + errors may be issued. Even if we rollback the current + tentative parse, those errors are valid. */ + decl = lookup_qualified_name (parser->scope, name, is_type, + /*complain=*/true); + if (pop_p) + pop_scope (parser->scope); + } + parser->qualifying_scope = parser->scope; + parser->object_scope = NULL_TREE; + } + else if (object_type) + { + tree object_decl = NULL_TREE; + /* Look up the name in the scope of the OBJECT_TYPE, unless the + OBJECT_TYPE is not a class. */ + if (CLASS_TYPE_P (object_type)) + /* If the OBJECT_TYPE is a template specialization, it may + be instantiated during name lookup. In that case, errors + may be issued. Even if we rollback the current tentative + parse, those errors are valid. */ + object_decl = lookup_member (object_type, + name, + /*protect=*/0, is_type); + /* Look it up in the enclosing context, too. */ + decl = lookup_name_real (name, is_type, /*nonclass=*/0, + is_namespace, + /*flags=*/0); + parser->object_scope = object_type; + parser->qualifying_scope = NULL_TREE; + if (object_decl) + decl = object_decl; + } + else + { + decl = lookup_name_real (name, is_type, /*nonclass=*/0, + is_namespace, + /*flags=*/0); + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + } + + /* If the lookup failed, let our caller know. */ + if (!decl + || decl == error_mark_node + || (TREE_CODE (decl) == FUNCTION_DECL + && DECL_ANTICIPATED (decl))) + return error_mark_node; + + /* If it's a TREE_LIST, the result of the lookup was ambiguous. */ + if (TREE_CODE (decl) == TREE_LIST) + { + /* The error message we have to print is too complicated for + cp_parser_error, so we incorporate its actions directly. */ + if (!cp_parser_simulate_error (parser)) + { + error ("reference to `%D' is ambiguous", name); + print_candidates (decl); + } + return error_mark_node; + } + + my_friendly_assert (DECL_P (decl) + || TREE_CODE (decl) == OVERLOAD + || TREE_CODE (decl) == SCOPE_REF + || TREE_CODE (decl) == UNBOUND_CLASS_TEMPLATE + || BASELINK_P (decl), + 20000619); + + /* If we have resolved the name of a member declaration, check to + see if the declaration is accessible. When the name resolves to + set of overloaded functions, accessibility is checked when + overload resolution is done. + + During an explicit instantiation, access is not checked at all, + as per [temp.explicit]. */ + if (DECL_P (decl)) + check_accessibility_of_qualified_id (decl, object_type, parser->scope); + + return decl; +} + +/* Like cp_parser_lookup_name, but for use in the typical case where + CHECK_ACCESS is TRUE, IS_TYPE is FALSE, IS_TEMPLATE is FALSE, + IS_NAMESPACE is FALSE, and CHECK_DEPENDENCY is TRUE. */ + +static tree +cp_parser_lookup_name_simple (cp_parser* parser, tree name) +{ + return cp_parser_lookup_name (parser, name, + /*is_type=*/false, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/true); +} + +/* If DECL is a TEMPLATE_DECL that can be treated like a TYPE_DECL in + the current context, return the TYPE_DECL. If TAG_NAME_P is + true, the DECL indicates the class being defined in a class-head, + or declared in an elaborated-type-specifier. + + Otherwise, return DECL. */ + +static tree +cp_parser_maybe_treat_template_as_class (tree decl, bool tag_name_p) +{ + /* If the TEMPLATE_DECL is being declared as part of a class-head, + the translation from TEMPLATE_DECL to TYPE_DECL occurs: + + struct A { + template <typename T> struct B; + }; + + template <typename T> struct A::B {}; + + Similarly, in a elaborated-type-specifier: + + namespace N { struct X{}; } + + struct A { + template <typename T> friend struct N::X; + }; + + However, if the DECL refers to a class type, and we are in + the scope of the class, then the name lookup automatically + finds the TYPE_DECL created by build_self_reference rather + than a TEMPLATE_DECL. For example, in: + + template <class T> struct S { + S s; + }; + + there is no need to handle such case. */ + + if (DECL_CLASS_TEMPLATE_P (decl) && tag_name_p) + return DECL_TEMPLATE_RESULT (decl); + + return decl; +} + +/* If too many, or too few, template-parameter lists apply to the + declarator, issue an error message. Returns TRUE if all went well, + and FALSE otherwise. */ + +static bool +cp_parser_check_declarator_template_parameters (cp_parser* parser, + tree declarator) +{ + unsigned num_templates; + + /* We haven't seen any classes that involve template parameters yet. */ + num_templates = 0; + + switch (TREE_CODE (declarator)) + { + case CALL_EXPR: + case ARRAY_REF: + case INDIRECT_REF: + case ADDR_EXPR: + { + tree main_declarator = TREE_OPERAND (declarator, 0); + return + cp_parser_check_declarator_template_parameters (parser, + main_declarator); + } + + case SCOPE_REF: + { + tree scope; + tree member; + + scope = TREE_OPERAND (declarator, 0); + member = TREE_OPERAND (declarator, 1); + + /* If this is a pointer-to-member, then we are not interested + in the SCOPE, because it does not qualify the thing that is + being declared. */ + if (TREE_CODE (member) == INDIRECT_REF) + return (cp_parser_check_declarator_template_parameters + (parser, member)); + + while (scope && CLASS_TYPE_P (scope)) + { + /* You're supposed to have one `template <...>' + for every template class, but you don't need one + for a full specialization. For example: + + template <class T> struct S{}; + template <> struct S<int> { void f(); }; + void S<int>::f () {} + + is correct; there shouldn't be a `template <>' for + the definition of `S<int>::f'. */ + if (CLASSTYPE_TEMPLATE_INFO (scope) + && (CLASSTYPE_TEMPLATE_INSTANTIATION (scope) + || uses_template_parms (CLASSTYPE_TI_ARGS (scope))) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope))) + ++num_templates; + + scope = TYPE_CONTEXT (scope); + } + } + + /* Fall through. */ + + default: + /* If the DECLARATOR has the form `X<y>' then it uses one + additional level of template parameters. */ + if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) + ++num_templates; + + return cp_parser_check_template_parameters (parser, + num_templates); + } +} + +/* NUM_TEMPLATES were used in the current declaration. If that is + invalid, return FALSE and issue an error messages. Otherwise, + return TRUE. */ + +static bool +cp_parser_check_template_parameters (cp_parser* parser, + unsigned num_templates) +{ + /* If there are more template classes than parameter lists, we have + something like: + + template <class T> void S<T>::R<T>::f (); */ + if (parser->num_template_parameter_lists < num_templates) + { + error ("too few template-parameter-lists"); + return false; + } + /* If there are the same number of template classes and parameter + lists, that's OK. */ + if (parser->num_template_parameter_lists == num_templates) + return true; + /* If there are more, but only one more, then we are referring to a + member template. That's OK too. */ + if (parser->num_template_parameter_lists == num_templates + 1) + return true; + /* Otherwise, there are too many template parameter lists. We have + something like: + + template <class T> template <class U> void S::f(); */ + error ("too many template-parameter-lists"); + return false; +} + +/* Parse a binary-expression of the general form: + + binary-expression: + <expr> + binary-expression <token> <expr> + + The TOKEN_TREE_MAP maps <token> types to <expr> codes. FN is used + to parser the <expr>s. If the first production is used, then the + value returned by FN is returned directly. Otherwise, a node with + the indicated EXPR_TYPE is returned, with operands corresponding to + the two sub-expressions. */ + +static tree +cp_parser_binary_expression (cp_parser* parser, + const cp_parser_token_tree_map token_tree_map, + cp_parser_expression_fn fn) +{ + tree lhs; + + /* Parse the first expression. */ + lhs = (*fn) (parser); + /* Now, look for more expressions. */ + while (true) + { + cp_token *token; + const cp_parser_token_tree_map_node *map_node; + tree rhs; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If the token is `>', and that's not an operator at the + moment, then we're done. */ + if (token->type == CPP_GREATER + && !parser->greater_than_is_operator_p) + break; + /* If we find one of the tokens we want, build the corresponding + tree representation. */ + for (map_node = token_tree_map; + map_node->token_type != CPP_EOF; + ++map_node) + if (map_node->token_type == token->type) + { + /* Assume that an overloaded operator will not be used. */ + bool overloaded_p = false; + + /* Consume the operator token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the right-hand side of the expression. */ + rhs = (*fn) (parser); + /* Build the binary tree node. */ + lhs = build_x_binary_op (map_node->tree_type, lhs, rhs, + &overloaded_p); + /* If the binary operator required the use of an + overloaded operator, then this expression cannot be an + integral constant-expression. An overloaded operator + can be used even if both operands are otherwise + permissible in an integral constant-expression if at + least one of the operands is of enumeration type. */ + if (overloaded_p + && (cp_parser_non_integral_constant_expression + (parser, "calls to overloaded operators"))) + lhs = error_mark_node; + break; + } + + /* If the token wasn't one of the ones we want, we're done. */ + if (map_node->token_type == CPP_EOF) + break; + } + + return lhs; +} + +/* Parse an optional `::' token indicating that the following name is + from the global namespace. If so, PARSER->SCOPE is set to the + GLOBAL_NAMESPACE. Otherwise, PARSER->SCOPE is set to NULL_TREE, + unless CURRENT_SCOPE_VALID_P is TRUE, in which case it is left alone. + Returns the new value of PARSER->SCOPE, if the `::' token is + present, and NULL_TREE otherwise. */ + +static tree +cp_parser_global_scope_opt (cp_parser* parser, bool current_scope_valid_p) +{ + cp_token *token; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If we're looking at a `::' token then we're starting from the + global namespace, not our current location. */ + if (token->type == CPP_SCOPE) + { + /* Consume the `::' token. */ + cp_lexer_consume_token (parser->lexer); + /* Set the SCOPE so that we know where to start the lookup. */ + parser->scope = global_namespace; + parser->qualifying_scope = global_namespace; + parser->object_scope = NULL_TREE; + + return parser->scope; + } + else if (!current_scope_valid_p) + { + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + } + + return NULL_TREE; +} + +/* Returns TRUE if the upcoming token sequence is the start of a + constructor declarator. If FRIEND_P is true, the declarator is + preceded by the `friend' specifier. */ + +static bool +cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) +{ + bool constructor_p; + tree type_decl = NULL_TREE; + bool nested_name_p; + cp_token *next_token; + + /* The common case is that this is not a constructor declarator, so + try to avoid doing lots of work if at all possible. It's not + valid declare a constructor at function scope. */ + if (at_function_scope_p ()) + return false; + /* And only certain tokens can begin a constructor declarator. */ + next_token = cp_lexer_peek_token (parser->lexer); + if (next_token->type != CPP_NAME + && next_token->type != CPP_SCOPE + && next_token->type != CPP_NESTED_NAME_SPECIFIER + && next_token->type != CPP_TEMPLATE_ID) + return false; + + /* Parse tentatively; we are going to roll back all of the tokens + consumed here. */ + cp_parser_parse_tentatively (parser); + /* Assume that we are looking at a constructor declarator. */ + constructor_p = true; + + /* Look for the optional `::' operator. */ + cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false); + /* Look for the nested-name-specifier. */ + nested_name_p + = (cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/false, + /*check_dependency_p=*/false, + /*type_p=*/false, + /*is_declaration=*/false) + != NULL_TREE); + /* Outside of a class-specifier, there must be a + nested-name-specifier. */ + if (!nested_name_p && + (!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type) + || friend_p)) + constructor_p = false; + /* If we still think that this might be a constructor-declarator, + look for a class-name. */ + if (constructor_p) + { + /* If we have: + + template <typename T> struct S { S(); }; + template <typename T> S<T>::S (); + + we must recognize that the nested `S' names a class. + Similarly, for: + + template <typename T> S<T>::S<T> (); + + we must recognize that the nested `S' names a template. */ + type_decl = cp_parser_class_name (parser, + /*typename_keyword_p=*/false, + /*template_keyword_p=*/false, + /*type_p=*/false, + /*check_dependency_p=*/false, + /*class_head_p=*/false, + /*is_declaration=*/false); + /* If there was no class-name, then this is not a constructor. */ + constructor_p = !cp_parser_error_occurred (parser); + } + + /* If we're still considering a constructor, we have to see a `(', + to begin the parameter-declaration-clause, followed by either a + `)', an `...', or a decl-specifier. We need to check for a + type-specifier to avoid being fooled into thinking that: + + S::S (f) (int); + + is a constructor. (It is actually a function named `f' that + takes one parameter (of type `int') and returns a value of type + `S::S'. */ + if (constructor_p + && cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + { + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN) + && cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS) + /* A parameter declaration begins with a decl-specifier, + which is either the "attribute" keyword, a storage class + specifier, or (usually) a type-specifier. */ + && !cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE) + && !cp_parser_storage_class_specifier_opt (parser)) + { + tree type; + bool pop_p = false; + unsigned saved_num_template_parameter_lists; + + /* Names appearing in the type-specifier should be looked up + in the scope of the class. */ + if (current_class_type) + type = NULL_TREE; + else + { + type = TREE_TYPE (type_decl); + if (TREE_CODE (type) == TYPENAME_TYPE) + { + type = resolve_typename_type (type, + /*only_current_p=*/false); + if (type == error_mark_node) + { + cp_parser_abort_tentative_parse (parser); + return false; + } + } + pop_p = push_scope (type); + } + + /* Inside the constructor parameter list, surrounding + template-parameter-lists do not apply. */ + saved_num_template_parameter_lists + = parser->num_template_parameter_lists; + parser->num_template_parameter_lists = 0; + + /* Look for the type-specifier. */ + cp_parser_type_specifier (parser, + CP_PARSER_FLAGS_NONE, + /*is_friend=*/false, + /*is_declarator=*/true, + /*declares_class_or_enum=*/NULL, + /*is_cv_qualifier=*/NULL); + + parser->num_template_parameter_lists + = saved_num_template_parameter_lists; + + /* Leave the scope of the class. */ + if (pop_p) + pop_scope (type); + + constructor_p = !cp_parser_error_occurred (parser); + } + } + else + constructor_p = false; + /* We did not really want to consume any tokens. */ + cp_parser_abort_tentative_parse (parser); + + return constructor_p; +} + +/* Parse the definition of the function given by the DECL_SPECIFIERS, + ATTRIBUTES, and DECLARATOR. The access checks have been deferred; + they must be performed once we are in the scope of the function. + + Returns the function defined. */ + +static tree +cp_parser_function_definition_from_specifiers_and_declarator + (cp_parser* parser, + tree decl_specifiers, + tree attributes, + tree declarator) +{ + tree fn; + bool success_p; + + /* Begin the function-definition. */ + success_p = begin_function_definition (decl_specifiers, + attributes, + declarator); + + /* If there were names looked up in the decl-specifier-seq that we + did not check, check them now. We must wait until we are in the + scope of the function to perform the checks, since the function + might be a friend. */ + perform_deferred_access_checks (); + + if (!success_p) + { + /* If begin_function_definition didn't like the definition, skip + the entire function. */ + error ("invalid function declaration"); + cp_parser_skip_to_end_of_block_or_statement (parser); + fn = error_mark_node; + } + else + fn = cp_parser_function_definition_after_declarator (parser, + /*inline_p=*/false); + + return fn; +} + +/* Parse the part of a function-definition that follows the + declarator. INLINE_P is TRUE iff this function is an inline + function defined with a class-specifier. + + Returns the function defined. */ + +static tree +cp_parser_function_definition_after_declarator (cp_parser* parser, + bool inline_p) +{ + tree fn; + bool ctor_initializer_p = false; + bool saved_in_unbraced_linkage_specification_p; + unsigned saved_num_template_parameter_lists; + + /* If the next token is `return', then the code may be trying to + make use of the "named return value" extension that G++ used to + support. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_RETURN)) + { + /* Consume the `return' keyword. */ + cp_lexer_consume_token (parser->lexer); + /* Look for the identifier that indicates what value is to be + returned. */ + cp_parser_identifier (parser); + /* Issue an error message. */ + error ("named return values are no longer supported"); + /* Skip tokens until we reach the start of the function body. */ + while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) + && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + cp_lexer_consume_token (parser->lexer); + } + /* The `extern' in `extern "C" void f () { ... }' does not apply to + anything declared inside `f'. */ + saved_in_unbraced_linkage_specification_p + = parser->in_unbraced_linkage_specification_p; + parser->in_unbraced_linkage_specification_p = false; + /* Inside the function, surrounding template-parameter-lists do not + apply. */ + saved_num_template_parameter_lists + = parser->num_template_parameter_lists; + parser->num_template_parameter_lists = 0; + /* If the next token is `try', then we are looking at a + function-try-block. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) + ctor_initializer_p = cp_parser_function_try_block (parser); + /* A function-try-block includes the function-body, so we only do + this next part if we're not processing a function-try-block. */ + else + ctor_initializer_p + = cp_parser_ctor_initializer_opt_and_function_body (parser); + + /* Finish the function. */ + fn = finish_function ((ctor_initializer_p ? 1 : 0) | + (inline_p ? 2 : 0)); + /* Generate code for it, if necessary. */ + expand_or_defer_fn (fn); + /* Restore the saved values. */ + parser->in_unbraced_linkage_specification_p + = saved_in_unbraced_linkage_specification_p; + parser->num_template_parameter_lists + = saved_num_template_parameter_lists; + + return fn; +} + +/* Parse a template-declaration, assuming that the `export' (and + `extern') keywords, if present, has already been scanned. MEMBER_P + is as for cp_parser_template_declaration. */ + +static void +cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) +{ + tree decl = NULL_TREE; + tree parameter_list; + bool friend_p = false; + + /* Look for the `template' keyword. */ + if (!cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'")) + return; + + /* And the `<'. */ + if (!cp_parser_require (parser, CPP_LESS, "`<'")) + return; + + /* If the next token is `>', then we have an invalid + specialization. Rather than complain about an invalid template + parameter, issue an error message here. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER)) + { + cp_parser_error (parser, "invalid explicit specialization"); + begin_specialization (); + parameter_list = NULL_TREE; + } + else + { + /* Parse the template parameters. */ + begin_template_parm_list (); + parameter_list = cp_parser_template_parameter_list (parser); + parameter_list = end_template_parm_list (parameter_list); + } + + /* Look for the `>'. */ + cp_parser_skip_until_found (parser, CPP_GREATER, "`>'"); + /* We just processed one more parameter list. */ + ++parser->num_template_parameter_lists; + /* If the next token is `template', there are more template + parameters. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_TEMPLATE)) + cp_parser_template_declaration_after_export (parser, member_p); + else + { + decl = cp_parser_single_declaration (parser, + member_p, + &friend_p); + + /* If this is a member template declaration, let the front + end know. */ + if (member_p && !friend_p && decl) + { + if (TREE_CODE (decl) == TYPE_DECL) + cp_parser_check_access_in_redeclaration (decl); + + decl = finish_member_template_decl (decl); + } + else if (friend_p && decl && TREE_CODE (decl) == TYPE_DECL) + make_friend_class (current_class_type, TREE_TYPE (decl), + /*complain=*/true); + } + /* We are done with the current parameter list. */ + --parser->num_template_parameter_lists; + + /* Finish up. */ + finish_template_decl (parameter_list); + + /* Register member declarations. */ + if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl)) + finish_member_declaration (decl); + + /* If DECL is a function template, we must return to parse it later. + (Even though there is no definition, there might be default + arguments that need handling.) */ + if (member_p && decl + && (TREE_CODE (decl) == FUNCTION_DECL + || DECL_FUNCTION_TEMPLATE_P (decl))) + TREE_VALUE (parser->unparsed_functions_queues) + = tree_cons (NULL_TREE, decl, + TREE_VALUE (parser->unparsed_functions_queues)); +} + +/* Parse a `decl-specifier-seq [opt] init-declarator [opt] ;' or + `function-definition' sequence. MEMBER_P is true, this declaration + appears in a class scope. + + Returns the DECL for the declared entity. If FRIEND_P is non-NULL, + *FRIEND_P is set to TRUE iff the declaration is a friend. */ + +static tree +cp_parser_single_declaration (cp_parser* parser, + bool member_p, + bool* friend_p) +{ + int declares_class_or_enum; + tree decl = NULL_TREE; + tree decl_specifiers; + tree attributes; + bool function_definition_p = false; + + /* Defer access checks until we know what is being declared. */ + push_deferring_access_checks (dk_deferred); + + /* Try the `decl-specifier-seq [opt] init-declarator [opt]' + alternative. */ + decl_specifiers + = cp_parser_decl_specifier_seq (parser, + CP_PARSER_FLAGS_OPTIONAL, + &attributes, + &declares_class_or_enum); + if (friend_p) + *friend_p = cp_parser_friend_p (decl_specifiers); + /* Gather up the access checks that occurred the + decl-specifier-seq. */ + stop_deferring_access_checks (); + + /* Check for the declaration of a template class. */ + if (declares_class_or_enum) + { + if (cp_parser_declares_only_class_p (parser)) + { + decl = shadow_tag (decl_specifiers); + if (decl) + decl = TYPE_NAME (decl); + else + decl = error_mark_node; + } + } + else + decl = NULL_TREE; + /* If it's not a template class, try for a template function. If + the next token is a `;', then this declaration does not declare + anything. But, if there were errors in the decl-specifiers, then + the error might well have come from an attempted class-specifier. + In that case, there's no need to warn about a missing declarator. */ + if (!decl + && (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON) + || !value_member (error_mark_node, decl_specifiers))) + decl = cp_parser_init_declarator (parser, + decl_specifiers, + attributes, + /*function_definition_allowed_p=*/true, + member_p, + declares_class_or_enum, + &function_definition_p); + + pop_deferring_access_checks (); + + /* Clear any current qualification; whatever comes next is the start + of something new. */ + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + /* Look for a trailing `;' after the declaration. */ + if (!function_definition_p + && !cp_parser_require (parser, CPP_SEMICOLON, "`;'")) + cp_parser_skip_to_end_of_block_or_statement (parser); + + return decl; +} + +/* Parse a cast-expression that is not the operand of a unary "&". */ + +static tree +cp_parser_simple_cast_expression (cp_parser *parser) +{ + return cp_parser_cast_expression (parser, /*address_p=*/false); +} + +/* Parse a functional cast to TYPE. Returns an expression + representing the cast. */ + +static tree +cp_parser_functional_cast (cp_parser* parser, tree type) +{ + tree expression_list; + tree cast; + + expression_list + = cp_parser_parenthesized_expression_list (parser, false, + /*non_constant_p=*/NULL); + + cast = build_functional_cast (type, expression_list); + /* [expr.const]/1: In an integral constant expression "only type + conversions to integral or enumeration type can be used". */ + if (cast != error_mark_node && !type_dependent_expression_p (type) + && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (type))) + { + if (cp_parser_non_integral_constant_expression + (parser, "a call to a constructor")) + return error_mark_node; + } + return cast; +} + +/* Save the tokens that make up the body of a member function defined + in a class-specifier. The DECL_SPECIFIERS and DECLARATOR have + already been parsed. The ATTRIBUTES are any GNU "__attribute__" + specifiers applied to the declaration. Returns the FUNCTION_DECL + for the member function. */ + +static tree +cp_parser_save_member_function_body (cp_parser* parser, + tree decl_specifiers, + tree declarator, + tree attributes) +{ + cp_token_cache *cache; + tree fn; + + /* Create the function-declaration. */ + fn = start_method (decl_specifiers, declarator, attributes); + /* If something went badly wrong, bail out now. */ + if (fn == error_mark_node) + { + /* If there's a function-body, skip it. */ + if (cp_parser_token_starts_function_definition_p + (cp_lexer_peek_token (parser->lexer))) + cp_parser_skip_to_end_of_block_or_statement (parser); + return error_mark_node; + } + + /* Remember it, if there default args to post process. */ + cp_parser_save_default_args (parser, fn); + + /* Create a token cache. */ + cache = cp_token_cache_new (); + /* Save away the tokens that make up the body of the + function. */ + cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/0); + /* Handle function try blocks. */ + while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH)) + cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/0); + + /* Save away the inline definition; we will process it when the + class is complete. */ + DECL_PENDING_INLINE_INFO (fn) = cache; + DECL_PENDING_INLINE_P (fn) = 1; + + /* We need to know that this was defined in the class, so that + friend templates are handled correctly. */ + DECL_INITIALIZED_IN_CLASS_P (fn) = 1; + + /* We're done with the inline definition. */ + finish_method (fn); + + /* Add FN to the queue of functions to be parsed later. */ + TREE_VALUE (parser->unparsed_functions_queues) + = tree_cons (NULL_TREE, fn, + TREE_VALUE (parser->unparsed_functions_queues)); + + return fn; +} + +/* Parse a template-argument-list, as well as the trailing ">" (but + not the opening ">"). See cp_parser_template_argument_list for the + return value. */ + +static tree +cp_parser_enclosed_template_argument_list (cp_parser* parser) +{ + tree arguments; + tree saved_scope; + tree saved_qualifying_scope; + tree saved_object_scope; + bool saved_greater_than_is_operator_p; + + /* [temp.names] + + When parsing a template-id, the first non-nested `>' is taken as + the end of the template-argument-list rather than a greater-than + operator. */ + saved_greater_than_is_operator_p + = parser->greater_than_is_operator_p; + parser->greater_than_is_operator_p = false; + /* Parsing the argument list may modify SCOPE, so we save it + here. */ + saved_scope = parser->scope; + saved_qualifying_scope = parser->qualifying_scope; + saved_object_scope = parser->object_scope; + /* Parse the template-argument-list itself. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER)) + arguments = NULL_TREE; + else + arguments = cp_parser_template_argument_list (parser); + /* Look for the `>' that ends the template-argument-list. If we find + a '>>' instead, it's probably just a typo. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT)) + { + if (!saved_greater_than_is_operator_p) + { + /* If we're in a nested template argument list, the '>>' has to be + a typo for '> >'. We emit the error message, but we continue + parsing and we push a '>' as next token, so that the argument + list will be parsed correctly.. */ + cp_token* token; + error ("`>>' should be `> >' within a nested template argument list"); + token = cp_lexer_peek_token (parser->lexer); + token->type = CPP_GREATER; + } + else + { + /* If this is not a nested template argument list, the '>>' is + a typo for '>'. Emit an error message and continue. */ + error ("spurious `>>', use `>' to terminate a template argument list"); + cp_lexer_consume_token (parser->lexer); + } + } + else if (!cp_parser_require (parser, CPP_GREATER, "`>'")) + error ("missing `>' to terminate the template argument list"); + /* The `>' token might be a greater-than operator again now. */ + parser->greater_than_is_operator_p + = saved_greater_than_is_operator_p; + /* Restore the SAVED_SCOPE. */ + parser->scope = saved_scope; + parser->qualifying_scope = saved_qualifying_scope; + parser->object_scope = saved_object_scope; + + return arguments; +} + +/* MEMBER_FUNCTION is a member function, or a friend. If default + arguments, or the body of the function have not yet been parsed, + parse them now. */ + +static void +cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) +{ + cp_lexer *saved_lexer; + + /* If this member is a template, get the underlying + FUNCTION_DECL. */ + if (DECL_FUNCTION_TEMPLATE_P (member_function)) + member_function = DECL_TEMPLATE_RESULT (member_function); + + /* There should not be any class definitions in progress at this + point; the bodies of members are only parsed outside of all class + definitions. */ + my_friendly_assert (parser->num_classes_being_defined == 0, 20010816); + /* While we're parsing the member functions we might encounter more + classes. We want to handle them right away, but we don't want + them getting mixed up with functions that are currently in the + queue. */ + parser->unparsed_functions_queues + = tree_cons (NULL_TREE, NULL_TREE, parser->unparsed_functions_queues); + + /* Make sure that any template parameters are in scope. */ + maybe_begin_member_template_processing (member_function); + + /* If the body of the function has not yet been parsed, parse it + now. */ + if (DECL_PENDING_INLINE_P (member_function)) + { + tree function_scope; + cp_token_cache *tokens; + + /* The function is no longer pending; we are processing it. */ + tokens = DECL_PENDING_INLINE_INFO (member_function); + DECL_PENDING_INLINE_INFO (member_function) = NULL; + DECL_PENDING_INLINE_P (member_function) = 0; + /* If this was an inline function in a local class, enter the scope + of the containing function. */ + function_scope = decl_function_context (member_function); + if (function_scope) + push_function_context_to (function_scope); + + /* Save away the current lexer. */ + saved_lexer = parser->lexer; + /* Make a new lexer to feed us the tokens saved for this function. */ + parser->lexer = cp_lexer_new_from_tokens (tokens); + parser->lexer->next = saved_lexer; + + /* Set the current source position to be the location of the first + token in the saved inline body. */ + cp_lexer_peek_token (parser->lexer); + + /* Let the front end know that we going to be defining this + function. */ + start_function (NULL_TREE, member_function, NULL_TREE, + SF_PRE_PARSED | SF_INCLASS_INLINE); + + /* Now, parse the body of the function. */ + cp_parser_function_definition_after_declarator (parser, + /*inline_p=*/true); + + /* Leave the scope of the containing function. */ + if (function_scope) + pop_function_context_from (function_scope); + /* Restore the lexer. */ + parser->lexer = saved_lexer; + } + + /* Remove any template parameters from the symbol table. */ + maybe_end_member_template_processing (); + + /* Restore the queue. */ + parser->unparsed_functions_queues + = TREE_CHAIN (parser->unparsed_functions_queues); +} + +/* If DECL contains any default args, remember it on the unparsed + functions queue. */ + +static void +cp_parser_save_default_args (cp_parser* parser, tree decl) +{ + tree probe; + + for (probe = TYPE_ARG_TYPES (TREE_TYPE (decl)); + probe; + probe = TREE_CHAIN (probe)) + if (TREE_PURPOSE (probe)) + { + TREE_PURPOSE (parser->unparsed_functions_queues) + = tree_cons (NULL_TREE, decl, + TREE_PURPOSE (parser->unparsed_functions_queues)); + break; + } + return; +} + +/* FN is a FUNCTION_DECL which may contains a parameter with an + unparsed DEFAULT_ARG. Parse the default args now. */ + +static void +cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) +{ + cp_lexer *saved_lexer; + cp_token_cache *tokens; + bool saved_local_variables_forbidden_p; + tree parameters; + + /* While we're parsing the default args, we might (due to the + statement expression extension) encounter more classes. We want + to handle them right away, but we don't want them getting mixed + up with default args that are currently in the queue. */ + parser->unparsed_functions_queues + = tree_cons (NULL_TREE, NULL_TREE, parser->unparsed_functions_queues); + + for (parameters = TYPE_ARG_TYPES (TREE_TYPE (fn)); + parameters; + parameters = TREE_CHAIN (parameters)) + { + if (!TREE_PURPOSE (parameters) + || TREE_CODE (TREE_PURPOSE (parameters)) != DEFAULT_ARG) + continue; + + /* Save away the current lexer. */ + saved_lexer = parser->lexer; + /* Create a new one, using the tokens we have saved. */ + tokens = DEFARG_TOKENS (TREE_PURPOSE (parameters)); + parser->lexer = cp_lexer_new_from_tokens (tokens); + + /* Set the current source position to be the location of the + first token in the default argument. */ + cp_lexer_peek_token (parser->lexer); + + /* Local variable names (and the `this' keyword) may not appear + in a default argument. */ + saved_local_variables_forbidden_p = parser->local_variables_forbidden_p; + parser->local_variables_forbidden_p = true; + /* Parse the assignment-expression. */ + if (DECL_CLASS_SCOPE_P (fn)) + push_nested_class (DECL_CONTEXT (fn)); + TREE_PURPOSE (parameters) = cp_parser_assignment_expression (parser); + if (DECL_CLASS_SCOPE_P (fn)) + pop_nested_class (); + + /* If the token stream has not been completely used up, then + there was extra junk after the end of the default + argument. */ + if (!cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + cp_parser_error (parser, "expected `,'"); + + /* Restore saved state. */ + parser->lexer = saved_lexer; + parser->local_variables_forbidden_p = saved_local_variables_forbidden_p; + } + + /* Restore the queue. */ + parser->unparsed_functions_queues + = TREE_CHAIN (parser->unparsed_functions_queues); +} + +/* Parse the operand of `sizeof' (or a similar operator). Returns + either a TYPE or an expression, depending on the form of the + input. The KEYWORD indicates which kind of expression we have + encountered. */ + +static tree +cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword) +{ + static const char *format; + tree expr = NULL_TREE; + const char *saved_message; + bool saved_integral_constant_expression_p; + + /* Initialize FORMAT the first time we get here. */ + if (!format) + format = "types may not be defined in `%s' expressions"; + + /* Types cannot be defined in a `sizeof' expression. Save away the + old message. */ + saved_message = parser->type_definition_forbidden_message; + /* And create the new one. */ + parser->type_definition_forbidden_message + = xmalloc (strlen (format) + + strlen (IDENTIFIER_POINTER (ridpointers[keyword])) + + 1 /* `\0' */); + sprintf ((char *) parser->type_definition_forbidden_message, + format, IDENTIFIER_POINTER (ridpointers[keyword])); + + /* The restrictions on constant-expressions do not apply inside + sizeof expressions. */ + saved_integral_constant_expression_p = parser->integral_constant_expression_p; + parser->integral_constant_expression_p = false; + + /* Do not actually evaluate the expression. */ + ++skip_evaluation; + /* If it's a `(', then we might be looking at the type-id + construction. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + tree type; + bool saved_in_type_id_in_expr_p; + + /* We can't be sure yet whether we're looking at a type-id or an + expression. */ + cp_parser_parse_tentatively (parser); + /* Consume the `('. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the type-id. */ + saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; + parser->in_type_id_in_expr_p = true; + type = cp_parser_type_id (parser); + parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; + /* Now, look for the trailing `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* If all went well, then we're done. */ + if (cp_parser_parse_definitely (parser)) + { + /* Build a list of decl-specifiers; right now, we have only + a single type-specifier. */ + type = build_tree_list (NULL_TREE, + type); + + /* Call grokdeclarator to figure out what type this is. */ + expr = grokdeclarator (NULL_TREE, + type, + TYPENAME, + /*initialized=*/0, + /*attrlist=*/NULL); + } + } + + /* If the type-id production did not work out, then we must be + looking at the unary-expression production. */ + if (!expr) + expr = cp_parser_unary_expression (parser, /*address_p=*/false); + /* Go back to evaluating expressions. */ + --skip_evaluation; + + /* Free the message we created. */ + free ((char *) parser->type_definition_forbidden_message); + /* And restore the old one. */ + parser->type_definition_forbidden_message = saved_message; + parser->integral_constant_expression_p = saved_integral_constant_expression_p; + + return expr; +} + +/* If the current declaration has no declarator, return true. */ + +static bool +cp_parser_declares_only_class_p (cp_parser *parser) +{ + /* If the next token is a `;' or a `,' then there is no + declarator. */ + return (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON) + || cp_lexer_next_token_is (parser->lexer, CPP_COMMA)); +} + +/* DECL_SPECIFIERS is the representation of a decl-specifier-seq. + Returns TRUE iff `friend' appears among the DECL_SPECIFIERS. */ + +static bool +cp_parser_friend_p (tree decl_specifiers) +{ + while (decl_specifiers) + { + /* See if this decl-specifier is `friend'. */ + if (TREE_CODE (TREE_VALUE (decl_specifiers)) == IDENTIFIER_NODE + && C_RID_CODE (TREE_VALUE (decl_specifiers)) == RID_FRIEND) + return true; + + /* Go on to the next decl-specifier. */ + decl_specifiers = TREE_CHAIN (decl_specifiers); + } + + return false; +} + +/* If the next token is of the indicated TYPE, consume it. Otherwise, + issue an error message indicating that TOKEN_DESC was expected. + + Returns the token consumed, if the token had the appropriate type. + Otherwise, returns NULL. */ + +static cp_token * +cp_parser_require (cp_parser* parser, + enum cpp_ttype type, + const char* token_desc) +{ + if (cp_lexer_next_token_is (parser->lexer, type)) + return cp_lexer_consume_token (parser->lexer); + else + { + /* Output the MESSAGE -- unless we're parsing tentatively. */ + if (!cp_parser_simulate_error (parser)) + { + char *message = concat ("expected ", token_desc, NULL); + cp_parser_error (parser, message); + free (message); + } + return NULL; + } +} + +/* Like cp_parser_require, except that tokens will be skipped until + the desired token is found. An error message is still produced if + the next token is not as expected. */ + +static void +cp_parser_skip_until_found (cp_parser* parser, + enum cpp_ttype type, + const char* token_desc) +{ + cp_token *token; + unsigned nesting_depth = 0; + + if (cp_parser_require (parser, type, token_desc)) + return; + + /* Skip tokens until the desired token is found. */ + while (true) + { + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If we've reached the token we want, consume it and + stop. */ + if (token->type == type && !nesting_depth) + { + cp_lexer_consume_token (parser->lexer); + return; + } + /* If we've run out of tokens, stop. */ + if (token->type == CPP_EOF) + return; + if (token->type == CPP_OPEN_BRACE + || token->type == CPP_OPEN_PAREN + || token->type == CPP_OPEN_SQUARE) + ++nesting_depth; + else if (token->type == CPP_CLOSE_BRACE + || token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_SQUARE) + { + if (nesting_depth-- == 0) + return; + } + /* Consume this token. */ + cp_lexer_consume_token (parser->lexer); + } +} + +/* If the next token is the indicated keyword, consume it. Otherwise, + issue an error message indicating that TOKEN_DESC was expected. + + Returns the token consumed, if the token had the appropriate type. + Otherwise, returns NULL. */ + +static cp_token * +cp_parser_require_keyword (cp_parser* parser, + enum rid keyword, + const char* token_desc) +{ + cp_token *token = cp_parser_require (parser, CPP_KEYWORD, token_desc); + + if (token && token->keyword != keyword) + { + dyn_string_t error_msg; + + /* Format the error message. */ + error_msg = dyn_string_new (0); + dyn_string_append_cstr (error_msg, "expected "); + dyn_string_append_cstr (error_msg, token_desc); + cp_parser_error (parser, error_msg->s); + dyn_string_delete (error_msg); + return NULL; + } + + return token; +} + +/* Returns TRUE iff TOKEN is a token that can begin the body of a + function-definition. */ + +static bool +cp_parser_token_starts_function_definition_p (cp_token* token) +{ + return (/* An ordinary function-body begins with an `{'. */ + token->type == CPP_OPEN_BRACE + /* A ctor-initializer begins with a `:'. */ + || token->type == CPP_COLON + /* A function-try-block begins with `try'. */ + || token->keyword == RID_TRY + /* The named return value extension begins with `return'. */ + || token->keyword == RID_RETURN); +} + +/* Returns TRUE iff the next token is the ":" or "{" beginning a class + definition. */ + +static bool +cp_parser_next_token_starts_class_definition_p (cp_parser *parser) +{ + cp_token *token; + + token = cp_lexer_peek_token (parser->lexer); + return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON); +} + +/* Returns TRUE iff the next token is the "," or ">" ending a + template-argument. ">>" is also accepted (after the full + argument was parsed) because it's probably a typo for "> >", + and there is a specific diagnostic for this. */ + +static bool +cp_parser_next_token_ends_template_argument_p (cp_parser *parser) +{ + cp_token *token; + + token = cp_lexer_peek_token (parser->lexer); + return (token->type == CPP_COMMA || token->type == CPP_GREATER + || token->type == CPP_RSHIFT); +} + +/* Returns TRUE iff the n-th token is a ">", or the n-th is a "[" and the + (n+1)-th is a ":" (which is a possible digraph typo for "< ::"). */ + +static bool +cp_parser_nth_token_starts_template_argument_list_p (cp_parser * parser, + size_t n) +{ + cp_token *token; + + token = cp_lexer_peek_nth_token (parser->lexer, n); + if (token->type == CPP_LESS) + return true; + /* Check for the sequence `<::' in the original code. It would be lexed as + `[:', where `[' is a digraph, and there is no whitespace before + `:'. */ + if (token->type == CPP_OPEN_SQUARE && token->flags & DIGRAPH) + { + cp_token *token2; + token2 = cp_lexer_peek_nth_token (parser->lexer, n+1); + if (token2->type == CPP_COLON && !(token2->flags & PREV_WHITE)) + return true; + } + return false; +} + +/* Returns the kind of tag indicated by TOKEN, if it is a class-key, + or none_type otherwise. */ + +static enum tag_types +cp_parser_token_is_class_key (cp_token* token) +{ + switch (token->keyword) + { + case RID_CLASS: + return class_type; + case RID_STRUCT: + return record_type; + case RID_UNION: + return union_type; + + default: + return none_type; + } +} + +/* Issue an error message if the CLASS_KEY does not match the TYPE. */ + +static void +cp_parser_check_class_key (enum tag_types class_key, tree type) +{ + if ((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type)) + pedwarn ("`%s' tag used in naming `%#T'", + class_key == union_type ? "union" + : class_key == record_type ? "struct" : "class", + type); +} + +/* Issue an error message if DECL is redeclared with different + access than its original declaration [class.access.spec/3]. + This applies to nested classes and nested class templates. + [class.mem/1]. */ + +static void cp_parser_check_access_in_redeclaration (tree decl) +{ + if (!CLASS_TYPE_P (TREE_TYPE (decl))) + return; + + if ((TREE_PRIVATE (decl) + != (current_access_specifier == access_private_node)) + || (TREE_PROTECTED (decl) + != (current_access_specifier == access_protected_node))) + error ("%D redeclared with different access", decl); +} + +/* Look for the `template' keyword, as a syntactic disambiguator. + Return TRUE iff it is present, in which case it will be + consumed. */ + +static bool +cp_parser_optional_template_keyword (cp_parser *parser) +{ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + { + /* The `template' keyword can only be used within templates; + outside templates the parser can always figure out what is a + template and what is not. */ + if (!processing_template_decl) + { + error ("`template' (as a disambiguator) is only allowed " + "within templates"); + /* If this part of the token stream is rescanned, the same + error message would be generated. So, we purge the token + from the stream. */ + cp_lexer_purge_token (parser->lexer); + return false; + } + else + { + /* Consume the `template' keyword. */ + cp_lexer_consume_token (parser->lexer); + return true; + } + } + + return false; +} + +/* The next token is a CPP_NESTED_NAME_SPECIFIER. Consume the token, + set PARSER->SCOPE, and perform other related actions. */ + +static void +cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser) +{ + tree value; + tree check; + + /* Get the stored value. */ + value = cp_lexer_consume_token (parser->lexer)->value; + /* Perform any access checks that were deferred. */ + for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check)) + perform_or_defer_access_check (TREE_PURPOSE (check), TREE_VALUE (check)); + /* Set the scope from the stored value. */ + parser->scope = TREE_VALUE (value); + parser->qualifying_scope = TREE_TYPE (value); + parser->object_scope = NULL_TREE; +} + +/* Add tokens to CACHE until an non-nested END token appears. */ + +static void +cp_parser_cache_group (cp_parser *parser, + cp_token_cache *cache, + enum cpp_ttype end, + unsigned depth) +{ + while (true) + { + cp_token *token; + + /* Abort a parenthesized expression if we encounter a brace. */ + if ((end == CPP_CLOSE_PAREN || depth == 0) + && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + return; + /* If we've reached the end of the file, stop. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + return; + /* Consume the next token. */ + token = cp_lexer_consume_token (parser->lexer); + /* Add this token to the tokens we are saving. */ + cp_token_cache_push_token (cache, token); + /* See if it starts a new group. */ + if (token->type == CPP_OPEN_BRACE) + { + cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, depth + 1); + if (depth == 0) + return; + } + else if (token->type == CPP_OPEN_PAREN) + cp_parser_cache_group (parser, cache, CPP_CLOSE_PAREN, depth + 1); + else if (token->type == end) + return; + } +} + +/* Begin parsing tentatively. We always save tokens while parsing + tentatively so that if the tentative parsing fails we can restore the + tokens. */ + +static void +cp_parser_parse_tentatively (cp_parser* parser) +{ + /* Enter a new parsing context. */ + parser->context = cp_parser_context_new (parser->context); + /* Begin saving tokens. */ + cp_lexer_save_tokens (parser->lexer); + /* In order to avoid repetitive access control error messages, + access checks are queued up until we are no longer parsing + tentatively. */ + push_deferring_access_checks (dk_deferred); +} + +/* Commit to the currently active tentative parse. */ + +static void +cp_parser_commit_to_tentative_parse (cp_parser* parser) +{ + cp_parser_context *context; + cp_lexer *lexer; + + /* Mark all of the levels as committed. */ + lexer = parser->lexer; + for (context = parser->context; context->next; context = context->next) + { + if (context->status == CP_PARSER_STATUS_KIND_COMMITTED) + break; + context->status = CP_PARSER_STATUS_KIND_COMMITTED; + while (!cp_lexer_saving_tokens (lexer)) + lexer = lexer->next; + cp_lexer_commit_tokens (lexer); + } +} + +/* Abort the currently active tentative parse. All consumed tokens + will be rolled back, and no diagnostics will be issued. */ + +static void +cp_parser_abort_tentative_parse (cp_parser* parser) +{ + cp_parser_simulate_error (parser); + /* Now, pretend that we want to see if the construct was + successfully parsed. */ + cp_parser_parse_definitely (parser); +} + +/* Stop parsing tentatively. If a parse error has occurred, restore the + token stream. Otherwise, commit to the tokens we have consumed. + Returns true if no error occurred; false otherwise. */ + +static bool +cp_parser_parse_definitely (cp_parser* parser) +{ + bool error_occurred; + cp_parser_context *context; + + /* Remember whether or not an error occurred, since we are about to + destroy that information. */ + error_occurred = cp_parser_error_occurred (parser); + /* Remove the topmost context from the stack. */ + context = parser->context; + parser->context = context->next; + /* If no parse errors occurred, commit to the tentative parse. */ + if (!error_occurred) + { + /* Commit to the tokens read tentatively, unless that was + already done. */ + if (context->status != CP_PARSER_STATUS_KIND_COMMITTED) + cp_lexer_commit_tokens (parser->lexer); + + pop_to_parent_deferring_access_checks (); + } + /* Otherwise, if errors occurred, roll back our state so that things + are just as they were before we began the tentative parse. */ + else + { + cp_lexer_rollback_tokens (parser->lexer); + pop_deferring_access_checks (); + } + /* Add the context to the front of the free list. */ + context->next = cp_parser_context_free_list; + cp_parser_context_free_list = context; + + return !error_occurred; +} + +/* Returns true if we are parsing tentatively -- but have decided that + we will stick with this tentative parse, even if errors occur. */ + +static bool +cp_parser_committed_to_tentative_parse (cp_parser* parser) +{ + return (cp_parser_parsing_tentatively (parser) + && parser->context->status == CP_PARSER_STATUS_KIND_COMMITTED); +} + +/* Returns nonzero iff an error has occurred during the most recent + tentative parse. */ + +static bool +cp_parser_error_occurred (cp_parser* parser) +{ + return (cp_parser_parsing_tentatively (parser) + && parser->context->status == CP_PARSER_STATUS_KIND_ERROR); +} + +/* Returns nonzero if GNU extensions are allowed. */ + +static bool +cp_parser_allow_gnu_extensions_p (cp_parser* parser) +{ + return parser->allow_gnu_extensions_p; +} + + + +/* The parser. */ + +static GTY (()) cp_parser *the_parser; + +/* External interface. */ + +/* Parse one entire translation unit. */ + +void +c_parse_file (void) +{ + bool error_occurred; + + the_parser = cp_parser_new (); + push_deferring_access_checks (flag_access_control + ? dk_no_deferred : dk_no_check); + error_occurred = cp_parser_translation_unit (the_parser); + the_parser = NULL; +} + +/* This variable must be provided by every front end. */ + +int yydebug; + +#include "gt-cp-parser.h" |