| /* 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; |
| |
| |