/* C++ Parser.
- Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004,
+ 2005 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
#include "toplev.h"
#include "output.h"
#include "target.h"
+#include "c-common.h"
\f
/* 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. */
+/* The cp_lexer_* routines mediate between the lexer proper (in libcpp
+ and c-lex.c) and the C++ parser. */
/* A C++ token. */
ENUM_BITFIELD (rid) keyword : 8;
/* Token flags. */
unsigned char flags;
+ /* True if this token is from a system header. */
+ BOOL_BITFIELD in_system_header : 1;
+ /* True if this token is from a context where it is implicitly extern "C" */
+ BOOL_BITFIELD implicit_extern_c : 1;
/* 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_CNEW (cp_token_cache);
-}
-
-/* Add *TOKEN to *CACHE. */
+/* We use a stack of token pointer for saving token sets. */
+typedef struct cp_token *cp_token_position;
+DEF_VEC_P (cp_token_position);
+DEF_VEC_ALLOC_P (cp_token_position,heap);
-static void
-cp_token_cache_push_token (cp_token_cache *cache,
- cp_token *token)
+static const cp_token eof_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_CNEW (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;
-}
+ CPP_EOF, RID_MAX, 0, 0, 0, NULL_TREE,
+#if USE_MAPPED_LOCATION
+ 0
+#else
+ {0, 0}
+#endif
+};
/* 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. */
+ it to the parser. Tokens are never added to the cp_lexer after
+ it is created. */
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
+ /* The memory allocated for the buffer. NULL if this lexer does not
+ own the token buffer. */
+ cp_token * GTY ((length ("%h.buffer_length"))) buffer;
+ /* If the lexer owns the buffer, this is the number of tokens in the
+ buffer. */
+ size_t buffer_length;
+
+ /* A pointer just past the last available token. The tokens
+ in this lexer are [buffer, last_token). */
+ cp_token_position GTY ((skip)) last_token;
+
+ /* The next available token. If NEXT_TOKEN is &eof_token, 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;
+ cp_token_position GTY ((skip)) next_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;
+ began saving tokens. If the stack is non-empty, we are saving
+ tokens. */
+ VEC(cp_token_position,heap) *GTY ((skip)) saved_tokens;
/* True if we should output debugging information. */
bool debugging_p;
struct cp_lexer *next;
} cp_lexer;
+/* cp_token_cache is a range of tokens. There is no need to represent
+ allocate heap memory for it, since tokens are never removed from the
+ lexer's array. There is also no need for the GC to walk through
+ a cp_token_cache, since everything in here is referenced through
+ a lexer. */
+
+typedef struct cp_token_cache GTY(())
+{
+ /* The beginning of the token range. */
+ cp_token * GTY((skip)) first;
+
+ /* Points immediately after the last token in the range. */
+ cp_token * GTY ((skip)) last;
+} cp_token_cache;
+
/* Prototypes. */
static cp_lexer *cp_lexer_new_main
(void);
static cp_lexer *cp_lexer_new_from_tokens
- (struct cp_token_cache *);
+ (cp_token_cache *tokens);
+static void cp_lexer_destroy
+ (cp_lexer *);
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 cp_token_position cp_lexer_token_position
+ (cp_lexer *, bool);
+static cp_token *cp_lexer_token_at
+ (cp_lexer *, cp_token_position);
static void cp_lexer_get_preprocessor_token
(cp_lexer *, cp_token *);
-static cp_token *cp_lexer_peek_token
+static inline cp_token *cp_lexer_peek_token
(cp_lexer *);
static cp_token *cp_lexer_peek_nth_token
(cp_lexer *, size_t);
static void cp_lexer_purge_token
(cp_lexer *);
static void cp_lexer_purge_tokens_after
- (cp_lexer *, cp_token *);
+ (cp_lexer *, cp_token_position);
+static void cp_lexer_handle_pragma
+ (cp_lexer *);
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 *);
#ifdef ENABLE_CHECKING
static void cp_lexer_print_token
(FILE *, cp_token *);
static void cp_lexer_stop_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
#else
-#define cp_lexer_debug_stream NULL
-#define cp_lexer_print_token(str, tok)
+/* If we define cp_lexer_debug_stream to NULL it will provoke warnings
+ about passing NULL to functions that require non-NULL arguments
+ (fputs, fprintf). It will never be used, so all we need is a value
+ of the right type that's guaranteed not to be NULL. */
+#define cp_lexer_debug_stream stdout
+#define cp_lexer_print_token(str, tok) (void) 0
#define cp_lexer_debugging_p(lexer) 0
#endif /* ENABLE_CHECKING */
-/* Manifest constants. */
+static cp_token_cache *cp_token_cache_new
+ (cp_token *, cp_token *);
-#define CP_TOKEN_BUFFER_SIZE 5
-#define CP_SAVED_TOKENS_SIZE 5
+/* Manifest constants. */
+#define CP_LEXER_BUFFER_SIZE 10000
+#define CP_SAVED_TOKEN_STACK 5
/* A token type for keywords, as opposed to ordinary identifiers. */
#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
#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)
+ to represent slots in the array where there used to be a token
+ that has now been deleted. */
+#define CPP_PURGED ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1))
+
+/* The number of token types, including C++-specific ones. */
+#define N_CP_TTYPES ((int) (CPP_PURGED + 1))
/* Variables. */
static cp_lexer *
cp_lexer_new_main (void)
{
- cp_lexer *lexer;
cp_token first_token;
+ cp_lexer *lexer;
+ cp_token *pos;
+ size_t alloc;
+ size_t space;
+ cp_token *buffer;
/* 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. */
+ token before allocating any memory. Pragmas must not be deferred
+ as -fpch-preprocess can generate a pragma to load the PCH file in
+ the preprocessed output used by -save-temps. */
cp_lexer_get_preprocessor_token (NULL, &first_token);
- c_common_no_more_pch ();
- /* Allocate the memory. */
- lexer = GGC_CNEW (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));
+ /* Tell cpplib we want CPP_PRAGMA tokens. */
+ cpp_get_options (parse_in)->defer_pragmas = true;
- /* This lexer obtains more tokens by calling c_lex. */
- lexer->main_lexer_p = true;
+ /* Tell c_lex not to merge string constants. */
+ c_lex_return_raw_strings = true;
- /* Create the SAVED_TOKENS stack. */
- VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens");
+ c_common_no_more_pch ();
- /* Create the STRINGS array. */
- VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings");
+ /* Allocate the memory. */
+ lexer = GGC_CNEW (cp_lexer);
#ifdef ENABLE_CHECKING
- /* Assume we are not debugging. */
+ /* Initially we are not debugging. */
lexer->debugging_p = false;
#endif /* ENABLE_CHECKING */
+ lexer->saved_tokens = VEC_alloc (cp_token_position, heap,
+ CP_SAVED_TOKEN_STACK);
+
+ /* Create the buffer. */
+ alloc = CP_LEXER_BUFFER_SIZE;
+ buffer = ggc_alloc (alloc * sizeof (cp_token));
+
+ /* Put the first token in the buffer. */
+ space = alloc;
+ pos = buffer;
+ *pos = first_token;
+
+ /* Get the remaining tokens from the preprocessor. */
+ while (pos->type != CPP_EOF)
+ {
+ pos++;
+ if (!--space)
+ {
+ space = alloc;
+ alloc *= 2;
+ buffer = ggc_realloc (buffer, alloc * sizeof (cp_token));
+ pos = buffer + space;
+ }
+ cp_lexer_get_preprocessor_token (lexer, pos);
+ }
+ lexer->buffer = buffer;
+ lexer->buffer_length = alloc - space;
+ lexer->last_token = pos;
+ lexer->next_token = lexer->buffer_length ? buffer : (cp_token *)&eof_token;
+ /* Pragma processing (via cpp_handle_deferred_pragma) may result in
+ direct calls to c_lex. Those callers all expect c_lex to do
+ string constant concatenation. */
+ c_lex_return_raw_strings = false;
+
+ gcc_assert (lexer->next_token->type != CPP_PURGED);
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. */
+/* Create a new lexer whose token stream is primed with the tokens in
+ CACHE. 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_new_from_tokens (cp_token_cache *cache)
{
- cp_lexer *lexer;
- cp_token *token;
- cp_token_block *block;
- ptrdiff_t num_tokens;
-
- /* Allocate the memory. */
- lexer = GGC_CNEW (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_NEWVEC (cp_token, num_tokens);
- 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");
+ cp_token *first = cache->first;
+ cp_token *last = cache->last;
+ cp_lexer *lexer = GGC_CNEW (cp_lexer);
+
+ /* We do not own the buffer. */
+ lexer->buffer = NULL;
+ lexer->buffer_length = 0;
+ lexer->next_token = first == last ? (cp_token *)&eof_token : first;
+ lexer->last_token = last;
+
+ lexer->saved_tokens = VEC_alloc (cp_token_position, heap,
+ CP_SAVED_TOKEN_STACK);
#ifdef ENABLE_CHECKING
- /* Assume we are not debugging. */
+ /* Initially we are not debugging. */
lexer->debugging_p = false;
-#endif /* ENABLE_CHECKING */
+#endif
+ gcc_assert (lexer->next_token->type != CPP_PURGED);
return lexer;
}
+/* Frees all resources associated with LEXER. */
+
+static void
+cp_lexer_destroy (cp_lexer *lexer)
+{
+ if (lexer->buffer)
+ ggc_free (lexer->buffer);
+ VEC_free (cp_token_position, heap, lexer->saved_tokens);
+ ggc_free (lexer);
+}
+
/* Returns nonzero if debugging information should be output. */
#ifdef ENABLE_CHECKING
#endif /* ENABLE_CHECKING */
-/* 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)
+static inline cp_token_position
+cp_lexer_token_position (cp_lexer *lexer, bool previous_p)
{
- token++;
- if (token == lexer->buffer_end)
- token = lexer->buffer;
- return token;
+ gcc_assert (!previous_p || lexer->next_token != &eof_token);
+
+ return lexer->next_token - previous_p;
}
-/* 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)
+cp_lexer_token_at (cp_lexer *lexer ATTRIBUTE_UNUSED, cp_token_position pos)
{
- if (token == lexer->buffer)
- token = lexer->buffer_end;
- return token - 1;
+ return pos;
}
/* nonzero if we are presently saving tokens. */
-static int
+static inline 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)
- {
- if (c_lex_string_translate)
- {
- tree value = token->value;
- tree type;
-
- /* We might as well go ahead and release the chained
- translated string such that we can reuse its memory. */
- if (TREE_CHAIN (value))
- value = TREE_CHAIN (token->value);
-
- /* Get the current type. It will be an ARRAY_TYPE. */
- type = TREE_TYPE (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 (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;
- }
+ return VEC_length (cp_token_position, lexer->saved_tokens) != 0;
}
-/* Store the next token from the preprocessor in *TOKEN. */
+/* Store the next token from the preprocessor in *TOKEN. Return true
+ if we reach EOF. */
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 = UNKNOWN_LOCATION;
- token->value = NULL_TREE;
- token->keyword = RID_MAX;
-
- return;
- }
+ static int is_extern_c = 0;
- 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;
+ /* Get a new token from the preprocessor. */
+ token->type
+ = c_lex_with_flags (&token->value, &token->location, &token->flags);
+ token->in_system_header = in_system_header;
- default:
- /* This is a good token, so we exit the loop. */
- done = true;
- break;
- }
- }
- /* Now we've got our token. */
- token->location = input_location;
+ /* On some systems, some header files are surrounded by an
+ implicit extern "C" block. Set a flag in the token if it
+ comes from such a header. */
+ is_extern_c += pending_lang_change;
+ pending_lang_change = 0;
+ token->implicit_extern_c = is_extern_c > 0;
/* Check to see if this token is a keyword. */
if (token->type == CPP_NAME
mapped to `const'. */
token->value = ridpointers[token->keyword];
}
+ /* Handle Objective-C++ keywords. */
+ else if (token->type == CPP_AT_NAME)
+ {
+ token->type = CPP_KEYWORD;
+ switch (C_RID_CODE (token->value))
+ {
+ /* Map 'class' to '@class', 'private' to '@private', etc. */
+ case RID_CLASS: token->keyword = RID_AT_CLASS; break;
+ case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break;
+ case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break;
+ case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break;
+ case RID_THROW: token->keyword = RID_AT_THROW; break;
+ case RID_TRY: token->keyword = RID_AT_TRY; break;
+ case RID_CATCH: token->keyword = RID_AT_CATCH; break;
+ default: token->keyword = C_RID_CODE (token->value);
+ }
+ }
else
token->keyword = RID_MAX;
}
+/* Update the globals input_location and in_system_header from TOKEN. */
+static inline void
+cp_lexer_set_source_position_from_token (cp_token *token)
+{
+ if (token->type != CPP_EOF)
+ {
+ input_location = token->location;
+ in_system_header = token->in_system_header;
+ }
+}
+
/* 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)
+static inline 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: ");
+ fputs ("cp_lexer: peeking at token: ", cp_lexer_debug_stream);
cp_lexer_print_token (cp_lexer_debug_stream, lexer->next_token);
- fprintf (cp_lexer_debug_stream, "\n");
+ putc ('\n', cp_lexer_debug_stream);
}
-
- token = lexer->next_token;
- cp_lexer_set_source_position_from_token (lexer, token);
- return token;
+ return lexer->next_token;
}
/* Return true if the next token has the indicated TYPE. */
-static bool
+static inline 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 cp_lexer_peek_token (lexer)->type == type;
}
/* Return true if the next token does not have the indicated TYPE. */
-static bool
+static inline 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
+static inline bool
cp_lexer_next_token_is_keyword (cp_lexer* lexer, enum rid keyword)
{
cp_token *token;
}
/* 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. */
+ then this is precisely equivalent to cp_lexer_peek_token (except
+ that it is not inline). One would like to disallow that case, but
+ there is one case (cp_parser_nth_token_starts_template_id) where
+ the caller passes a variable for N and it might be 1. */
static cp_token *
cp_lexer_peek_nth_token (cp_lexer* lexer, size_t n)
cp_token *token;
/* N is 1-based, not zero-based. */
- gcc_assert (n > 0);
+ gcc_assert (n > 0 && lexer->next_token != &eof_token);
+
+ if (cp_lexer_debugging_p (lexer))
+ fprintf (cp_lexer_debug_stream,
+ "cp_lexer: peeking ahead %ld at token: ", (long)n);
- /* Skip ahead from NEXT_TOKEN, reading more tokens as necessary. */
+ --n;
token = lexer->next_token;
- /* If there are no tokens in the buffer, get one now. */
- if (!token)
+ while (n != 0)
{
- cp_lexer_read_token (lexer);
- token = lexer->next_token;
+ ++token;
+ if (token == lexer->last_token)
+ {
+ token = (cp_token *)&eof_token;
+ break;
+ }
+
+ if (token->type != CPP_PURGED)
+ --n;
}
- /* Now, read tokens until we have enough. */
- while (--n > 0)
+ if (cp_lexer_debugging_p (lexer))
{
- /* 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);
+ cp_lexer_print_token (cp_lexer_debug_stream, token);
+ putc ('\n', cp_lexer_debug_stream);
}
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. */
+/* Return the next token, and advance the lexer's next_token pointer
+ to point to the next non-purged token. */
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;
+ cp_token *token = lexer->next_token;
- /* If we're not saving tokens, then move FIRST_TOKEN too. */
- if (!cp_lexer_saving_tokens (lexer))
+ gcc_assert (token != &eof_token);
+
+ do
{
- /* 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;
+ lexer->next_token++;
+ if (lexer->next_token == lexer->last_token)
+ {
+ lexer->next_token = (cp_token *)&eof_token;
+ break;
+ }
+
}
-
+ while (lexer->next_token->type == CPP_PURGED);
+
+ cp_lexer_set_source_position_from_token (token);
+
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
{
- fprintf (cp_lexer_debug_stream, "cp_lexer: consuming token: ");
+ fputs ("cp_lexer: consuming token: ", cp_lexer_debug_stream);
cp_lexer_print_token (cp_lexer_debug_stream, token);
- fprintf (cp_lexer_debug_stream, "\n");
+ putc ('\n', cp_lexer_debug_stream);
}
-
+
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. */
+/* Permanently remove the next token from the token stream, and
+ advance the next_token pointer to refer to the next non-purged
+ token. */
static void
cp_lexer_purge_token (cp_lexer *lexer)
{
- cp_token *token;
- cp_token *next_token;
+ cp_token *tok = lexer->next_token;
+
+ gcc_assert (tok != &eof_token);
+ tok->type = CPP_PURGED;
+ tok->location = UNKNOWN_LOCATION;
+ tok->value = NULL_TREE;
+ tok->keyword = RID_MAX;
- token = lexer->next_token;
- while (true)
+ do
{
- next_token = cp_lexer_next_token (lexer, token);
- if (next_token == lexer->last_token)
- break;
- *token = *next_token;
- token = next_token;
+ tok++;
+ if (tok == lexer->last_token)
+ {
+ tok = (cp_token *)&eof_token;
+ break;
+ }
}
-
- 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;
+ while (tok->type == CPP_PURGED);
+ lexer->next_token = tok;
}
-/* Permanently remove all tokens after TOKEN, up to, but not
+/* Permanently remove all tokens after TOK, 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_lexer_purge_tokens_after (cp_lexer *lexer, cp_token *tok)
{
- cp_token *peek;
- cp_token *t1;
- cp_token *t2;
+ cp_token *peek = lexer->next_token;
- 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
+ if (peek == &eof_token)
+ peek = lexer->last_token;
+
+ gcc_assert (tok < peek);
+
+ for ( tok += 1; tok != peek; tok += 1)
{
- /* 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);
+ tok->type = CPP_PURGED;
+ tok->location = UNKNOWN_LOCATION;
+ tok->value = NULL_TREE;
+ tok->keyword = RID_MAX;
}
}
+/* Consume and handle a pragma token. */
+static void
+cp_lexer_handle_pragma (cp_lexer *lexer)
+{
+ cpp_string s;
+ cp_token *token = cp_lexer_consume_token (lexer);
+ gcc_assert (token->type == CPP_PRAGMA);
+ gcc_assert (token->value);
+
+ s.len = TREE_STRING_LENGTH (token->value);
+ s.text = (const unsigned char *) TREE_STRING_POINTER (token->value);
+
+ cpp_handle_deferred_pragma (parse_in, &s);
+
+ /* Clearing token->value here means that we will get an ICE if we
+ try to process this #pragma again (which should be impossible). */
+ token->value = NULL;
+}
+
/* Begin saving tokens. All tokens consumed after this point will be
preserved. */
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));
+ VEC_safe_push (cp_token_position, heap,
+ lexer->saved_tokens, lexer->next_token);
}
/* Commit to the portion of the token stream most recently saved. */
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: committing tokens\n");
- VARRAY_POP (lexer->saved_tokens);
+ VEC_pop (cp_token_position, lexer->saved_tokens);
}
/* Return all tokens saved since the last call to cp_lexer_save_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);
+ lexer->next_token = VEC_pop (cp_token_position, lexer->saved_tokens);
}
/* Print a representation of the TOKEN on the STREAM. */
#ifdef ENABLE_CHECKING
static void
-cp_lexer_print_token (FILE * stream, cp_token* token)
+cp_lexer_print_token (FILE * stream, cp_token *token)
{
- const char *token_type = NULL;
+ /* We don't use cpp_type2name here because the parser defines
+ a few tokens of its own. */
+ static const char *const token_names[] = {
+ /* cpplib-defined token types */
+#define OP(e, s) #e,
+#define TK(e, s) #e,
+ TTYPE_TABLE
+#undef OP
+#undef TK
+ /* C++ parser token types - see "Manifest constants", above. */
+ "KEYWORD",
+ "TEMPLATE_ID",
+ "NESTED_NAME_SPECIFIER",
+ "PURGED"
+ };
+
+ /* If we have a name for the token, print it out. Otherwise, we
+ simply give the numeric code. */
+ gcc_assert (token->type < ARRAY_SIZE(token_names));
+ fputs (token_names[token->type], stream);
- /* Figure out what kind of token this is. */
+ /* For some tokens, print the associated data. */
switch (token->type)
{
- case CPP_EQ:
- token_type = "EQ";
- break;
-
- case CPP_COMMA:
- token_type = "COMMA";
+ case CPP_KEYWORD:
+ /* Some keywords have a value that is not an IDENTIFIER_NODE.
+ For example, `struct' is mapped to an INTEGER_CST. */
+ if (TREE_CODE (token->value) != IDENTIFIER_NODE)
+ break;
+ /* else fall through */
+ case CPP_NAME:
+ fputs (IDENTIFIER_POINTER (token->value), stream);
break;
- case CPP_OPEN_PAREN:
- token_type = "OPEN_PAREN";
+ case CPP_STRING:
+ case CPP_WSTRING:
+ case CPP_PRAGMA:
+ fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->value));
break;
- case CPP_CLOSE_PAREN:
- token_type = "CLOSE_PAREN";
+ default:
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. */
+/* Start emitting debugging information. */
static void
cp_lexer_start_debugging (cp_lexer* lexer)
{
- ++lexer->debugging_p;
+ lexer->debugging_p = true;
}
/* Stop emitting debugging information. */
static void
cp_lexer_stop_debugging (cp_lexer* lexer)
{
- --lexer->debugging_p;
+ lexer->debugging_p = false;
}
#endif /* ENABLE_CHECKING */
+/* Create a new cp_token_cache, representing a range of tokens. */
+
+static cp_token_cache *
+cp_token_cache_new (cp_token *first, cp_token *last)
+{
+ cp_token_cache *cache = GGC_NEW (cp_token_cache);
+ cache->first = first;
+ cache->last = last;
+ return cache;
+}
+
\f
/* Decl-specifiers. */
Other parts of the front end that need to create entities (like
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
-static cp_declarator *make_id_declarator
- (tree);
static cp_declarator *make_call_declarator
(cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree);
static cp_declarator *make_array_declarator
return declarator;
}
-/* Make a declarator for a generalized identifier. */
+/* Make a declarator for a generalized identifier. If non-NULL, the
+ identifier is QUALIFYING_SCOPE::UNQUALIFIED_NAME; otherwise, it is
+ just UNQUALIFIED_NAME. */
-cp_declarator *
-make_id_declarator (tree id)
+static cp_declarator *
+make_id_declarator (tree qualifying_scope, tree unqualified_name)
{
cp_declarator *declarator;
+ /* It is valid to write:
+
+ class C { void f(); };
+ typedef C D;
+ void D::f();
+
+ The standard is not clear about whether `typedef const C D' is
+ legal; as of 2002-09-15 the committee is considering that
+ question. EDG 3.0 allows that syntax. Therefore, we do as
+ well. */
+ if (qualifying_scope && TYPE_P (qualifying_scope))
+ qualifying_scope = TYPE_MAIN_VARIANT (qualifying_scope);
+
declarator = make_declarator (cdk_id);
- declarator->u.id.name = id;
+ declarator->u.id.qualifying_scope = qualifying_scope;
+ declarator->u.id.unqualified_name = unqualified_name;
declarator->u.id.sfk = sfk_none;
return declarator;
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. */
+ The performance of the parser could probably be improved substantially.
+ 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. */
CP_PARSER_DECLARATOR_EITHER
} cp_parser_declarator_kind;
-/* A mapping from a token type to a corresponding tree node type. */
+/* The precedence values used to parse binary expressions. The minimum value
+ of PREC must be 1, because zero is reserved to quickly discriminate
+ binary operators from other tokens. */
-typedef struct cp_parser_token_tree_map_node
+enum cp_parser_prec
+{
+ PREC_NOT_OPERATOR,
+ PREC_LOGICAL_OR_EXPRESSION,
+ PREC_LOGICAL_AND_EXPRESSION,
+ PREC_INCLUSIVE_OR_EXPRESSION,
+ PREC_EXCLUSIVE_OR_EXPRESSION,
+ PREC_AND_EXPRESSION,
+ PREC_EQUALITY_EXPRESSION,
+ PREC_RELATIONAL_EXPRESSION,
+ PREC_SHIFT_EXPRESSION,
+ PREC_ADDITIVE_EXPRESSION,
+ PREC_MULTIPLICATIVE_EXPRESSION,
+ PREC_PM_EXPRESSION,
+ NUM_PREC_VALUES = PREC_PM_EXPRESSION
+};
+
+/* A mapping from a token type to a corresponding tree node type, with a
+ precedence value. */
+
+typedef struct cp_parser_binary_operations_map_node
{
/* The token type. */
- ENUM_BITFIELD (cpp_ttype) token_type : 8;
+ enum cpp_ttype token_type;
/* 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[];
+ enum tree_code tree_type;
+ /* The precedence of this operator. */
+ enum cp_parser_prec prec;
+} cp_parser_binary_operations_map_node;
/* The status of a tentative parse. */
CP_PARSER_STATUS_KIND_COMMITTED
} cp_parser_status_kind;
-/* Context that is saved and restored when parsing tentatively. */
+typedef struct cp_parser_expression_stack_entry
+{
+ tree lhs;
+ enum tree_code tree_type;
+ int prec;
+} cp_parser_expression_stack_entry;
+/* The stack for storing partial expressions. We only need NUM_PREC_VALUES
+ entries because precedence levels on the stack are monotonically
+ increasing. */
+typedef struct cp_parser_expression_stack_entry
+ cp_parser_expression_stack[NUM_PREC_VALUES];
+
+/* 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
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;
static GTY((deletable)) cp_parser_context* cp_parser_context_free_list;
+/* The operator-precedence table used by cp_parser_binary_expression.
+ Transformed into an associative array (binops_by_token) by
+ cp_parser_new. */
+
+static const cp_parser_binary_operations_map_node binops[] = {
+ { CPP_DEREF_STAR, MEMBER_REF, PREC_PM_EXPRESSION },
+ { CPP_DOT_STAR, DOTSTAR_EXPR, PREC_PM_EXPRESSION },
+
+ { CPP_MULT, MULT_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
+ { CPP_DIV, TRUNC_DIV_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
+ { CPP_MOD, TRUNC_MOD_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
+
+ { CPP_PLUS, PLUS_EXPR, PREC_ADDITIVE_EXPRESSION },
+ { CPP_MINUS, MINUS_EXPR, PREC_ADDITIVE_EXPRESSION },
+
+ { CPP_LSHIFT, LSHIFT_EXPR, PREC_SHIFT_EXPRESSION },
+ { CPP_RSHIFT, RSHIFT_EXPR, PREC_SHIFT_EXPRESSION },
+
+ { CPP_LESS, LT_EXPR, PREC_RELATIONAL_EXPRESSION },
+ { CPP_GREATER, GT_EXPR, PREC_RELATIONAL_EXPRESSION },
+ { CPP_LESS_EQ, LE_EXPR, PREC_RELATIONAL_EXPRESSION },
+ { CPP_GREATER_EQ, GE_EXPR, PREC_RELATIONAL_EXPRESSION },
+ { CPP_MIN, MIN_EXPR, PREC_RELATIONAL_EXPRESSION },
+ { CPP_MAX, MAX_EXPR, PREC_RELATIONAL_EXPRESSION },
+
+ { CPP_EQ_EQ, EQ_EXPR, PREC_EQUALITY_EXPRESSION },
+ { CPP_NOT_EQ, NE_EXPR, PREC_EQUALITY_EXPRESSION },
+
+ { CPP_AND, BIT_AND_EXPR, PREC_AND_EXPRESSION },
+
+ { CPP_XOR, BIT_XOR_EXPR, PREC_EXCLUSIVE_OR_EXPRESSION },
+
+ { CPP_OR, BIT_IOR_EXPR, PREC_INCLUSIVE_OR_EXPRESSION },
+
+ { CPP_AND_AND, TRUTH_ANDIF_EXPR, PREC_LOGICAL_AND_EXPRESSION },
+
+ { CPP_OR_OR, TRUTH_ORIF_EXPR, PREC_LOGICAL_OR_EXPRESSION }
+};
+
+/* The same as binops, but initialized by cp_parser_new so that
+ binops_by_token[N].token_type == N. Used in cp_parser_binary_expression
+ for speed. */
+static cp_parser_binary_operations_map_node binops_by_token[N_CP_TTYPES];
+
/* Constructors and destructors. */
/* Construct a new context. The context below this one on the stack
}
else
context = GGC_CNEW (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
alternatives. */
bool in_type_id_in_expr_p;
+ /* TRUE if we are currently in a header file where declarations are
+ implicitly extern "C". */
+ bool implicit_extern_c;
+
+ /* TRUE if strings in expressions should be translated to the execution
+ character set. */
+ bool translate_strings_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. */
static tree cp_parser_identifier
(cp_parser *);
+static tree cp_parser_string_literal
+ (cp_parser *, bool, bool);
/* Basic concepts [gram.basic] */
/* Expressions [gram.expr] */
static tree cp_parser_primary_expression
- (cp_parser *, cp_id_kind *, tree *);
+ (cp_parser *, bool, cp_id_kind *, tree *);
static tree cp_parser_id_expression
(cp_parser *, bool, bool, bool *, bool);
static tree cp_parser_unqualified_id
static tree cp_parser_class_or_namespace_name
(cp_parser *, bool, bool, bool, bool, bool);
static tree cp_parser_postfix_expression
- (cp_parser *, bool);
+ (cp_parser *, bool, bool);
static tree cp_parser_postfix_open_square_expression
(cp_parser *, tree, bool);
static tree cp_parser_postfix_dot_deref_expression
(cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *);
static tree cp_parser_parenthesized_expression_list
- (cp_parser *, bool, bool *);
+ (cp_parser *, bool, bool, bool *);
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree *, tree *);
static tree cp_parser_unary_expression
- (cp_parser *, bool);
+ (cp_parser *, bool, bool);
static enum tree_code cp_parser_unary_operator
(cp_token *);
static tree cp_parser_new_expression
static tree cp_parser_delete_expression
(cp_parser *);
static tree cp_parser_cast_expression
+ (cp_parser *, bool, bool);
+static tree cp_parser_binary_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 *);
+ (cp_parser *, bool);
static enum tree_code cp_parser_assignment_operator_opt
(cp_parser *);
static tree cp_parser_expression
- (cp_parser *);
+ (cp_parser *, bool);
static tree cp_parser_constant_expression
(cp_parser *, bool, bool *);
static tree cp_parser_builtin_offsetof
static tree cp_parser_init_declarator
(cp_parser *, cp_decl_specifier_seq *, bool, bool, int, bool *);
static cp_declarator *cp_parser_declarator
- (cp_parser *, cp_parser_declarator_kind, int *, bool *);
+ (cp_parser *, cp_parser_declarator_kind, int *, bool *, bool);
static cp_declarator *cp_parser_direct_declarator
- (cp_parser *, cp_parser_declarator_kind, int *);
+ (cp_parser *, cp_parser_declarator_kind, int *, bool);
static enum tree_code cp_parser_ptr_operator
(cp_parser *, tree *, cp_cv_quals *);
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
static tree cp_parser_type_id
(cp_parser *);
static void cp_parser_type_specifier_seq
- (cp_parser *, cp_decl_specifier_seq *);
+ (cp_parser *, bool, cp_decl_specifier_seq *);
static cp_parameter_declarator *cp_parser_parameter_declaration_clause
(cp_parser *);
static cp_parameter_declarator *cp_parser_parameter_declaration_list
/* Classes [gram.class] */
static tree cp_parser_class_name
- (cp_parser *, bool, bool, bool, bool, bool, bool);
+ (cp_parser *, bool, bool, enum tag_types, bool, bool, bool);
static tree cp_parser_class_specifier
(cp_parser *);
static tree cp_parser_class_head
static void cp_parser_label_declaration
(cp_parser *);
+/* Objective-C++ Productions */
+
+static tree cp_parser_objc_message_receiver
+ (cp_parser *);
+static tree cp_parser_objc_message_args
+ (cp_parser *);
+static tree cp_parser_objc_message_expression
+ (cp_parser *);
+static tree cp_parser_objc_encode_expression
+ (cp_parser *);
+static tree cp_parser_objc_defs_expression
+ (cp_parser *);
+static tree cp_parser_objc_protocol_expression
+ (cp_parser *);
+static tree cp_parser_objc_selector_expression
+ (cp_parser *);
+static tree cp_parser_objc_expression
+ (cp_parser *);
+static bool cp_parser_objc_selector_p
+ (enum cpp_ttype);
+static tree cp_parser_objc_selector
+ (cp_parser *);
+static tree cp_parser_objc_protocol_refs_opt
+ (cp_parser *);
+static void cp_parser_objc_declaration
+ (cp_parser *);
+static tree cp_parser_objc_statement
+ (cp_parser *);
+
/* Utility Routines */
static tree cp_parser_lookup_name
- (cp_parser *, tree, bool, bool, bool, bool, bool *);
+ (cp_parser *, tree, enum tag_types, bool, bool, bool, bool *);
static tree cp_parser_lookup_name_simple
(cp_parser *, tree);
static tree cp_parser_maybe_treat_template_as_class
(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
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);
+ (cp_parser *, enum cpp_ttype, unsigned);
static void cp_parser_parse_tentatively
(cp_parser *);
static void cp_parser_commit_to_tentative_parse
(cp_parser *);
static inline bool cp_parser_parsing_tentatively
(cp_parser *);
-static bool cp_parser_committed_to_tentative_parse
+static bool cp_parser_uncommitted_to_tentative_parse_p
(cp_parser *);
static void cp_parser_error
(cp_parser *, const char *);
static void cp_parser_check_type_definition
(cp_parser *);
static void cp_parser_check_for_definition_in_return_type
- (cp_declarator *, int);
+ (cp_declarator *, tree);
static void cp_parser_check_for_invalid_template_id
(cp_parser *, tree);
static bool cp_parser_non_integral_constant_expression
return token->keyword == keyword;
}
-/* Issue the indicated error MESSAGE. */
+/* A minimum or maximum operator has been seen. As these are
+ deprecated, issue a warning. */
+
+static inline void
+cp_parser_warn_min_max (void)
+{
+ if (warn_deprecated && !in_system_header)
+ warning (0, "minimum/maximum operators are deprecated");
+}
+
+/* If not parsing tentatively, issue a diagnostic of the form
+ FILE:LINE: MESSAGE before TOKEN
+ where TOKEN is the next token in the input stream. MESSAGE
+ (specified by the caller) is usually of the form "expected
+ OTHER-TOKEN". */
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);
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ /* This diagnostic makes more sense if it is tagged to the line
+ of the token we just peeked at. */
+ cp_lexer_set_source_position_from_token (token);
+ if (token->type == CPP_PRAGMA)
+ {
+ error ("%<#pragma%> is not allowed here");
+ cp_lexer_purge_token (parser->lexer);
+ return;
+ }
c_parse_error (message,
/* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like
if (decl == error_mark_node)
{
if (parser->scope && parser->scope != global_namespace)
- error ("`%D::%D' has not been declared",
+ error ("%<%D::%D%> has not been declared",
parser->scope, name);
else if (parser->scope == global_namespace)
- error ("`::%D' has not been declared", name);
+ error ("%<::%D%> has not been declared", name);
else if (parser->object_scope
&& !CLASS_TYPE_P (parser->object_scope))
- error ("request for member `%D' in non-class type `%T'",
+ error ("request for member %qD in non-class type %qT",
name, parser->object_scope);
else if (parser->object_scope)
- error ("`%T::%D' has not been declared",
+ error ("%<%T::%D%> has not been declared",
parser->object_scope, name);
else
- error ("`%D' has not been declared", name);
+ error ("%qD has not been declared", name);
}
else if (parser->scope && parser->scope != global_namespace)
- error ("`%D::%D' %s", parser->scope, name, desired);
+ error ("%<%D::%D%> %s", parser->scope, name, desired);
else if (parser->scope == global_namespace)
- error ("`::%D' %s", name, desired);
+ error ("%<::%D%> %s", name, desired);
else
- error ("`%D' %s", name, desired);
+ error ("%qD %s", name, desired);
}
/* If we are parsing tentatively, remember that an error has occurred
static bool
cp_parser_simulate_error (cp_parser* parser)
{
- if (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
{
parser->context->status = CP_PARSER_STATUS_KIND_ERROR;
return true;
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. */
+/* This function is called when the DECLARATOR is processed. The TYPE
+ was a type defined in the decl-specifiers. If it is invalid to
+ define a type in the decl-specifiers for DECLARATOR, an error is
+ issued. */
static void
cp_parser_check_for_definition_in_return_type (cp_declarator *declarator,
- int declares_class_or_enum)
+ tree type)
{
/* [dcl.fct] forbids type definitions in return types.
Unfortunately, it's not easy to know whether or not we are
|| declarator->kind == cdk_ptrmem))
declarator = declarator->declarator;
if (declarator
- && declarator->kind == cdk_function
- && declares_class_or_enum & 2)
- error ("new types may not be defined in a return type");
+ && declarator->kind == cdk_function)
+ {
+ error ("new types may not be defined in a return type");
+ inform ("(perhaps a semicolon is missing after the definition of %qT)",
+ type);
+ }
}
/* A type-specifier (TYPE) has been parsed which cannot be followed by
cp_parser_check_for_invalid_template_id (cp_parser* parser,
tree type)
{
- ptrdiff_t start;
- cp_token *token;
+ cp_token_position start = 0;
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
{
if (TYPE_P (type))
- error ("`%T' is not a template", type);
+ error ("%qT is not a template", type);
else if (TREE_CODE (type) == IDENTIFIER_NODE)
- error ("`%E' is not a template", type);
+ error ("%qE is not a template", 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;
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
+ start = cp_lexer_token_position (parser->lexer, true);
/* 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 (start)
+ cp_lexer_purge_tokens_after (parser->lexer, start);
}
}
/* 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. */
+ return false. In either case, set
+ PARSER->NON_INTEGRAL_CONSTANT_EXPRESSION_P. */
static bool
cp_parser_non_integral_constant_expression (cp_parser *parser,
const char *thing)
{
+ parser->non_integral_constant_expression_p = true;
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;
}
-/* Emit a diagnostic for an invalid type name. Consider also if it is
- qualified or not and the result of a lookup, to provide a better
- message. */
+/* Emit a diagnostic for an invalid type name. SCOPE is the
+ qualifying scope (or NULL, if none) for ID. This function commits
+ to the current active tentative parse, if any. (Otherwise, the
+ problematic construct might be encountered again later, resulting
+ in duplicate error messages.) */
static void
cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
/* If the lookup found a template-name, it means that the user forgot
to specify an argument list. Emit an useful error message. */
if (TREE_CODE (decl) == TEMPLATE_DECL)
- error ("invalid use of template-name `%E' without an argument list",
+ error ("invalid use of template-name %qE without an argument list",
decl);
else if (!parser->scope)
{
/* Issue an error message. */
- error ("`%E' does not name a type", id);
+ error ("%qE does not name a type", id);
/* 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 B : public A<T> { X x; };
The user should have said "typename A<T>::X". */
- if (processing_template_decl && current_class_type)
+ if (processing_template_decl && current_class_type
+ && TYPE_BINFO (current_class_type))
{
tree b;
if (TREE_CODE (field) == TYPE_DECL
&& DECL_NAME (field) == id)
{
- inform ("(perhaps `typename %T::%E' was intended)",
+ inform ("(perhaps %<typename %T::%E%> was intended)",
BINFO_TYPE (b), id);
break;
}
else
{
if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
- error ("`%E' in namespace `%E' does not name a type",
+ error ("%qE in namespace %qE does not name a type",
id, parser->scope);
else if (TYPE_P (parser->scope))
- error ("`%E' in class `%T' does not name a type",
- id, parser->scope);
+ error ("%qE in class %qT does not name a type", id, parser->scope);
else
gcc_unreachable ();
}
+ cp_parser_commit_to_tentative_parse (parser);
}
/* Check for a common situation where a type-name should be present,
cp_parser_abort_tentative_parse (parser);
return false;
}
- if (!cp_parser_parse_definitely (parser))
+ if (!cp_parser_parse_definitely (parser)
+ || TREE_CODE (id) != IDENTIFIER_NODE)
return false;
- /* If we got here, this cannot be a valid variable declaration, thus
- the cp_parser_id_expression must have resolved to a plain identifier
- node (not a TYPE_DECL or TEMPLATE_ID_EXPR). */
- gcc_assert (TREE_CODE (id) == IDENTIFIER_NODE);
/* Emit a diagnostic for the invalid type. */
cp_parser_diagnose_invalid_type_name (parser, parser->scope, id);
/* Skip to the end of the declaration; there's no point in
{
unsigned paren_depth = 0;
unsigned brace_depth = 0;
- int saved_c_lex_string_translate = c_lex_string_translate;
int result;
- if (recovering && !or_comma && cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
+ if (recovering && !or_comma
+ && cp_parser_uncommitted_to_tentative_parse_p (parser))
return 0;
- if (! recovering)
- /* If we're looking ahead, keep both translated and untranslated
- strings. */
- c_lex_string_translate = -1;
-
while (true)
{
cp_token *token;
cp_lexer_consume_token (parser->lexer);
}
- c_lex_string_translate = saved_c_lex_string_translate;
return result;
}
tree result;
if (TREE_CODE (id) == IDENTIFIER_NODE)
{
- result = make_typename_type (scope, id, /*complain=*/0);
+ result = make_typename_type (scope, id, typename_type,
+ /*complain=*/0);
if (result == error_mark_node)
cp_parser_diagnose_invalid_type_name (parser, scope, id);
return result;
}
- return make_typename_type (scope, id, tf_error);
+ return make_typename_type (scope, id, typename_type, tf_error);
}
{
cp_parser *parser;
cp_lexer *lexer;
+ unsigned i;
/* 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 ();
+ /* Initialize the binops_by_token so that we can get the tree
+ directly from the token. */
+ for (i = 0; i < sizeof (binops) / sizeof (binops[0]); i++)
+ binops_by_token[binops[i].token_type] = binops[i];
+
parser = GGC_CNEW (cp_parser);
parser->lexer = lexer;
parser->context = cp_parser_context_new (NULL);
/* We are not parsing a type-id inside an expression. */
parser->in_type_id_in_expr_p = false;
+ /* Declarations aren't implicitly extern "C". */
+ parser->implicit_extern_c = false;
+
+ /* String literals should be translated to the execution character set. */
+ parser->translate_strings_p = true;
+
/* The unparsed function queue is empty. */
parser->unparsed_functions_queues = build_tree_list (NULL_TREE, NULL_TREE);
return parser;
}
+/* Create a cp_lexer structure which will emit the tokens in CACHE
+ and push it onto the parser's lexer stack. This is used for delayed
+ parsing of in-class method bodies and default arguments, and should
+ not be confused with tentative parsing. */
+static void
+cp_parser_push_lexer_for_tokens (cp_parser *parser, cp_token_cache *cache)
+{
+ cp_lexer *lexer = cp_lexer_new_from_tokens (cache);
+ lexer->next = parser->lexer;
+ parser->lexer = lexer;
+
+ /* Move the current source position to that of the first token in the
+ new lexer. */
+ cp_lexer_set_source_position_from_token (lexer->next_token);
+}
+
+/* Pop the top lexer off the parser stack. This is never used for the
+ "main" lexer, only for those pushed by cp_parser_push_lexer_for_tokens. */
+static void
+cp_parser_pop_lexer (cp_parser *parser)
+{
+ cp_lexer *lexer = parser->lexer;
+ parser->lexer = lexer->next;
+ cp_lexer_destroy (lexer);
+
+ /* Put the current source position back where it was before this
+ lexer was pushed. */
+ cp_lexer_set_source_position_from_token (parser->lexer->next_token);
+}
+
/* Lexical conventions [gram.lex] */
/* Parse an identifier. Returns an IDENTIFIER_NODE representing the
return token ? token->value : error_mark_node;
}
+/* Parse a sequence of adjacent string constants. Returns a
+ TREE_STRING representing the combined, nul-terminated string
+ constant. If TRANSLATE is true, translate the string to the
+ execution character set. If WIDE_OK is true, a wide string is
+ invalid here.
+
+ C++98 [lex.string] says that if a narrow string literal token is
+ adjacent to a wide string literal token, the behavior is undefined.
+ However, C99 6.4.5p4 says that this results in a wide string literal.
+ We follow C99 here, for consistency with the C front end.
+
+ This code is largely lifted from lex_string() in c-lex.c.
+
+ FUTURE: ObjC++ will need to handle @-strings here. */
+static tree
+cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
+{
+ tree value;
+ bool wide = false;
+ size_t count;
+ struct obstack str_ob;
+ cpp_string str, istr, *strs;
+ cp_token *tok;
+
+ tok = cp_lexer_peek_token (parser->lexer);
+ if (!cp_parser_is_string_literal (tok))
+ {
+ cp_parser_error (parser, "expected string-literal");
+ return error_mark_node;
+ }
+
+ /* Try to avoid the overhead of creating and destroying an obstack
+ for the common case of just one string. */
+ if (!cp_parser_is_string_literal
+ (cp_lexer_peek_nth_token (parser->lexer, 2)))
+ {
+ cp_lexer_consume_token (parser->lexer);
+
+ str.text = (const unsigned char *)TREE_STRING_POINTER (tok->value);
+ str.len = TREE_STRING_LENGTH (tok->value);
+ count = 1;
+ if (tok->type == CPP_WSTRING)
+ wide = true;
+
+ strs = &str;
+ }
+ else
+ {
+ gcc_obstack_init (&str_ob);
+ count = 0;
+
+ do
+ {
+ cp_lexer_consume_token (parser->lexer);
+ count++;
+ str.text = (unsigned char *)TREE_STRING_POINTER (tok->value);
+ str.len = TREE_STRING_LENGTH (tok->value);
+ if (tok->type == CPP_WSTRING)
+ wide = true;
+
+ obstack_grow (&str_ob, &str, sizeof (cpp_string));
+
+ tok = cp_lexer_peek_token (parser->lexer);
+ }
+ while (cp_parser_is_string_literal (tok));
+
+ strs = (cpp_string *) obstack_finish (&str_ob);
+ }
+
+ if (wide && !wide_ok)
+ {
+ cp_parser_error (parser, "a wide string is invalid in this context");
+ wide = false;
+ }
+
+ if ((translate ? cpp_interpret_string : cpp_interpret_string_notranslate)
+ (parse_in, strs, count, &istr, wide))
+ {
+ value = build_string (istr.len, (char *)istr.text);
+ free ((void *)istr.text);
+
+ TREE_TYPE (value) = wide ? wchar_array_type_node : char_array_type_node;
+ value = fix_string_type (value);
+ }
+ else
+ /* cpp_interpret_string has issued an error. */
+ value = error_mark_node;
+
+ if (count > 1)
+ obstack_free (&str_ob, 0);
+
+ return value;
+}
+
+
/* Basic concepts [gram.basic] */
/* Parse a translation-unit.
/* If there are no tokens left then all went well. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
{
- /* Consume the EOF token. */
- cp_parser_require (parser, CPP_EOF, "end-of-file");
+ /* Get rid of the token array; we don't need it any more. */
+ cp_lexer_destroy (parser->lexer);
+ parser->lexer = NULL;
+
+ /* This file might have been a context that's implicitly extern
+ "C". If so, pop the lang context. (Only relevant for PCH.) */
+ if (parser->implicit_extern_c)
+ {
+ pop_lang_context ();
+ parser->implicit_extern_c = false;
+ }
/* Finish up. */
finish_translation_unit ();
( compound-statement )
__builtin_va_arg ( assignment-expression , type-id )
+ Objective-C++ Extension:
+
+ primary-expression:
+ objc-expression
+
literal:
__null
+ CAST_P is true if this primary expression is the target of a cast.
+
Returns a representation of the expression.
*IDK indicates what kind of id-expression (if any) was present.
static tree
cp_parser_primary_expression (cp_parser *parser,
+ bool cast_p,
cp_id_kind *idk,
tree *qualifying_class)
{
case CPP_WCHAR:
case CPP_NUMBER:
token = cp_lexer_consume_token (parser->lexer);
+ /* Floating-point literals are only allowed in an integral
+ constant expression if they are cast to an integral or
+ enumeration type. */
+ if (TREE_CODE (token->value) == REAL_CST
+ && parser->integral_constant_expression_p
+ && pedantic)
+ {
+ /* CAST_P will be set even in invalid code like "int(2.7 +
+ ...)". Therefore, we have to check that the next token
+ is sure to end the cast. */
+ if (cast_p)
+ {
+ cp_token *next_token;
+
+ next_token = cp_lexer_peek_token (parser->lexer);
+ if (/* The comma at the end of an
+ enumerator-definition. */
+ next_token->type != CPP_COMMA
+ /* The curly brace at the end of an enum-specifier. */
+ && next_token->type != CPP_CLOSE_BRACE
+ /* The end of a statement. */
+ && next_token->type != CPP_SEMICOLON
+ /* The end of the cast-expression. */
+ && next_token->type != CPP_CLOSE_PAREN
+ /* The end of an array bound. */
+ && next_token->type != CPP_CLOSE_SQUARE)
+ cast_p = false;
+ }
+
+ /* If we are within a cast, then the constraint that the
+ cast is to an integral or enumeration type will be
+ checked at that point. If we are not within a cast, then
+ this code is invalid. */
+ if (!cast_p)
+ cp_parser_non_integral_constant_expression
+ (parser, "floating-point literal");
+ }
return token->value;
case CPP_STRING:
case CPP_WSTRING:
- token = cp_lexer_consume_token (parser->lexer);
- if (TREE_CHAIN (token->value))
- return TREE_CHAIN (token->value);
- else
- return token->value;
+ /* ??? Should wide strings be allowed when parser->translate_strings_p
+ is false (i.e. in attributes)? If not, we can kill the third
+ argument to cp_parser_string_literal. */
+ return cp_parser_string_literal (parser,
+ parser->translate_strings_p,
+ true);
case CPP_OPEN_PAREN:
{
else
{
/* Parse the parenthesized expression. */
- expr = cp_parser_expression (parser);
+ expr = cp_parser_expression (parser, cast_p);
/* 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
cp_lexer_consume_token (parser->lexer);
if (parser->local_variables_forbidden_p)
{
- error ("`this' may not be used in this context");
+ error ("%<this%> may not be used in this context");
return error_mark_node;
}
/* Pointers cannot appear in constant-expressions. */
/* Look for the opening `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Now, parse the assignment-expression. */
- expression = cp_parser_assignment_expression (parser);
+ expression = cp_parser_assignment_expression (parser,
+ /*cast_p=*/false);
/* Look for the `,'. */
cp_parser_require (parser, CPP_COMMA, "`,'");
/* Parse the type-id. */
case RID_OFFSETOF:
return cp_parser_builtin_offsetof (parser);
+ /* Objective-C++ expressions. */
+ case RID_AT_ENCODE:
+ case RID_AT_PROTOCOL:
+ case RID_AT_SELECTOR:
+ return cp_parser_objc_expression (parser);
+
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
bool ambiguous_p;
decl = cp_parser_lookup_name (parser, id_expression,
- /*is_type=*/false,
+ none_type,
/*is_template=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true,
been issued. */
if (ambiguous_p)
return error_mark_node;
+
+ /* In Objective-C++, an instance variable (ivar) may be preferred
+ to whatever cp_parser_lookup_name() found. */
+ decl = objc_lookup_ivar (decl, id_expression);
+
/* If name lookup gives us a SCOPE_REF, then the
qualifying scope was dependent. Just propagate the
name. */
decl = check_for_out_of_scope_variable (decl);
if (local_variable_p (decl))
{
- error ("local variable `%D' may not appear in this context",
+ error ("local variable %qD may not appear in this context",
decl);
return error_mark_node;
}
/* Anything else is an error. */
default:
+ /* ...unless we have an Objective-C++ message or string literal, that is. */
+ if (c_dialect_objc ()
+ && (token->type == CPP_OPEN_SQUARE || token->type == CPP_OBJC_STRING))
+ return cp_parser_objc_expression (parser);
+
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
/*typename_keyword_p=*/false,
check_dependency_p,
/*type_p=*/false,
- /*is_declarator=*/false)
+ declarator_p)
!= NULL_TREE);
/* If there is a nested-name-specifier, then we are looking at
the first qualified-id production. */
tree qualifying_scope;
tree object_scope;
tree scope;
+ bool done;
/* Consume the `~' token. */
cp_lexer_consume_token (parser->lexer);
/* If there was an explicit qualification (S::~T), first look
in the scope given by the qualification (i.e., S). */
+ done = false;
+ type_decl = NULL_TREE;
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,
+ none_type,
/*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));
+ done = true;
}
/* In "N::S::~S", look in "N" as well. */
- if (scope && qualifying_scope)
+ if (!done && scope && qualifying_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = qualifying_scope;
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- /*type_p=*/false,
+ none_type,
/*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));
+ done = true;
}
/* In "p->S::~T", look in the scope given by "*p" as well. */
- else if (object_scope)
+ else if (!done && object_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = object_scope;
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- /*type_p=*/false,
+ none_type,
/*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));
+ done = true;
}
/* 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 (!done)
+ {
+ 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,
+ none_type,
+ /*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
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",
+ && !DECL_SELF_REFERENCE_P (type_decl)
+ && !cp_parser_uncommitted_to_tentative_parse_p (parser))
+ error ("typedef-name %qD used as destructor declarator",
type_decl);
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
{
bool success = false;
tree access_check = NULL_TREE;
- ptrdiff_t start;
- cp_token* token;
+ cp_token_position start = 0;
+ 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
}
/* 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;
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
+ start = cp_lexer_token_position (parser->lexer, false);
push_deferring_access_checks (dk_deferred);
might destroy it. */
old_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
+ /* In a declarator-id like "X<T>::I::Y<T>" we must be able to
+ look up names in "X<T>::I" in order to determine that "Y" is
+ a template. So, if we have a typename at this point, we make
+ an effort to look through it. */
+ if (is_declaration
+ && !typename_keyword_p
+ && parser->scope
+ && TREE_CODE (parser->scope) == TYPENAME_TYPE)
+ parser->scope = resolve_typename_type (parser->scope,
+ /*only_current_p=*/false);
/* Parse the qualifying entity. */
new_scope
= cp_parser_class_or_namespace_name (parser,
decl = cp_parser_lookup_name_simple (parser, token->value);
if (TREE_CODE (decl) == TEMPLATE_DECL)
- error ("`%D' used without template parameters",
- decl);
+ error ("%qD used without template parameters", decl);
else
cp_parser_name_lookup_error
(parser, token->value, decl,
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)
+ if (success && start)
{
- /* Find the token that corresponds to the start of the
- template-id. */
- token = cp_lexer_advance_token (parser->lexer,
- parser->lexer->first_token,
- start);
-
+ cp_token *token = cp_lexer_token_at (parser->lexer, 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);
+ cp_lexer_purge_tokens_after (parser->lexer, start);
}
pop_deferring_access_checks ();
scope = cp_parser_class_name (parser,
typename_keyword_p,
template_keyword_p,
- type_p,
+ type_p ? class_type : none_type,
check_dependency_p,
/*class_head_p=*/false,
is_declaration);
but they are essentially the same concept.)
If ADDRESS_P is true, the postfix expression is the operand of the
- `&' operator.
+ `&' operator. CAST_P is true if this expression is the target of a
+ cast.
Returns a representation of the expression. */
static tree
-cp_parser_postfix_expression (cp_parser *parser, bool address_p)
+cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
{
cp_token *token;
enum rid keyword;
/* And the expression which is being cast. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/true);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Only type conversions to integral or enumeration types
tree expression;
/* Look for an expression. */
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
/* Compute its typeid. */
postfix_expression = build_typeid (expression);
/* Look for the `)' token. */
bool template_p = false;
tree id;
tree type;
+ tree scope;
/* Consume the `typename' token. */
cp_lexer_consume_token (parser->lexer);
/* Look for the optional `::' operator. */
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
- /* Look for the nested-name-specifier. */
- cp_parser_nested_name_specifier (parser,
- /*typename_keyword_p=*/true,
- /*check_dependency_p=*/true,
- /*type_p=*/true,
- /*is_declaration=*/true);
+ /* Look for the nested-name-specifier. In case of error here,
+ consume the trailing id to avoid subsequent error messages
+ for usual cases. */
+ scope = cp_parser_nested_name_specifier (parser,
+ /*typename_keyword_p=*/true,
+ /*check_dependency_p=*/true,
+ /*type_p=*/true,
+ /*is_declaration=*/true);
+
/* Look for the optional `template' keyword. */
template_p = cp_parser_optional_template_keyword (parser);
/* We don't know whether we're looking at a template-id or an
/* If that didn't work, try an identifier. */
if (!cp_parser_parse_definitely (parser))
id = cp_parser_identifier (parser);
+
+ /* Don't process id if nested name specifier is invalid. */
+ if (scope == error_mark_node)
+ return error_mark_node;
/* If we look up a template-id in a non-dependent qualifying
scope, there's no need to create a dependent type. */
- if (TREE_CODE (id) == TYPE_DECL
+ else if (TREE_CODE (id) == TYPE_DECL
&& !dependent_type_p (parser->scope))
type = TREE_TYPE (id);
/* Create a TYPENAME_TYPE to represent the type to which the
functional cast is being performed. */
else
type = make_typename_type (parser->scope, id,
+ typename_type,
/*complain=*/1);
postfix_expression = cp_parser_functional_cast (parser, type);
/* It must be a primary-expression. */
postfix_expression = cp_parser_primary_expression (parser,
+ cast_p,
&idk,
&qualifying_class);
}
/* postfix-expression ( expression-list [opt] ) */
{
bool koenig_p;
- tree args = (cp_parser_parenthesized_expression_list
- (parser, false, /*non_constant_p=*/NULL));
+ bool is_builtin_constant_p;
+ bool saved_integral_constant_expression_p = false;
+ bool saved_non_integral_constant_expression_p = false;
+ tree args;
+
+ is_builtin_constant_p
+ = DECL_IS_BUILTIN_CONSTANT_P (postfix_expression);
+ if (is_builtin_constant_p)
+ {
+ /* The whole point of __builtin_constant_p is to allow
+ non-constant expressions to appear as arguments. */
+ saved_integral_constant_expression_p
+ = parser->integral_constant_expression_p;
+ saved_non_integral_constant_expression_p
+ = parser->non_integral_constant_expression_p;
+ parser->integral_constant_expression_p = false;
+ }
+ args = (cp_parser_parenthesized_expression_list
+ (parser, /*is_attribute_list=*/false,
+ /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
+ if (is_builtin_constant_p)
+ {
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
+ }
if (args == error_mark_node)
{
/* Function calls are not permitted in
constant-expressions. */
- if (cp_parser_non_integral_constant_expression (parser,
- "a function call"))
+ if (! builtin_valid_in_constant_expr_p (postfix_expression)
+ && cp_parser_non_integral_constant_expression (parser,
+ "a function call"))
{
postfix_expression = error_mark_node;
break;
koenig_p = false;
if (idk == CP_ID_KIND_UNQUALIFIED)
{
+ if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
+ {
+ if (args)
+ {
+ koenig_p = true;
+ postfix_expression
+ = perform_koenig_lookup (postfix_expression, args);
+ }
+ else
+ postfix_expression
+ = unqualified_fn_lookup_error (postfix_expression);
+ }
/* We do not perform argument-dependent lookup if
normal lookup finds a non-function, in accordance
with the expected resolution of DR 218. */
- if (args
- && (is_overloaded_fn (postfix_expression)
- || TREE_CODE (postfix_expression) == IDENTIFIER_NODE))
+ else if (args && is_overloaded_fn (postfix_expression))
{
- koenig_p = true;
- postfix_expression
- = perform_koenig_lookup (postfix_expression, args);
+ tree fn = get_first_fn (postfix_expression);
+
+ if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+ fn = OVL_CURRENT (TREE_OPERAND (fn, 0));
+
+ /* Only do argument dependent lookup if regular
+ lookup does not find a set of member functions.
+ [basic.lookup.koenig]/2a */
+ if (!DECL_FUNCTION_MEMBER_P (fn))
+ {
+ koenig_p = true;
+ postfix_expression
+ = perform_koenig_lookup (postfix_expression, args);
+ }
}
- else if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
- postfix_expression
- = unqualified_fn_lookup_error (postfix_expression);
}
if (TREE_CODE (postfix_expression) == COMPONENT_REF)
if (for_offsetof)
index = cp_parser_constant_expression (parser, false, NULL);
else
- index = cp_parser_expression (parser);
+ index = cp_parser_expression (parser, /*cast_p=*/false);
/* Look for the closing `]'. */
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
tree name;
bool dependent_p;
bool template_p;
+ bool pseudo_destructor_p;
tree scope = NULL_TREE;
/* If this is a `->' operator, dereference the pointer. */
postfix_expression = error_mark_node;
}
- /* If the SCOPE is not a scalar type, we are looking at an
- ordinary class member access expression, rather than a
- pseudo-destructor-name. */
- if (!scope || !SCALAR_TYPE_P (scope))
+ /* Assume this expression is not a pseudo-destructor access. */
+ pseudo_destructor_p = false;
+
+ /* If the SCOPE is a scalar type, then, if this is a valid program,
+ we must be looking at a pseudo-destructor-name. */
+ if (scope && SCALAR_TYPE_P (scope))
{
- template_p = cp_parser_optional_template_keyword (parser);
- /* Parse the id-expression. */
- name = cp_parser_id_expression (parser, template_p,
- /*check_dependency_p=*/true,
- /*template_p=*/NULL,
- /*declarator_p=*/false);
- /* In general, build a SCOPE_REF if the member name is qualified.
- However, if the name was not dependent and has already been
- resolved; there is no need to build the SCOPE_REF. For example;
+ tree s;
+ tree type;
- struct X { void f(); };
+ cp_parser_parse_tentatively (parser);
+ /* Parse the pseudo-destructor-name. */
+ s = NULL_TREE;
+ cp_parser_pseudo_destructor_name (parser, &s, &type);
+ if (cp_parser_parse_definitely (parser))
+ {
+ pseudo_destructor_p = true;
+ postfix_expression
+ = finish_pseudo_destructor_expr (postfix_expression,
+ s, TREE_TYPE (type));
+ }
+ }
+
+ if (!pseudo_destructor_p)
+ {
+ /* If the SCOPE is not a scalar type, we are looking at an
+ ordinary class member access expression, rather than a
+ pseudo-destructor-name. */
+ template_p = cp_parser_optional_template_keyword (parser);
+ /* Parse the id-expression. */
+ name = cp_parser_id_expression (parser, template_p,
+ /*check_dependency_p=*/true,
+ /*template_p=*/NULL,
+ /*declarator_p=*/false);
+ /* In general, build a SCOPE_REF if the member name is qualified.
+ However, if the name was not dependent and has already been
+ resolved; there is no need to build the SCOPE_REF. For example;
+
+ struct X { void f(); };
template <typename T> void f(T* t) { t->X::f(); }
Even though "t" is dependent, "X::f" is not and has been resolved
if (parser->scope)
*idk = CP_ID_KIND_QUALIFIED;
- if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
+ /* If the name is a template-id that names a type, we will get a
+ TYPE_DECL here. That is invalid code. */
+ if (TREE_CODE (name) == TYPE_DECL)
{
- name = build_nt (SCOPE_REF, parser->scope, name);
- parser->scope = NULL_TREE;
- parser->qualifying_scope = NULL_TREE;
- parser->object_scope = NULL_TREE;
+ error ("invalid use of %qD", name);
+ postfix_expression = error_mark_node;
+ }
+ else
+ {
+ if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
+ {
+ name = build_nt (SCOPE_REF, parser->scope, name);
+ parser->scope = NULL_TREE;
+ parser->qualifying_scope = NULL_TREE;
+ parser->object_scope = NULL_TREE;
+ }
+ if (scope && name && BASELINK_P (name))
+ adjust_result_of_qualified_name_lookup
+ (name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
+ postfix_expression
+ = finish_class_member_access_expr (postfix_expression, name);
}
- if (scope && name && BASELINK_P (name))
- adjust_result_of_qualified_name_lookup
- (name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
- postfix_expression
- = finish_class_member_access_expr (postfix_expression, name);
- }
- /* Otherwise, try the pseudo-destructor-name production. */
- else
- {
- tree s = NULL_TREE;
- tree type;
-
- /* Parse the pseudo-destructor-name. */
- cp_parser_pseudo_destructor_name (parser, &s, &type);
- /* Form the call. */
- postfix_expression
- = finish_pseudo_destructor_expr (postfix_expression,
- s, TREE_TYPE (type));
}
/* We no longer need to look up names in the scope of the object on
identifier
identifier, expression-list
+ CAST_P is true if this expression is the target of a cast.
+
Returns a TREE_LIST. The TREE_VALUE of each node is a
representation of an assignment-expression. Note that a TREE_LIST
is returned even if there is only a single expression in the list.
static tree
cp_parser_parenthesized_expression_list (cp_parser* parser,
bool is_attribute_list,
+ bool cast_p,
bool *non_constant_p)
{
tree expression_list = NULL_TREE;
+ bool fold_expr_p = is_attribute_list;
tree identifier = NULL_TREE;
/* Assume all the expressions will be constant. */
*non_constant_p = true;
}
else
- expr = cp_parser_assignment_expression (parser);
+ expr = cp_parser_assignment_expression (parser, cast_p);
+
+ if (fold_expr_p)
+ expr = fold_non_dependent_expr (expr);
/* Add it to the list. We add error_mark_node
expressions to the list, so that we can still tell if
&& identifier
ADDRESS_P is true iff the unary-expression is appearing as the
- operand of the `&' operator.
+ operand of the `&' operator. CAST_P is true if this expression is
+ the target of a cast.
Returns a representation of the expression. */
static tree
-cp_parser_unary_expression (cp_parser *parser, bool address_p)
+cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p)
{
cp_token *token;
enum tree_code unary_operator;
token = cp_lexer_consume_token (parser->lexer);
/* Parse the cast-expression. */
cast_expression
- = cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR);
+ = cp_parser_cast_expression (parser,
+ unary_operator == ADDR_EXPR,
+ /*cast_p=*/false);
/* Now, build an appropriate representation. */
switch (unary_operator)
{
non_constant_p = (unary_operator == PREINCREMENT_EXPR
? "`++'" : "`--'");
/* Fall through. */
- case CONVERT_EXPR:
+ case UNARY_PLUS_EXPR:
case NEGATE_EXPR:
case TRUTH_NOT_EXPR:
expression = finish_unary_op_expr (unary_operator, cast_expression);
return expression;
}
- return cp_parser_postfix_expression (parser, address_p);
+ return cp_parser_postfix_expression (parser, address_p, cast_p);
}
/* Returns ERROR_MARK if TOKEN is not a unary-operator. If TOKEN is a
return ADDR_EXPR;
case CPP_PLUS:
- return CONVERT_EXPR;
+ return UNARY_PLUS_EXPR;
case CPP_MINUS:
return NEGATE_EXPR;
inform ("try removing the parentheses around the type-id");
cp_parser_direct_new_declarator (parser);
}
- nelts = integer_one_node;
+ nelts = NULL_TREE;
}
/* Otherwise, there must be a new-type-id. */
else
/* Parse the expression-list. */
expression_list = (cp_parser_parenthesized_expression_list
- (parser, false, /*non_constant_p=*/NULL));
+ (parser, false, /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
return expression_list;
}
parser->type_definition_forbidden_message
= "types may not be defined in a new-type-id";
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, &type_specifier_seq);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifier_seq);
/* Restore the old message. */
parser->type_definition_forbidden_message = saved_message;
/* Parse the new-declarator. */
*nelts = declarator->u.array.bounds;
if (*nelts == error_mark_node)
*nelts = integer_one_node;
- else if (!processing_template_decl)
- {
- if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, *nelts,
- false))
- pedwarn ("size in array new must have integral type");
- *nelts = save_expr (cp_convert (sizetype, *nelts));
- if (*nelts == integer_zero_node)
- warning ("zero size array reserves no space");
- }
+
if (outer_declarator)
outer_declarator->declarator = declarator->declarator;
else
/* The first expression is not required to be constant. */
if (!declarator)
{
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
/* The standard requires that the expression have integral
type. DR 74 adds enumeration types. We believe that the
real intent is that these expressions be handled like the
/*complain=*/true);
if (!expression)
{
- error ("expression in new-declarator must have integral or enumeration type");
+ error ("expression in new-declarator must have integral "
+ "or enumeration type");
expression = error_mark_node;
}
}
tree expression_list;
expression_list = (cp_parser_parenthesized_expression_list
- (parser, false, /*non_constant_p=*/NULL));
+ (parser, false, /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
if (!expression_list)
expression_list = void_zero_node;
unary-expression
( type-id ) cast-expression
+ ADDRESS_P is true iff the unary-expression is appearing as the
+ operand of the `&' operator. CAST_P is true if this expression is
+ the target of a cast.
+
Returns a representation of the expression. */
static tree
-cp_parser_cast_expression (cp_parser *parser, bool address_p)
+cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p)
{
/* If it's a `(', then we might be looking at a cast. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
ctor of T, but looks like a cast to function returning T
without a dependent expression. */
if (!cp_parser_error_occurred (parser))
- expr = cp_parser_simple_cast_expression (parser);
+ expr = cp_parser_cast_expression (parser,
+ /*address_p=*/false,
+ /*cast_p=*/true);
if (cp_parser_parse_definitely (parser))
{
&& !in_system_header
&& !VOID_TYPE_P (type)
&& current_lang_name != lang_name_c)
- warning ("use of old-style cast");
+ warning (0, "use of old-style cast");
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
/* If we get here, then it's not a cast, so it must be a
unary-expression. */
- return cp_parser_unary_expression (parser, address_p);
+ return cp_parser_unary_expression (parser, address_p, cast_p);
}
-/* Parse a pm-expression.
+/* Parse a binary expression of the general form:
pm-expression:
cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression
- Returns a representation of the expression. */
-
-static tree
-cp_parser_pm_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_DEREF_STAR, MEMBER_REF },
- { CPP_DOT_STAR, DOTSTAR_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
-
- return cp_parser_binary_expression (parser, map,
- cp_parser_simple_cast_expression);
-}
-
-/* Parse a multiplicative-expression.
-
multiplicative-expression:
pm-expression
multiplicative-expression * pm-expression
multiplicative-expression / pm-expression
multiplicative-expression % pm-expression
- Returns a representation of the expression. */
-
-static tree
-cp_parser_multiplicative_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_MULT, MULT_EXPR },
- { CPP_DIV, TRUNC_DIV_EXPR },
- { CPP_MOD, TRUNC_MOD_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
-
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_pm_expression);
-}
-
-/* Parse an additive-expression.
-
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
- Returns a representation of the expression. */
-
-static tree
-cp_parser_additive_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_PLUS, PLUS_EXPR },
- { CPP_MINUS, MINUS_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
-
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_multiplicative_expression);
-}
-
-/* Parse a shift-expression.
-
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
- Returns a representation of the expression. */
-
-static tree
-cp_parser_shift_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_LSHIFT, LSHIFT_EXPR },
- { CPP_RSHIFT, RSHIFT_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
-
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_additive_expression);
-}
-
-/* Parse a relational-expression.
-
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
- GNU Extension:
-
+ GNU Extension:
+
relational-expression:
relational-expression <? shift-expression
relational-expression >? shift-expression
- Returns a representation of the expression. */
-
-static tree
-cp_parser_relational_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_LESS, LT_EXPR },
- { CPP_GREATER, GT_EXPR },
- { CPP_LESS_EQ, LE_EXPR },
- { CPP_GREATER_EQ, GE_EXPR },
- { CPP_MIN, MIN_EXPR },
- { CPP_MAX, MAX_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
-
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_shift_expression);
-}
-
-/* Parse an equality-expression.
-
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
- Returns a representation of the expression. */
-
-static tree
-cp_parser_equality_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_EQ_EQ, EQ_EXPR },
- { CPP_NOT_EQ, NE_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
-
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_relational_expression);
-}
-
-/* Parse an and-expression.
-
and-expression:
equality-expression
and-expression & equality-expression
- Returns a representation of the expression. */
-
-static tree
-cp_parser_and_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_AND, BIT_AND_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
-
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_equality_expression);
-}
-
-/* Parse an exclusive-or-expression.
-
exclusive-or-expression:
and-expression
exclusive-or-expression ^ and-expression
- Returns a representation of the expression. */
+ inclusive-or-expression:
+ exclusive-or-expression
+ inclusive-or-expression | exclusive-or-expression
-static tree
-cp_parser_exclusive_or_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_XOR, BIT_XOR_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
+ logical-and-expression:
+ inclusive-or-expression
+ logical-and-expression && inclusive-or-expression
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_and_expression);
-}
+ logical-or-expression:
+ logical-and-expression
+ logical-or-expression || logical-and-expression
+ All these are implemented with a single function like:
-/* Parse an inclusive-or-expression.
+ binary-expression:
+ simple-cast-expression
+ binary-expression <token> binary-expression
- inclusive-or-expression:
- exclusive-or-expression
- inclusive-or-expression | exclusive-or-expression
+ CAST_P is true if this expression is the target of a cast.
- Returns a representation of the expression. */
+ The binops_by_token map is used to get the tree codes for each <token> type.
+ binary-expressions are associated according to a precedence table. */
+
+#define TOKEN_PRECEDENCE(token) \
+ ((token->type == CPP_GREATER && !parser->greater_than_is_operator_p) \
+ ? PREC_NOT_OPERATOR \
+ : binops_by_token[token->type].prec)
static tree
-cp_parser_inclusive_or_expression (cp_parser* parser)
+cp_parser_binary_expression (cp_parser* parser, bool cast_p)
{
- static const cp_parser_token_tree_map map = {
- { CPP_OR, BIT_IOR_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
-
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_exclusive_or_expression);
-}
+ cp_parser_expression_stack stack;
+ cp_parser_expression_stack_entry *sp = &stack[0];
+ tree lhs, rhs;
+ cp_token *token;
+ enum tree_code tree_type;
+ enum cp_parser_prec prec = PREC_NOT_OPERATOR, new_prec, lookahead_prec;
+ bool overloaded_p;
-/* Parse a logical-and-expression.
+ /* Parse the first expression. */
+ lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p);
- logical-and-expression:
- inclusive-or-expression
- logical-and-expression && inclusive-or-expression
+ for (;;)
+ {
+ /* Get an operator token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_MIN || token->type == CPP_MAX)
+ cp_parser_warn_min_max ();
+
+ new_prec = TOKEN_PRECEDENCE (token);
+
+ /* Popping an entry off the stack means we completed a subexpression:
+ - either we found a token which is not an operator (`>' where it is not
+ an operator, or prec == PREC_NOT_OPERATOR), in which case popping
+ will happen repeatedly;
+ - or, we found an operator which has lower priority. This is the case
+ where the recursive descent *ascends*, as in `3 * 4 + 5' after
+ parsing `3 * 4'. */
+ if (new_prec <= prec)
+ {
+ if (sp == stack)
+ break;
+ else
+ goto pop;
+ }
- Returns a representation of the expression. */
+ get_rhs:
+ tree_type = binops_by_token[token->type].tree_type;
-static tree
-cp_parser_logical_and_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_AND_AND, TRUTH_ANDIF_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
+ /* We used the operator token. */
+ cp_lexer_consume_token (parser->lexer);
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_inclusive_or_expression);
-}
+ /* Extract another operand. It may be the RHS of this expression
+ or the LHS of a new, higher priority expression. */
+ rhs = cp_parser_simple_cast_expression (parser);
-/* Parse a logical-or-expression.
+ /* Get another operator token. Look up its precedence to avoid
+ building a useless (immediately popped) stack entry for common
+ cases such as 3 + 4 + 5 or 3 * 4 + 5. */
+ token = cp_lexer_peek_token (parser->lexer);
+ lookahead_prec = TOKEN_PRECEDENCE (token);
+ if (lookahead_prec > new_prec)
+ {
+ /* ... and prepare to parse the RHS of the new, higher priority
+ expression. Since precedence levels on the stack are
+ monotonically increasing, we do not have to care about
+ stack overflows. */
+ sp->prec = prec;
+ sp->tree_type = tree_type;
+ sp->lhs = lhs;
+ sp++;
+ lhs = rhs;
+ prec = new_prec;
+ new_prec = lookahead_prec;
+ goto get_rhs;
+
+ pop:
+ /* If the stack is not empty, we have parsed into LHS the right side
+ (`4' in the example above) of an expression we had suspended.
+ We can use the information on the stack to recover the LHS (`3')
+ from the stack together with the tree code (`MULT_EXPR'), and
+ the precedence of the higher level subexpression
+ (`PREC_ADDITIVE_EXPRESSION'). TOKEN is the CPP_PLUS token,
+ which will be used to actually build the additive expression. */
+ --sp;
+ prec = sp->prec;
+ tree_type = sp->tree_type;
+ rhs = lhs;
+ lhs = sp->lhs;
+ }
- logical-or-expression:
- logical-and-expression
- logical-or-expression || logical-and-expression
+ overloaded_p = false;
+ lhs = build_x_binary_op (tree_type, lhs, rhs, &overloaded_p);
- Returns a representation of the expression. */
+ /* If the binary operator required the use of an overloaded operator,
+ then this expression cannot be an integral constant-expression.
+ An overloaded operator can be used even if both operands are
+ otherwise permissible in an integral constant-expression if at
+ least one of the operands is of enumeration type. */
-static tree
-cp_parser_logical_or_expression (cp_parser* parser)
-{
- static const cp_parser_token_tree_map map = {
- { CPP_OR_OR, TRUTH_ORIF_EXPR },
- { CPP_EOF, ERROR_MARK }
- };
+ if (overloaded_p
+ && (cp_parser_non_integral_constant_expression
+ (parser, "calls to overloaded operators")))
+ return error_mark_node;
+ }
- return cp_parser_binary_expression (parser,
- map,
- cp_parser_logical_and_expression);
+ return lhs;
}
+
/* Parse the `? expression : assignment-expression' part of a
conditional-expression. The LOGICAL_OR_EXPR is the
logical-or-expression that started the conditional-expression.
expr = NULL_TREE;
else
/* Parse the expression. */
- expr = cp_parser_expression (parser);
+ expr = cp_parser_expression (parser, /*cast_p=*/false);
/* The next token should be a `:'. */
cp_parser_require (parser, CPP_COLON, "`:'");
/* Parse the assignment-expression. */
- assignment_expr = cp_parser_assignment_expression (parser);
+ assignment_expr = cp_parser_assignment_expression (parser, /*cast_p=*/false);
/* Build the conditional-expression. */
return build_x_conditional_expr (logical_or_expr,
logical-or-expression assignment-operator assignment_expression
throw-expression
+ CAST_P is true if this expression is the target of a cast.
+
Returns a representation for the expression. */
static tree
-cp_parser_assignment_expression (cp_parser* parser)
+cp_parser_assignment_expression (cp_parser* parser, bool cast_p)
{
tree expr;
logical-or-expression. */
else
{
- /* Parse the logical-or-expression. */
- expr = cp_parser_logical_or_expression (parser);
+ /* Parse the binary expressions (logical-or-expression). */
+ expr = cp_parser_binary_expression (parser, cast_p);
/* If the next token is a `?' then we're actually looking at a
conditional-expression. */
if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
tree rhs;
/* Parse the right-hand side of the assignment. */
- rhs = cp_parser_assignment_expression (parser);
+ rhs = cp_parser_assignment_expression (parser, cast_p);
/* An assignment may not appear in a
constant-expression. */
if (cp_parser_non_integral_constant_expression (parser,
case CPP_MIN_EQ:
op = MIN_EXPR;
+ cp_parser_warn_min_max ();
break;
case CPP_MAX_EQ:
op = MAX_EXPR;
+ cp_parser_warn_min_max ();
break;
default:
assignment-expression
expression , assignment-expression
+ CAST_P is true if this expression is the target of a cast.
+
Returns a representation of the expression. */
static tree
-cp_parser_expression (cp_parser* parser)
+cp_parser_expression (cp_parser* parser, bool cast_p)
{
tree expression = NULL_TREE;
/* Parse the next assignment-expression. */
assignment_expression
- = cp_parser_assignment_expression (parser);
+ = cp_parser_assignment_expression (parser, cast_p);
/* If this is the first assignment-expression, we can just
save it away. */
if (!expression)
For example, cp_parser_initializer_clauses uses this function to
determine whether a particular assignment-expression is in fact
constant. */
- expression = cp_parser_assignment_expression (parser);
+ expression = cp_parser_assignment_expression (parser, /*cast_p=*/false);
/* Restore the old settings. */
- parser->integral_constant_expression_p = saved_integral_constant_expression_p;
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
parser->allow_non_integral_constant_expression_p
= saved_allow_non_integral_constant_expression_p;
if (allow_non_constant_p)
*non_constant_p = parser->non_integral_constant_expression_p;
- parser->non_integral_constant_expression_p = saved_non_integral_constant_expression_p;
+ else if (parser->non_integral_constant_expression_p)
+ expression = error_mark_node;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
return expression;
}
statement = cp_parser_jump_statement (parser);
break;
+ /* Objective-C++ exception-handling constructs. */
+ case RID_AT_TRY:
+ case RID_AT_CATCH:
+ case RID_AT_FINALLY:
+ case RID_AT_SYNCHRONIZED:
+ case RID_AT_THROW:
+ statement = cp_parser_objc_statement (parser);
+ break;
+
case RID_TRY:
statement = cp_parser_try_block (parser);
break;
/* Anything that starts with a `{' must be a compound-statement. */
else if (token->type == CPP_OPEN_BRACE)
statement = cp_parser_compound_statement (parser, NULL, false);
+ /* CPP_PRAGMA is a #pragma inside a function body, which constitutes
+ a statement all its own. */
+ else if (token->type == CPP_PRAGMA)
+ {
+ cp_lexer_handle_pragma (parser->lexer);
+ return;
+ }
/* Everything else must be a declaration-statement or an
expression-statement. Try for the declaration-statement
expr_hi = NULL_TREE;
if (!parser->in_switch_statement_p)
- error ("case label `%E' not within a switch statement", expr);
+ error ("case label %qE not within a switch statement", expr);
else
statement = finish_case_label (expr, expr_hi);
}
/* If the next token is a ';', then there is no expression
statement. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- statement = cp_parser_expression (parser);
+ statement = cp_parser_expression (parser, /*cast_p=*/false);
/* Consume the final `;'. */
cp_parser_consume_semicolon_at_end_of_statement (parser);
if (in_statement_expr
&& cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
- {
- /* This is the final expression statement of a statement
- expression. */
- statement = finish_stmt_expr_expr (statement, in_statement_expr);
- }
+ /* This is the final expression statement of a statement
+ expression. */
+ statement = finish_stmt_expr_expr (statement, in_statement_expr);
else if (statement)
statement = finish_expr_stmt (statement);
else
parser->type_definition_forbidden_message
= "types may not be defined in conditions";
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, &type_specifiers);
+ cp_parser_type_specifier_seq (parser, /*is_condition==*/true,
+ &type_specifiers);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
/* If all is well, we might be looking at a declaration. */
/* Parse the declarator. */
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
/*ctor_dtor_or_conv_p=*/NULL,
- /*parenthesized_p=*/NULL);
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
/* Parse the attributes. */
attributes = cp_parser_attributes_opt (parser);
/* Parse the asm-specification. */
for sure. */
if (cp_parser_parse_definitely (parser))
{
- bool pop_p;
+ tree pushed_scope;
/* Create the declaration. */
decl = start_decl (declarator, &type_specifiers,
/*initialized_p=*/true,
attributes, /*prefix_attributes=*/NULL_TREE,
- &pop_p);
+ &pushed_scope);
/* Parse the assignment-expression. */
- initializer = cp_parser_assignment_expression (parser);
+ initializer = cp_parser_assignment_expression (parser,
+ /*cast_p=*/false);
/* Process the initializer. */
cp_finish_decl (decl,
initializer,
asm_specification,
LOOKUP_ONLYCONVERTING);
- if (pop_p)
- pop_scope (DECL_CONTEXT (decl));
+
+ if (pushed_scope)
+ pop_scope (pushed_scope);
return convert_from_reference (decl);
}
cp_parser_abort_tentative_parse (parser);
/* Otherwise, we are looking at an expression. */
- return cp_parser_expression (parser);
+ return cp_parser_expression (parser, /*cast_p=*/false);
}
/* Parse an iteration-statement.
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Parse the expression. */
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
/* We're done with the do-statement. */
finish_do_stmt (expression, statement);
/* Look for the `)'. */
/* If there's an expression, process it. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
finish_for_expr (expression, statement);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
}
else
statement = finish_break_stmt ();
- cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+ cp_parser_require (parser, CPP_SEMICOLON, "%<;%>");
break;
case RID_CONTINUE:
}
else
statement = finish_continue_stmt ();
- cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+ cp_parser_require (parser, CPP_SEMICOLON, "%<;%>");
break;
case RID_RETURN:
/* If the next token is a `;', then there is no
expression. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- expr = cp_parser_expression (parser);
+ expr = cp_parser_expression (parser, /*cast_p=*/false);
else
expr = NULL_TREE;
/* Build the return-statement. */
statement = finish_return_stmt (expr);
/* Look for the final `;'. */
- cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+ cp_parser_require (parser, CPP_SEMICOLON, "%<;%>");
}
break;
/* Consume the '*' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the dependent expression. */
- finish_goto_stmt (cp_parser_expression (parser));
+ finish_goto_stmt (cp_parser_expression (parser, /*cast_p=*/false));
}
else
finish_goto_stmt (cp_parser_identifier (parser));
/* Look for the final `;'. */
- cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+ cp_parser_require (parser, CPP_SEMICOLON, "%<;%>");
break;
default:
{
/* A declaration consisting of a single semicolon is
invalid. Allow it unless we're being pedantic. */
- if (pedantic && !in_system_header)
- pedwarn ("extra `;'");
cp_lexer_consume_token (parser->lexer);
+ if (pedantic && !in_system_header)
+ pedwarn ("extra %<;%>");
continue;
}
- /* The C lexer modifies PENDING_LANG_CHANGE when it wants the
- parser to enter or exit implicit `extern "C"' blocks. */
- while (pending_lang_change > 0)
+ /* If we're entering or exiting a region that's implicitly
+ extern "C", modify the lang context appropriately. */
+ if (!parser->implicit_extern_c && token->implicit_extern_c)
{
push_lang_context (lang_name_c);
- --pending_lang_change;
+ parser->implicit_extern_c = true;
}
- while (pending_lang_change < 0)
+ else if (parser->implicit_extern_c && !token->implicit_extern_c)
{
pop_lang_context ();
- ++pending_lang_change;
+ parser->implicit_extern_c = false;
+ }
+
+ if (token->type == CPP_PRAGMA)
+ {
+ /* A top-level declaration can consist solely of a #pragma.
+ A nested declaration cannot, so this is done here and not
+ in cp_parser_declaration. (A #pragma at block scope is
+ handled in cp_parser_statement.) */
+ cp_lexer_handle_pragma (parser->lexer);
+ continue;
}
/* Parse the declaration itself. */
int saved_pedantic;
void *p;
- /* Set this here since we can be called after
- pushing the linkage specification. */
- c_lex_string_translate = 1;
-
/* Check for the `__extension__' keyword. */
if (cp_parser_extension_opt (parser, &saved_pedantic))
{
/* Try to figure out what kind of declaration is present. */
token1 = *cp_lexer_peek_token (parser->lexer);
- /* Don't translate the CPP_STRING in extern "C". */
- if (token1.keyword == RID_EXTERN)
- c_lex_string_translate = 0;
-
if (token1.type != CPP_EOF)
token2 = *cp_lexer_peek_nth_token (parser->lexer, 2);
- c_lex_string_translate = 1;
-
/* Get the high-water mark for the DECLARATOR_OBSTACK. */
p = obstack_alloc (&declarator_obstack, 0);
/* An unnamed namespace definition. */
|| token2.type == CPP_OPEN_BRACE))
cp_parser_namespace_definition (parser);
+ /* Objective-C++ declaration/definition. */
+ else if (c_dialect_objc () && OBJC_IS_AT_KEYWORD (token1.keyword))
+ cp_parser_objc_declaration (parser);
/* We must have either a block declaration or a function
definition. */
else
T t;
where "T" should name a type -- but does not. */
- if (cp_parser_parse_and_diagnose_invalid_type_name (parser))
+ if (!decl_specifiers.type
+ && cp_parser_parse_and_diagnose_invalid_type_name (parser))
{
/* If parsing tentatively, we should commit; we really are
looking at a declaration. */
/* Give up. */
goto done;
}
+
+ /* If we have seen at least one decl-specifier, and the next token
+ is not a parenthesis, then we must be looking at a declaration.
+ (After "int (" we might be looking at a functional cast.) */
+ if (decl_specifiers.any_specifiers_p
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
+ cp_parser_commit_to_tentative_parse (parser);
/* Keep going until we hit the `;' at the end of the simple
declaration. */
/* Anything else is an error. */
else
{
- cp_parser_error (parser, "expected `,' or `;'");
+ /* If we have already issued an error message we don't need
+ to issue another one. */
+ if (decl != error_mark_node
+ || cp_parser_uncommitted_to_tentative_parse_p (parser))
+ cp_parser_error (parser, "expected %<,%> or %<;%>");
/* Skip tokens until we reach the end of the statement. */
cp_parser_skip_to_end_of_statement (parser);
/* If the next token is now a `;', consume it. */
friend */
case RID_FRIEND:
if (decl_specs->specs[(int) ds_friend]++)
- error ("duplicate `friend'");
+ error ("duplicate %<friend%>");
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
break;
cp_lexer_consume_token (parser->lexer);
if (decl_specs->specs[(int) ds_thread])
{
- error ("`__thread' before `static'");
+ error ("%<__thread%> before %<static%>");
decl_specs->specs[(int) ds_thread] = 0;
}
cp_parser_set_storage_class (decl_specs, sc_static);
cp_lexer_consume_token (parser->lexer);
if (decl_specs->specs[(int) ds_thread])
{
- error ("`__thread' before `extern'");
+ error ("%<__thread%> before %<extern%>");
decl_specs->specs[(int) ds_thread] = 0;
}
cp_parser_set_storage_class (decl_specs, sc_extern);
static void
cp_parser_linkage_specification (cp_parser* parser)
{
- cp_token *token;
tree linkage;
/* Look for the `extern' keyword. */
cp_parser_require_keyword (parser, RID_EXTERN, "`extern'");
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* If it's not a string-literal, then there's a problem. */
- if (!cp_parser_is_string_literal (token))
- {
- cp_parser_error (parser, "expected language-name");
- return;
- }
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
+ /* Look for the string-literal. */
+ linkage = cp_parser_string_literal (parser, false, false);
/* Transform the literal into an identifier. If the literal is a
wide-character string, or contains embedded NULs, then we can't
handle it as the user wants. */
- if (token->type == CPP_WSTRING
- || (strlen (TREE_STRING_POINTER (token->value))
- != (size_t) (TREE_STRING_LENGTH (token->value) - 1)))
+ if (strlen (TREE_STRING_POINTER (linkage))
+ != (size_t) (TREE_STRING_LENGTH (linkage) - 1))
{
cp_parser_error (parser, "invalid linkage-specification");
/* Assume C++ linkage. */
- linkage = get_identifier ("c++");
+ linkage = lang_name_cplusplus;
}
- /* If the string is chained to another string, take the latter,
- that's the untranslated string. */
- else if (TREE_CHAIN (token->value))
- linkage = get_identifier (TREE_STRING_POINTER (TREE_CHAIN (token->value)));
- /* If it's a simple string constant, things are easier. */
else
- linkage = get_identifier (TREE_STRING_POINTER (token->value));
+ linkage = get_identifier (TREE_STRING_POINTER (linkage));
/* We're now using the new linkage. */
push_lang_context (linkage);
tree saved_scope;
tree saved_qualifying_scope;
tree saved_object_scope;
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
/* Look for the `operator' token. */
if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
In order to see that `I' is a type-name in the definition, we
must be in the scope of `S'. */
if (saved_scope)
- pop_p = push_scope (saved_scope);
+ pushed_scope = push_scope (saved_scope);
/* Parse the conversion-type-id. */
type = cp_parser_conversion_type_id (parser);
/* Leave the scope of the class, if any. */
- if (pop_p)
- pop_scope (saved_scope);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
/* Restore the saved scope. */
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
tree attributes;
cp_decl_specifier_seq type_specifiers;
cp_declarator *declarator;
+ tree type_specified;
/* Parse the attributes. */
attributes = cp_parser_attributes_opt (parser);
/* Parse the type-specifiers. */
- cp_parser_type_specifier_seq (parser, &type_specifiers);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifiers);
/* If that didn't work, stop. */
if (type_specifiers.type == error_mark_node)
return error_mark_node;
/* Parse the conversion-declarator. */
declarator = cp_parser_conversion_declarator_opt (parser);
- return grokdeclarator (declarator, &type_specifiers, TYPENAME,
- /*initialized=*/0, &attributes);
+ type_specified = grokdeclarator (declarator, &type_specifiers, TYPENAME,
+ /*initialized=*/0, &attributes);
+ if (attributes)
+ cplus_decl_attributes (&type_specified, attributes, /*flags=*/0);
+ return type_specified;
}
/* Parse an (optional) conversion-declarator.
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
+ /*cast_p=*/false,
/*non_constant_p=*/NULL);
if (!expression_list)
expression_list = void_type_node;
/* `typename' is not allowed in this context ([temp.res]). */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
{
- error ("keyword `typename' not allowed in this context (a qualified "
+ error ("keyword %<typename%> not allowed in this context (a qualified "
"member initializer is implicitly a type)");
cp_lexer_consume_token (parser->lexer);
}
return cp_parser_class_name (parser,
/*typename_keyword_p=*/true,
/*template_keyword_p=*/template_p,
- /*type_p=*/false,
+ none_type,
/*check_dependency_p=*/true,
/*class_head_p=*/false,
/*is_declaration=*/true);
id = cp_parser_class_name (parser,
/*typename_keyword_p=*/true,
/*template_keyword_p=*/false,
- /*type_p=*/false,
+ none_type,
/*check_dependency_p=*/true,
/*class_head_p=*/false,
/*is_declaration=*/true);
/* Extensions. */
case CPP_MIN:
id = ansi_opname (MIN_EXPR);
+ cp_parser_warn_min_max ();
break;
case CPP_MAX:
id = ansi_opname (MAX_EXPR);
+ cp_parser_warn_min_max ();
break;
case CPP_MIN_EQ:
id = ansi_assopname (MIN_EXPR);
+ cp_parser_warn_min_max ();
break;
case CPP_MAX_EQ:
id = ansi_assopname (MAX_EXPR);
+ cp_parser_warn_min_max ();
break;
default:
/* Consume the `export' token. */
cp_lexer_consume_token (parser->lexer);
/* Warn that we do not support `export'. */
- warning ("keyword `export' not implemented, and will be ignored");
+ warning (0, "keyword %<export%> not implemented, and will be ignored");
}
cp_parser_template_declaration_after_export (parser, member_p);
/* Parse the template-parameter. */
parameter = cp_parser_template_parameter (parser, &is_non_type);
/* Add it to the list. */
- parameter_list = process_template_parm (parameter_list,
- parameter,
- is_non_type);
+ if (parameter != error_mark_node)
+ parameter_list = process_template_parm (parameter_list,
+ parameter,
+ is_non_type);
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's not a `,', we're done. */
type-parameter
parameter-declaration
- Returns a TREE_LIST. The TREE_VALUE represents the parameter. The
- TREE_PURPOSE is the default value, if any. *IS_NON_TYPE is set to
- true iff this parameter is a non-type parameter. */
+ If all goes well, returns a TREE_LIST. The TREE_VALUE represents
+ the parameter. The TREE_PURPOSE is the default value, if any.
+ Returns ERROR_MARK_NODE on failure. *IS_NON_TYPE is set to true
+ iff this parameter is a non-type parameter. */
static tree
cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
{
cp_token *token;
cp_parameter_declarator *parameter_declarator;
+ tree parm;
/* Assume it is a type parameter or a template parameter. */
*is_non_type = false;
parameter_declarator
= cp_parser_parameter_declaration (parser, /*template_parm_p=*/true,
/*parenthesized_p=*/NULL);
- return (build_tree_list
- (parameter_declarator->default_argument,
- grokdeclarator (parameter_declarator->declarator,
- ¶meter_declarator->decl_specifiers,
- PARM, /*initialized=*/0,
- /*attrlist=*/NULL)));
+ parm = grokdeclarator (parameter_declarator->declarator,
+ ¶meter_declarator->decl_specifiers,
+ PARM, /*initialized=*/0,
+ /*attrlist=*/NULL);
+ if (parm == error_mark_node)
+ return error_mark_node;
+ return build_tree_list (parameter_declarator->default_argument, parm);
}
/* Parse a type-parameter.
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
- identifier = cp_parser_identifier (parser);
+ {
+ identifier = cp_parser_identifier (parser);
+ /* Treat invalid names as if the parameter were nameless. */
+ if (identifier == error_mark_node)
+ identifier = NULL_TREE;
+ }
else
identifier = NULL_TREE;
+
/* Create the template parameter. */
parameter = finish_template_template_parm (class_type_node,
identifier);
/* Look up the name. */
default_argument
= cp_parser_lookup_name (parser, default_argument,
- /*is_type=*/false,
- /*is_template=*/is_template,
- /*is_namespace=*/false,
- /*check_dependency=*/true,
- /*ambiguous_p=*/NULL);
+ none_type,
+ /*is_template=*/is_template,
+ /*is_namespace=*/false,
+ /*check_dependency=*/true,
+ /*ambiguous_p=*/NULL);
/* See if the default argument is valid. */
default_argument
= check_template_template_default_arg (default_argument);
/* Create the combined representation of the parameter and the
default argument. */
- parameter = build_tree_list (default_argument, parameter);
+ parameter = build_tree_list (default_argument, parameter);
}
break;
default:
- /* Anything else is an error. */
- cp_parser_error (parser,
- "expected `class', `typename', or `template'");
- parameter = error_mark_node;
+ gcc_unreachable ();
+ break;
}
return parameter;
tree template;
tree arguments;
tree template_id;
- ptrdiff_t start_of_id;
+ cp_token_position start_of_id = 0;
tree access_check = NULL_TREE;
cp_token *next_token, *next_token_2;
bool is_identifier;
}
/* Remember where the template-id starts. */
- if (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
- {
- next_token = cp_lexer_peek_token (parser->lexer);
- start_of_id = cp_lexer_token_difference (parser->lexer,
- parser->lexer->first_token,
- next_token);
- }
- else
- start_of_id = -1;
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
+ start_of_id = cp_lexer_token_position (parser->lexer, false);
push_deferring_access_checks (dk_deferred);
/* If we find the sequence `[:' after a template-name, it's probably
a digraph-typo for `< ::'. Substitute the tokens and check if we can
parse correctly the argument list. */
- next_token = cp_lexer_peek_nth_token (parser->lexer, 1);
+ next_token = cp_lexer_peek_token (parser->lexer);
next_token_2 = cp_lexer_peek_nth_token (parser->lexer, 2);
if (next_token->type == CPP_OPEN_SQUARE
&& next_token->flags & DIGRAPH
and return simply an error. Maybe this is not a template-id
after all. */
next_token_2->type = CPP_COLON;
- cp_parser_error (parser, "expected `<'");
+ cp_parser_error (parser, "expected %<<%>");
pop_deferring_access_checks ();
return error_mark_node;
}
/* Otherwise, emit an error about the invalid digraph, but continue
parsing because we got our argument list. */
- pedwarn ("`<::' cannot begin a template-argument list");
- inform ("`<:' is an alternate spelling for `['. Insert whitespace "
- "between `<' and `::'");
+ pedwarn ("%<<::%> cannot begin a template-argument list");
+ inform ("%<<:%> is an alternate spelling for %<[%>. Insert whitespace "
+ "between %<<%> and %<::%>");
if (!flag_permissive)
{
static bool hint;
if (!hint)
{
- inform ("(if you use `-fpermissive' G++ will accept your code)");
+ inform ("(if you use -fpermissive G++ will accept your code)");
hint = true;
}
}
the effort required to do the parse, nor will we issue duplicate
error messages about problems during instantiation of the
template. */
- if (start_of_id >= 0)
+ if (start_of_id)
{
- cp_token *token;
-
- /* Find the token that corresponds to the start of the
- template-id. */
- token = cp_lexer_advance_token (parser->lexer,
- parser->lexer->first_token,
- start_of_id);
-
+ cp_token *token = cp_lexer_token_at (parser->lexer, start_of_id);
+
/* Reset the contents of the START_OF_ID token. */
token->type = CPP_TEMPLATE_ID;
token->value = build_tree_list (access_check, template_id);
token->keyword = RID_MAX;
+
/* Purge all subsequent tokens. */
- cp_lexer_purge_tokens_after (parser->lexer, token);
+ cp_lexer_purge_tokens_after (parser->lexer, start_of_id);
+
+ /* ??? Can we actually assume that, if template_id ==
+ error_mark_node, we will have issued a diagnostic to the
+ user, as opposed to simply marking the tentative parse as
+ failed? */
+ if (cp_parser_error_occurred (parser) && template_id != error_mark_node)
+ error ("parse error in template argument list");
}
pop_deferring_access_checks ();
if (is_declaration
&& !template_keyword_p
&& parser->scope && TYPE_P (parser->scope)
+ && check_dependency_p
&& dependent_type_p (parser->scope)
/* Do not do this for dtors (or ctors), since they never
need the template keyword before their name. */
&& !constructor_name_p (identifier, parser->scope))
{
- ptrdiff_t start;
- cp_token* token;
+ cp_token_position start = 0;
+
/* Explain what went wrong. */
- error ("non-template `%D' used as template", identifier);
- inform ("use `%T::template %D' to indicate that it is a template",
+ error ("non-template %qD used as template", identifier);
+ inform ("use %<%T::template %D%> to indicate that it is a template",
parser->scope, identifier);
- /* If parsing tentatively, find the location of the "<"
- token. */
- if (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
- {
- cp_parser_simulate_error (parser);
- token = cp_lexer_peek_token (parser->lexer);
- token = cp_lexer_prev_token (parser->lexer, token);
- start = cp_lexer_token_difference (parser->lexer,
- parser->lexer->first_token,
- token);
- }
- else
- start = -1;
+ /* If parsing tentatively, find the location of the "<" token. */
+ if (cp_parser_simulate_error (parser))
+ start = cp_lexer_token_position (parser->lexer, true);
/* Parse the template arguments so that we can issue error
messages about them. */
cp_lexer_consume_token (parser->lexer);
template argument list. That will prevent duplicate
error messages from being issued about the missing
"template" keyword. */
- if (start >= 0)
- {
- token = cp_lexer_advance_token (parser->lexer,
- parser->lexer->first_token,
- start);
- cp_lexer_purge_tokens_after (parser->lexer, token);
- }
+ if (start)
+ cp_lexer_purge_tokens_after (parser->lexer, start);
if (is_identifier)
*is_identifier = true;
return identifier;
/* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier,
- /*is_type=*/false,
+ none_type,
/*is_template=*/false,
/*is_namespace=*/false,
check_dependency_p,
;
else
{
+ tree fn = NULL_TREE;
+
/* The standard does not explicitly indicate whether a name that
names a set of overloaded declarations, some of which are
templates, is a template-name. However, such a name should
template-id for the overloaded templates. */
fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;
if (TREE_CODE (fns) == OVERLOAD)
- {
- tree fn;
+ for (fn = fns; fn; fn = OVL_NEXT (fn))
+ if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
+ break;
- for (fn = fns; fn; fn = OVL_NEXT (fn))
- if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
- break;
- }
- else
+ if (!fn)
{
- /* Otherwise, the name does not name a template. */
+ /* The name does not name a template. */
cp_parser_error (parser, "expected template-name");
return error_mark_node;
}
at this point in that case. */
if (TREE_CODE (argument) != TYPE_DECL)
argument = cp_parser_lookup_name (parser, argument,
- /*is_type=*/false,
+ none_type,
/*is_template=*/template_p,
/*is_namespace=*/false,
/*check_dependency=*/true,
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
+ /*cast_p=*/false,
&idk,
&qualifying_class);
if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
if (cp_parser_parse_definitely (parser))
return argument;
}
+
/* If the next token is "&", the argument must be the address of an
object or function with external linkage. */
address_p = cp_lexer_next_token_is (parser->lexer, CPP_AND);
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
+ /*cast_p=*/false,
&idk,
&qualifying_class);
if (cp_parser_error_occurred (parser)
cp_parser_abort_tentative_parse (parser);
else
{
+ if (TREE_CODE (argument) == INDIRECT_REF)
+ {
+ gcc_assert (REFERENCE_REF_P (argument));
+ argument = TREE_OPERAND (argument, 0);
+ }
+
if (qualifying_class)
argument = finish_qualified_id_expr (qualifying_class,
argument,
|| TREE_CODE (argument) == SCOPE_REF))
/* A pointer-to-member. */
;
+ else if (TREE_CODE (argument) == TEMPLATE_PARM_INDEX)
+ ;
else
cp_parser_simulate_error (parser);
cp_parser_error (parser, "invalid non-type template argument");
return error_mark_node;
}
+
/* If the argument wasn't successfully parsed as a type-id followed
by '>>', the argument can only be a constant expression now.
Otherwise, we try parsing the constant-expression tentatively,
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
/*ctor_dtor_or_conv_p=*/NULL,
- /*parenthesized_p=*/NULL);
- cp_parser_check_for_definition_in_return_type (declarator,
- declares_class_or_enum);
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
+ if (declares_class_or_enum & 2)
+ cp_parser_check_for_definition_in_return_type (declarator,
+ decl_specifiers.type);
if (declarator != cp_error_declarator)
{
decl = grokdeclarator (declarator, &decl_specifiers,
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type
== CPP_OPEN_BRACE))
{
- type_spec = cp_parser_enum_specifier (parser);
+ if (parser->num_template_parameter_lists)
+ {
+ error ("template declaration of %qs", "enum");
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ type_spec = error_mark_node;
+ }
+ else
+ type_spec = cp_parser_enum_specifier (parser);
+
if (declares_class_or_enum)
*declares_class_or_enum = 2;
if (decl_specs)
followed by a "<". That usually indicates that the user thought
that the type was a template. */
if (type && type != error_mark_node)
- cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type));
+ {
+ /* As a last-ditch effort, see if TYPE is an Objective-C type.
+ If it is, then the '<'...'>' enclose protocol names rather than
+ template arguments, and so everything is fine. */
+ if (c_dialect_objc ()
+ && (objc_is_id (type) || objc_is_class_name (type)))
+ {
+ tree protos = cp_parser_objc_protocol_refs_opt (parser);
+ tree qual_type = objc_get_protocol_qualified_type (type, protos);
+
+ /* Clobber the "unqualified" type previously entered into
+ DECL_SPECS with the new, improved protocol-qualified version. */
+ if (decl_specs)
+ decl_specs->type = qual_type;
+
+ return qual_type;
+ }
+
+ cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type));
+ }
return type;
}
typedef-name:
identifier
- Returns a TYPE_DECL for the the type. */
+ Returns a TYPE_DECL for the type. */
static tree
cp_parser_type_name (cp_parser* parser)
type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- /*type_p=*/false,
+ none_type,
/*check_dependency_p=*/true,
/*class_head_p=*/false,
/*is_declaration=*/false);
/* Look up the type-name. */
type_decl = cp_parser_lookup_name_simple (parser, identifier);
+
+ if (TREE_CODE (type_decl) != TYPE_DECL
+ && (objc_is_id (identifier) || objc_is_class_name (identifier)))
+ {
+ /* See if this is an Objective-C type. */
+ tree protos = cp_parser_objc_protocol_refs_opt (parser);
+ tree type = objc_get_protocol_qualified_type (identifier, protos);
+ if (type)
+ type_decl = TYPE_NAME (type);
+ }
+
/* Issue an error if we did not find a type-name. */
if (TREE_CODE (type_decl) != TYPE_DECL)
{
tag_type = typename_type;
/* The `typename' keyword is only allowed in templates. */
if (!processing_template_decl)
- pedwarn ("using `typename' outside of template");
+ pedwarn ("using %<typename%> outside of template");
}
/* Otherwise it must be a class-key. */
else
else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
&& tag_type == typename_type)
type = make_typename_type (parser->scope, decl,
+ typename_type,
/*complain=*/1);
else
type = TREE_TYPE (decl);
}
/* For a `typename', we needn't call xref_tag. */
- if (tag_type == typename_type)
+ if (tag_type == typename_type
+ && TREE_CODE (parser->scope) != NAMESPACE_DECL)
return cp_parser_make_typename_type (parser, parser->scope,
identifier);
/* Look up a qualified name in the usual way. */
{
tree decl;
- /* In an elaborated-type-specifier, names are assumed to name
- types, so we set IS_TYPE to TRUE when calling
- cp_parser_lookup_name. */
decl = cp_parser_lookup_name (parser, identifier,
- /*is_type=*/true,
+ tag_type,
/*is_template=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true,
if (TREE_CODE (decl) != TYPE_DECL)
{
- error ("expected type-name");
+ cp_parser_diagnose_invalid_type_name (parser,
+ parser->scope,
+ identifier);
return error_mark_node;
}
definition of a new type; a new type can only be declared in a
declaration context. */
+ tag_scope ts;
+ if (is_friend)
+ /* Friends have special name lookup rules. */
+ ts = ts_within_enclosing_non_class;
+ else if (is_declaration
+ && cp_lexer_next_token_is (parser->lexer,
+ CPP_SEMICOLON))
+ /* This is a `class-key identifier ;' */
+ ts = ts_current;
+ else
+ ts = ts_global;
+
/* Warn about attributes. They are ignored. */
if (attributes)
- warning ("type attributes are honored only at type definition");
+ warning (OPT_Wattributes,
+ "type attributes are honored only at type definition");
- type = xref_tag (tag_type, identifier,
- (is_friend
- || !is_declaration
- || cp_lexer_next_token_is_not (parser->lexer,
- CPP_SEMICOLON)),
+ type = xref_tag (tag_type, identifier, ts,
parser->num_template_parameter_lists);
}
}
enum-specifier:
enum identifier [opt] { enumerator-list [opt] }
+ GNU Extensions:
+ enum identifier [opt] { enumerator-list [opt] } attributes
+
Returns an ENUM_TYPE representing the enumeration. */
static tree
else
identifier = make_anon_name ();
- cp_lexer_consume_token (parser->lexer);
-
/* Issue an error message if type-definitions are forbidden here. */
cp_parser_check_type_definition (parser);
- /* Create the new type. */
+ /* Create the new type. We do this before consuming the opening brace
+ so the enum will be recorded as being on the line of its tag (or the
+ 'enum' keyword, if there is no tag). */
type = start_enum (identifier);
+ /* Consume the opening brace. */
+ cp_lexer_consume_token (parser->lexer);
+
/* If the next token is not '}', then there are some enumerators. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
cp_parser_enumerator_list (parser, type);
/* Consume the final '}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+ /* Look for trailing attributes to apply to this enumeration, and
+ apply them if appropriate. */
+ if (cp_parser_allow_gnu_extensions_p (parser))
+ {
+ tree trailing_attr = cp_parser_attributes_opt (parser);
+ cplus_decl_attributes (&type,
+ trailing_attr,
+ (int) ATTR_FLAG_TYPE_IN_PLACE);
+ }
+
/* Finish up the enumeration. */
finish_enum (type);
function if the token after the name is the scope resolution
operator.) */
namespace_decl = cp_parser_lookup_name (parser, identifier,
- /*is_type=*/false,
+ none_type,
/*is_template=*/false,
/*is_namespace=*/true,
/*check_dependency=*/true,
bool global_scope_p;
tree decl;
tree identifier;
- tree scope;
tree qscope;
/* Look for the `using' keyword. */
error ("a template-id may not appear in a using-declaration");
else
{
- scope = current_scope ();
- if (scope && TYPE_P (scope))
+ if (at_class_scope_p ())
{
/* Create the USING_DECL. */
- decl = do_class_using_decl (build_nt (SCOPE_REF,
- parser->scope,
- identifier));
+ decl = do_class_using_decl (parser->scope, identifier);
/* Add it to the list of members in this class. */
finish_member_declaration (decl);
}
decl = cp_parser_lookup_name_simple (parser, identifier);
if (decl == error_mark_node)
cp_parser_name_lookup_error (parser, identifier, decl, NULL);
- else if (scope)
+ else if (!at_namespace_scope_p ())
do_local_using_decl (decl, qscope, identifier);
else
do_toplevel_using_decl (decl, qscope, identifier);
static void
cp_parser_asm_definition (cp_parser* parser)
{
- cp_token *token;
tree string;
tree outputs = NULL_TREE;
tree inputs = NULL_TREE;
cp_lexer_consume_token (parser->lexer);
}
/* Look for the opening `('. */
- cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+ return;
/* Look for the string. */
- c_lex_string_translate = 0;
- token = cp_parser_require (parser, CPP_STRING, "asm body");
- if (!token)
- goto finish;
- string = token->value;
+ string = cp_parser_string_literal (parser, false, false);
+ if (string == error_mark_node)
+ {
+ cp_parser_skip_to_closing_parenthesis (parser, true, false,
+ /*consume_paren=*/true);
+ return;
+ }
+
/* If we're allowing GNU extensions, check for the extended assembly
syntax. Unfortunately, the `:' tokens need not be separated by
a space in C, and so, for compatibility, we tolerate that here
inputs, clobbers);
/* If the extended syntax was not used, mark the ASM_EXPR. */
if (!extended_p)
- ASM_INPUT_P (asm_stmt) = 1;
+ {
+ tree temp = asm_stmt;
+ if (TREE_CODE (temp) == CLEANUP_POINT_EXPR)
+ temp = TREE_OPERAND (temp, 0);
+
+ ASM_INPUT_P (temp) = 1;
+ }
}
else
assemble_asm (string);
-
- finish:
- c_lex_string_translate = 1;
}
/* Declarators [gram.dcl.decl] */
bool is_non_constant_init;
int ctor_dtor_or_conv_p;
bool friend_p;
- bool pop_p = false;
+ tree pushed_scope = NULL;
/* Gather the attributes that were provided with the
decl-specifiers. */
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
&ctor_dtor_or_conv_p,
- /*parenthesized_p=*/NULL);
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
/* Gather up the deferred checks. */
stop_deferring_access_checks ();
if (declarator == cp_error_declarator)
return error_mark_node;
- cp_parser_check_for_definition_in_return_type (declarator,
- declares_class_or_enum);
+ if (declares_class_or_enum & 2)
+ cp_parser_check_for_definition_in_return_type (declarator,
+ decl_specifiers->type);
/* Figure out what scope the entity declared by the DECLARATOR is
located in. `grokdeclarator' sometimes changes the scope, so
&& token->type != CPP_COMMA
&& token->type != CPP_SEMICOLON)
{
- cp_parser_error (parser, "expected init-declarator");
+ cp_parser_error (parser, "expected initializer");
return error_mark_node;
}
}
decl = start_decl (declarator, decl_specifiers,
is_initialized, attributes, prefix_attributes,
- &pop_p);
+ &pushed_scope);
}
else if (scope)
/* Enter the SCOPE. That way unqualified names appearing in the
initializer will be looked up in SCOPE. */
- pop_p = push_scope (scope);
+ pushed_scope = push_scope (scope);
/* Perform deferred access control checks, now that we know in which
SCOPE the declared entity resides. */
attributes -- but ignores them. */
if (cp_parser_allow_gnu_extensions_p (parser) && is_parenthesized_init)
if (cp_parser_attributes_opt (parser))
- warning ("attributes after parenthesized initializer ignored");
+ warning (OPT_Wattributes,
+ "attributes after parenthesized initializer ignored");
/* For an in-class declaration, use `grokfield' to create the
declaration. */
if (member_p)
{
- if (pop_p)
- pop_scope (scope);
+ if (pushed_scope)
+ {
+ pop_scope (pushed_scope);
+ pushed_scope = false;
+ }
decl = grokfield (declarator, decl_specifiers,
initializer, /*asmspec=*/NULL_TREE,
/*attributes=*/NULL_TREE);
`explicit' constructor cannot be used. */
((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
- if (pop_p)
- pop_scope (DECL_CONTEXT (decl));
}
+ if (!friend_p && pushed_scope)
+ pop_scope (pushed_scope);
/* Remember whether or not variables were initialized by
constant-expressions. */
expression, not a declaration.)
If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to true iff
- the declarator is a direct-declarator of the form "(...)". */
+ the declarator is a direct-declarator of the form "(...)".
+
+ MEMBER_P is true iff this declarator is a member-declarator. */
static cp_declarator *
cp_parser_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
int* ctor_dtor_or_conv_p,
- bool* parenthesized_p)
+ bool* parenthesized_p,
+ bool member_p)
{
cp_token *token;
cp_declarator *declarator;
/* Parse the dependent declarator. */
declarator = cp_parser_declarator (parser, dcl_kind,
/*ctor_dtor_or_conv_p=*/NULL,
- /*parenthesized_p=*/NULL);
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
/* If we are parsing an abstract-declarator, we must handle the
case where the dependent declarator is absent. */
*parenthesized_p = cp_lexer_next_token_is (parser->lexer,
CPP_OPEN_PAREN);
declarator = cp_parser_direct_declarator (parser, dcl_kind,
- ctor_dtor_or_conv_p);
+ ctor_dtor_or_conv_p,
+ member_p);
}
if (attributes && declarator != cp_error_declarator)
we are parsing a direct-declarator. It is
CP_PARSER_DECLARATOR_EITHER, if we can accept either - in the case
of ambiguity we prefer an abstract declarator, as per
- [dcl.ambig.res]. CTOR_DTOR_OR_CONV_P is as for
+ [dcl.ambig.res]. CTOR_DTOR_OR_CONV_P and MEMBER_P are as for
cp_parser_declarator. */
static cp_declarator *
cp_parser_direct_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
- int* ctor_dtor_or_conv_p)
+ int* ctor_dtor_or_conv_p,
+ bool member_p)
{
cp_token *token;
cp_declarator *declarator = NULL;
bool saved_default_arg_ok_p = parser->default_arg_ok_p;
bool saved_in_declarator_p = parser->in_declarator_p;
bool first = true;
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
while (true)
{
cp_parameter_declarator *params;
unsigned saved_num_template_parameter_lists;
- cp_parser_parse_tentatively (parser);
+ /* In a member-declarator, the only valid interpretation
+ of a parenthesis is the start of a
+ parameter-declaration-clause. (It is invalid to
+ initialize a static data member with a parenthesized
+ initializer; only the "=" form of initialization is
+ permitted.) */
+ if (!member_p)
+ cp_parser_parse_tentatively (parser);
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* If all went well, parse the cv-qualifier-seq and the
exception-specification. */
- if (cp_parser_parse_definitely (parser))
+ if (member_p || cp_parser_parse_definitely (parser))
{
cp_cv_quals cv_quals;
tree exception_specification;
parser->in_type_id_in_expr_p = true;
declarator
= cp_parser_declarator (parser, dcl_kind, ctor_dtor_or_conv_p,
- /*parenthesized_p=*/NULL);
+ /*parenthesized_p=*/NULL,
+ member_p);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
first = false;
/* Expect a `)'. */
&non_constant_p);
if (!non_constant_p)
bounds = fold_non_dependent_expr (bounds);
+ /* Normally, the array bound must be an integral constant
+ expression. However, as an extension, we allow VLAs
+ in function scopes. */
+ else if (!at_function_scope_p ())
+ {
+ error ("array bound is not an integer constant");
+ bounds = error_mark_node;
+ }
}
else
bounds = NULL_TREE;
}
else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
- tree id;
+ tree qualifying_scope;
+ tree unqualified_name;
/* Parse a declarator-id */
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
cp_parser_parse_tentatively (parser);
- id = cp_parser_declarator_id (parser);
+ unqualified_name = cp_parser_declarator_id (parser);
+ qualifying_scope = parser->scope;
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
{
if (!cp_parser_parse_definitely (parser))
- id = error_mark_node;
- else if (TREE_CODE (id) != IDENTIFIER_NODE)
+ unqualified_name = error_mark_node;
+ else if (qualifying_scope
+ || (TREE_CODE (unqualified_name)
+ != IDENTIFIER_NODE))
{
cp_parser_error (parser, "expected unqualified-id");
- id = error_mark_node;
+ unqualified_name = error_mark_node;
}
}
- if (id == error_mark_node)
+ if (unqualified_name == error_mark_node)
{
declarator = cp_error_declarator;
break;
}
- if (TREE_CODE (id) == SCOPE_REF && !current_scope ())
+ if (qualifying_scope && at_namespace_scope_p ()
+ && TREE_CODE (qualifying_scope) == TYPENAME_TYPE)
{
- tree scope = TREE_OPERAND (id, 0);
-
/* In the declaration of a member of a template class
outside of the class itself, the SCOPE will sometimes
be a TYPENAME_TYPE. For example, given:
`S<T>::R' not a type. However, if `S' is
specialized, then this `i' will not be used, so there
is no harm in resolving the types here. */
- if (TREE_CODE (scope) == TYPENAME_TYPE)
- {
- tree type;
-
- /* Resolve the TYPENAME_TYPE. */
- type = resolve_typename_type (scope,
- /*only_current_p=*/false);
- /* If that failed, the declarator is invalid. */
- if (type == error_mark_node)
- error ("`%T::%D' is not a type",
- TYPE_CONTEXT (scope),
- TYPE_IDENTIFIER (scope));
- /* Build a new DECLARATOR. */
- id = build_nt (SCOPE_REF, type, TREE_OPERAND (id, 1));
- }
+ tree type;
+
+ /* Resolve the TYPENAME_TYPE. */
+ type = resolve_typename_type (qualifying_scope,
+ /*only_current_p=*/false);
+ /* If that failed, the declarator is invalid. */
+ if (type == error_mark_node)
+ error ("%<%T::%D%> is not a type",
+ TYPE_CONTEXT (qualifying_scope),
+ TYPE_IDENTIFIER (qualifying_scope));
+ qualifying_scope = type;
}
- declarator = make_id_declarator (id);
- if (id)
+ declarator = make_id_declarator (qualifying_scope,
+ unqualified_name);
+ declarator->id_loc = token->location;
+ if (unqualified_name)
{
tree class_type;
- tree unqualified_name;
- if (TREE_CODE (id) == SCOPE_REF
- && CLASS_TYPE_P (TREE_OPERAND (id, 0)))
- {
- class_type = TREE_OPERAND (id, 0);
- unqualified_name = TREE_OPERAND (id, 1);
- }
+ if (qualifying_scope
+ && CLASS_TYPE_P (qualifying_scope))
+ class_type = qualifying_scope;
else
- {
- class_type = current_class_type;
- unqualified_name = id;
- }
+ class_type = current_class_type;
if (class_type)
{
declarator->u.id.sfk = sfk_destructor;
else if (IDENTIFIER_TYPENAME_P (unqualified_name))
declarator->u.id.sfk = sfk_conversion;
- else if (constructor_name_p (unqualified_name,
- class_type)
- || (TREE_CODE (unqualified_name) == TYPE_DECL
- && same_type_p (TREE_TYPE (unqualified_name),
- class_type)))
+ else if (/* There's no way to declare a constructor
+ for an anonymous type, even if the type
+ got a name for linkage purposes. */
+ !TYPE_WAS_ANONYMOUS (class_type)
+ && (constructor_name_p (unqualified_name,
+ class_type)
+ || (TREE_CODE (unqualified_name) == TYPE_DECL
+ && (same_type_p
+ (TREE_TYPE (unqualified_name),
+ class_type)))))
declarator->u.id.sfk = sfk_constructor;
if (ctor_dtor_or_conv_p && declarator->u.id.sfk != sfk_none)
*ctor_dtor_or_conv_p = -1;
- if (TREE_CODE (id) == SCOPE_REF
+ if (qualifying_scope
&& TREE_CODE (unqualified_name) == TYPE_DECL
&& CLASSTYPE_USE_TEMPLATE (TREE_TYPE (unqualified_name)))
{
error ("invalid use of constructor as a template");
- inform ("use `%T::%D' instead of `%T::%T' to name the "
- "constructor in a qualified name", class_type,
+ inform ("use %<%T::%D%> instead of %<%T::%T%> to name "
+ "the constructor in a qualified name",
+ class_type,
DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
class_type, class_type);
}
if (scope)
/* Any names that appear after the declarator-id for a
member are looked up in the containing scope. */
- pop_p = push_scope (scope);
+ pushed_scope = push_scope (scope);
parser->in_declarator_p = true;
if ((ctor_dtor_or_conv_p && *ctor_dtor_or_conv_p)
|| (declarator && declarator->kind == cdk_id))
cp_parser_error (parser, "expected declarator");
/* If we entered a scope, we must exit it now. */
- if (pop_p)
- pop_scope (scope);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
parser->default_arg_ok_p = saved_default_arg_ok_p;
parser->in_declarator_p = saved_in_declarator_p;
static tree
cp_parser_declarator_id (cp_parser* parser)
{
- tree id_expression;
-
/* The expression must be an id-expression. Assume that qualified
names are the names of types so that:
int S<T>::R<T>::i = 3;
will work, too. */
- id_expression = cp_parser_id_expression (parser,
- /*template_keyword_p=*/false,
- /*check_dependency_p=*/false,
- /*template_p=*/NULL,
- /*declarator_p=*/true);
- /* If the name was qualified, create a SCOPE_REF to represent
- that. */
- if (parser->scope)
- {
- id_expression = build_nt (SCOPE_REF, parser->scope, id_expression);
- parser->scope = NULL_TREE;
- }
-
- return id_expression;
+ return cp_parser_id_expression (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/false,
+ /*template_p=*/NULL,
+ /*declarator_p=*/true);
}
/* Parse a type-id.
cp_declarator *abstract_declarator;
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, &type_specifier_seq);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifier_seq);
if (type_specifier_seq.type == error_mark_node)
return error_mark_node;
/* Look for the declarator. */
abstract_declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL,
- /*parenthesized_p=*/NULL);
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
/* Check to see if there really was a declarator. */
if (!cp_parser_parse_definitely (parser))
abstract_declarator = NULL;
type-specifier-seq:
attributes type-specifier-seq [opt]
+ If IS_CONDITION is true, we are at the start of a "condition",
+ e.g., we've just seen "if (".
+
Sets *TYPE_SPECIFIER_SEQ to represent the sequence. */
static void
cp_parser_type_specifier_seq (cp_parser* parser,
+ bool is_condition,
cp_decl_specifier_seq *type_specifier_seq)
{
bool seen_type_specifier = false;
+ cp_parser_flags flags = CP_PARSER_FLAGS_OPTIONAL;
/* Clear the TYPE_SPECIFIER_SEQ. */
clear_decl_specs (type_specifier_seq);
while (true)
{
tree type_specifier;
+ bool is_cv_qualifier;
/* Check for attributes first. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
/* Look for the type-specifier. */
type_specifier = cp_parser_type_specifier (parser,
- CP_PARSER_FLAGS_OPTIONAL,
+ flags,
type_specifier_seq,
/*is_declaration=*/false,
NULL,
- NULL);
- /* If the first type-specifier could not be found, this is not a
- type-specifier-seq at all. */
- if (!seen_type_specifier && !type_specifier)
+ &is_cv_qualifier);
+ if (!type_specifier)
{
- cp_parser_error (parser, "expected type-specifier");
- type_specifier_seq->type = error_mark_node;
- return;
+ /* If the first type-specifier could not be found, this is not a
+ type-specifier-seq at all. */
+ if (!seen_type_specifier)
+ {
+ cp_parser_error (parser, "expected type-specifier");
+ type_specifier_seq->type = error_mark_node;
+ return;
+ }
+ /* If subsequent type-specifiers could not be found, the
+ type-specifier-seq is complete. */
+ break;
}
- /* If subsequent type-specifiers could not be found, the
- type-specifier-seq is complete. */
- else if (seen_type_specifier && !type_specifier)
- break;
seen_type_specifier = true;
+ /* The standard says that a condition can be:
+
+ type-specifier-seq declarator = assignment-expression
+
+ However, given:
+
+ struct S {};
+ if (int S = ...)
+
+ we should treat the "S" as a declarator, not as a
+ type-specifier. The standard doesn't say that explicitly for
+ type-specifier-seq, but it does say that for
+ decl-specifier-seq in an ordinary declaration. Perhaps it
+ would be clearer just to allow a decl-specifier-seq here, and
+ then add a semantic restriction that if any decl-specifiers
+ that are not type-specifiers appear, the program is invalid. */
+ if (is_condition && !is_cv_qualifier)
+ flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
}
return;
/* Peek at the next token. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
- || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
+ /* These are for Objective-C++ */
+ || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+ || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
/* The parameter-declaration-list is complete. */
break;
else if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
list. */
if (!parser->in_template_argument_list_p
&& !parser->in_type_id_in_expr_p
- && cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser)
+ && cp_parser_uncommitted_to_tentative_parse_p (parser)
/* However, a parameter-declaration of the form
"foat(f)" (which is a valid declaration of a
parameter "f") can also be interpreted as an
}
else
{
- cp_parser_error (parser, "expected `,' or `...'");
- if (!cp_parser_parsing_tentatively (parser)
- || cp_parser_committed_to_tentative_parse (parser))
+ cp_parser_error (parser, "expected %<,%> or %<...%>");
+ if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
cp_parser_skip_to_closing_parenthesis (parser,
/*recovering=*/true,
/*or_comma=*/false,
function-type (taking a "char" as a parameter) or a cast
of some object of type "char" to "int". */
&& !parser->in_type_id_in_expr_p
- && cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser)
+ && cp_parser_uncommitted_to_tentative_parse_p (parser)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
cp_parser_commit_to_tentative_parse (parser);
/* Parse the declarator. */
declarator = cp_parser_declarator (parser,
CP_PARSER_DECLARATOR_EITHER,
/*ctor_dtor_or_conv_p=*/NULL,
- parenthesized_p);
+ parenthesized_p,
+ /*member_p=*/false);
parser->default_arg_ok_p = saved_default_arg_ok_p;
/* After the declarator, allow more attributes. */
decl_specifiers.attributes
&& TYPE_BEING_DEFINED (current_class_type))
{
unsigned depth = 0;
-
- /* Create a DEFAULT_ARG to represented the unparsed default
- argument. */
- default_argument = make_node (DEFAULT_ARG);
- DEFARG_TOKENS (default_argument) = cp_token_cache_new ();
+ cp_token *first_token;
+ cp_token *token;
/* Add tokens until we have processed the entire default
- argument. */
+ argument. We add the range [first_token, token). */
+ first_token = cp_lexer_peek_token (parser->lexer);
while (true)
{
bool done = false;
- cp_token *token;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* Add the token to the token block. */
token = cp_lexer_consume_token (parser->lexer);
- cp_token_cache_push_token (DEFARG_TOKENS (default_argument),
- token);
}
+
+ /* Create a DEFAULT_ARG to represented the unparsed default
+ argument. */
+ default_argument = make_node (DEFAULT_ARG);
+ DEFARG_TOKENS (default_argument)
+ = cp_token_cache_new (first_token, token);
+ DEFARG_INSTANTIATIONS (default_argument) = NULL;
}
/* Outside of a class definition, we can just parse the
assignment-expression. */
= parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
/* Parse the assignment-expression. */
- default_argument = cp_parser_assignment_expression (parser);
+ default_argument
+ = cp_parser_assignment_expression (parser, /*cast_p=*/false);
/* Restore saved state. */
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
if (!parser->default_arg_ok_p)
{
if (!flag_pedantic_errors)
- warning ("deprecated use of default argument for parameter of non-function");
+ warning (0, "deprecated use of default argument for parameter of non-function");
else
{
error ("default arguments are only permitted for function parameters");
}
else if (token->type == CPP_OPEN_PAREN)
init = cp_parser_parenthesized_expression_list (parser, false,
+ /*cast_p=*/false,
non_constant_p);
else
{
{
tree initializer;
+ /* Assume the expression is constant. */
+ *non_constant_p = false;
+
/* If it is not a `{', then we are looking at an
assignment-expression. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
to indicate that names looked up in dependent types should be
assumed to be types. TEMPLATE_KEYWORD_P is true iff the `template'
keyword has been used to indicate that the name that appears next
- is a template. TYPE_P is true iff the next name should be treated
- as class-name, even if it is declared to be some other kind of name
- as well. If CHECK_DEPENDENCY_P is FALSE, names are looked up in
- dependent scopes. If CLASS_HEAD_P is TRUE, this class is the class
- being defined in a class-head.
+ is a template. TAG_TYPE indicates the explicit tag given before
+ the type name, if any. If CHECK_DEPENDENCY_P is FALSE, names are
+ looked up in dependent scopes. If CLASS_HEAD_P is TRUE, this class
+ is the class being defined in a class-head.
Returns the TYPE_DECL representing the class. */
cp_parser_class_name (cp_parser *parser,
bool typename_keyword_p,
bool template_keyword_p,
- bool type_p,
+ enum tag_types tag_type,
bool check_dependency_p,
bool class_head_p,
bool is_declaration)
resolution operator, object, function, and enumerator
names are ignored. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
- type_p = true;
+ tag_type = typename_type;
/* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier,
- type_p,
+ tag_type,
/*is_template=*/false,
/*is_namespace=*/false,
check_dependency_p,
/* If this is a typename, create a TYPENAME_TYPE. */
if (typename_p && decl != error_mark_node)
{
- decl = make_typename_type (scope, decl, /*complain=*/1);
+ decl = make_typename_type (scope, decl, typename_type, /*complain=*/1);
if (decl != error_mark_node)
decl = TYPE_NAME (decl);
}
standard does not seem to be definitive, but there is no other
valid interpretation of the following `::'. Therefore, those
names are considered class-names. */
- decl = TYPE_NAME (make_typename_type (scope, decl, tf_error));
+ decl = TYPE_NAME (make_typename_type (scope, decl, tag_type, tf_error));
else if (decl == error_mark_node
|| TREE_CODE (decl) != TYPE_DECL
+ || TREE_TYPE (decl) == error_mark_node
|| !IS_AGGR_TYPE (TREE_TYPE (decl)))
{
cp_parser_error (parser, "expected class-name");
int has_trailing_semicolon;
bool nested_name_specifier_p;
unsigned saved_num_template_parameter_lists;
- bool pop_p = false;
+ tree old_scope = NULL_TREE;
tree scope = NULL_TREE;
push_deferring_access_checks (dk_no_deferred);
if (nested_name_specifier_p)
{
scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
- pop_p = push_scope (scope);
+ old_scope = push_inner_scope (scope);
}
type = begin_class_definition (type);
}
if (type != error_mark_node)
type = finish_struct (type, attributes);
- if (pop_p)
- pop_scope (scope);
+ if (nested_name_specifier_p)
+ pop_inner_scope (old_scope, scope);
/* If this class is not itself within the scope of another class,
then we need to parse the bodies of all of the queued function
definitions. Note that the queued functions defined in a class
{
tree queue_entry;
tree fn;
- tree class_type;
- bool pop_p;
+ tree class_type = NULL_TREE;
+ tree pushed_scope = NULL_TREE;
/* In a first pass, parse default arguments to the functions.
Then, in a second pass, parse the bodies of the functions.
};
*/
- class_type = NULL_TREE;
- pop_p = false;
for (TREE_PURPOSE (parser->unparsed_functions_queues)
= nreverse (TREE_PURPOSE (parser->unparsed_functions_queues));
(queue_entry = TREE_PURPOSE (parser->unparsed_functions_queues));
take care of them now. */
if (class_type != TREE_PURPOSE (queue_entry))
{
- if (pop_p)
- pop_scope (class_type);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
class_type = TREE_PURPOSE (queue_entry);
- pop_p = push_scope (class_type);
+ pushed_scope = push_scope (class_type);
}
/* Make sure that any template parameters are in scope. */
maybe_begin_member_template_processing (fn);
/* Remove any template parameters from the symbol table. */
maybe_end_member_template_processing ();
}
- if (pop_p)
- pop_scope (class_type);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
/* Now parse the body of the functions. */
for (TREE_VALUE (parser->unparsed_functions_queues)
= nreverse (TREE_VALUE (parser->unparsed_functions_queues));
*NESTED_NAME_SPECIFIER_P to TRUE iff one of the productions
involving a nested-name-specifier was used, and FALSE otherwise.
+ Returns error_mark_node if this is not a class-head.
+
Returns NULL_TREE if the class-head is syntactically valid, but
semantically invalid in a way that means we should skip the entire
body of the class. */
bool qualified_p = false;
bool invalid_nested_name_p = false;
bool invalid_explicit_specialization_p = false;
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
unsigned num_templates;
tree bases;
type = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- /*type_p=*/true,
+ class_type,
/*check_dependency_p=*/false,
/*class_head_p=*/true,
/*is_declaration=*/false);
xref_tag, since that has irreversible side-effects. */
if (!cp_parser_next_token_starts_class_definition_p (parser))
{
- cp_parser_error (parser, "expected `{' or `:'");
+ cp_parser_error (parser, "expected %<{%> or %<:%>");
return error_mark_node;
}
else if (nested_name_specifier)
{
tree scope;
+
+ /* Reject typedef-names in class heads. */
+ if (!DECL_IMPLICIT_TYPEDEF_P (type))
+ {
+ error ("invalid class name in declaration of %qD", type);
+ type = NULL_TREE;
+ goto done;
+ }
+
/* Figure out in what scope the declaration is being placed. */
scope = current_scope ();
- if (!scope)
- scope = current_namespace;
/* If that scope does not contain the scope in which the
class was originally declared, the program is invalid. */
if (scope && !is_ancestor (scope, nested_name_specifier))
{
- error ("declaration of `%D' in `%D' which does not "
- "enclose `%D'", type, scope, nested_name_specifier);
+ error ("declaration of %qD in %qD which does not enclose %qD",
+ type, scope, nested_name_specifier);
type = NULL_TREE;
goto done;
}
&& parser->num_template_parameter_lists == 0
&& template_id_p)
{
- error ("an explicit specialization must be preceded by 'template <>'");
+ error ("an explicit specialization must be preceded by %<template <>%>");
invalid_explicit_specialization_p = true;
/* Take the same action that would have been taken by
cp_parser_explicit_specialization. */
{
type = TREE_TYPE (id);
maybe_process_partial_specialization (type);
+ if (nested_name_specifier)
+ pushed_scope = push_scope (nested_name_specifier);
}
- else if (!nested_name_specifier)
- {
- /* If the class was unnamed, create a dummy name. */
- if (!id)
- id = make_anon_name ();
- type = xref_tag (class_key, id, /*globalize=*/false,
- parser->num_template_parameter_lists);
- }
- else
+ else if (nested_name_specifier)
{
tree class_type;
- bool pop_p = false;
/* Given:
maybe_process_partial_specialization (TREE_TYPE (type));
class_type = current_class_type;
/* Enter the scope indicated by the nested-name-specifier. */
- if (nested_name_specifier)
- pop_p = push_scope (nested_name_specifier);
+ pushed_scope = push_scope (nested_name_specifier);
/* Get the canonical version of this type. */
type = TYPE_MAIN_DECL (TREE_TYPE (type));
if (PROCESSING_REAL_TEMPLATE_DECL_P ()
&& !CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (type)))
- type = push_template_decl (type);
- type = TREE_TYPE (type);
- if (nested_name_specifier)
{
- *nested_name_specifier_p = true;
- if (pop_p)
- pop_scope (nested_name_specifier);
+ type = push_template_decl (type);
+ if (type == error_mark_node)
+ {
+ type = NULL_TREE;
+ goto done;
+ }
}
+
+ type = TREE_TYPE (type);
+ *nested_name_specifier_p = true;
+ }
+ else /* The name is not a nested name. */
+ {
+ /* If the class was unnamed, create a dummy name. */
+ if (!id)
+ id = make_anon_name ();
+ type = xref_tag (class_key, id, /*tag_scope=*/ts_current,
+ parser->num_template_parameter_lists);
}
+
/* Indicate whether this class was declared as a `class' or as a
`struct'. */
if (TREE_CODE (type) == RECORD_TYPE)
CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);
cp_parser_check_class_key (class_key, type);
- /* Enter the scope containing the class; the names of base classes
- should be looked up in that context. For example, given:
+ /* If this type was already complete, and we see another definition,
+ that's an error. */
+ if (type != error_mark_node && COMPLETE_TYPE_P (type))
+ {
+ error ("redefinition of %q#T", type);
+ cp_error_at ("previous definition of %q#T", type);
+ type = NULL_TREE;
+ goto done;
+ }
+
+ /* We will have entered the scope containing the class; the names of
+ base classes should be looked up in that context. For example:
struct A { struct B {}; struct C; };
struct A::C : B {};
is valid. */
- if (nested_name_specifier)
- pop_p = push_scope (nested_name_specifier);
-
bases = NULL_TREE;
/* Get the list of base-classes, if there is one. */
/* Process the base classes. */
xref_basetypes (type, bases);
+ done:
/* Leave the scope given by the nested-name-specifier. We will
enter the class scope itself while processing the members. */
- if (pop_p)
- pop_scope (nested_name_specifier);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
- done:
if (invalid_explicit_specialization_p)
{
end_specialization ();
break;
default:
+ /* Accept #pragmas at class scope. */
+ if (token->type == CPP_PRAGMA)
+ {
+ cp_lexer_handle_pragma (parser->lexer);
+ break;
+ }
+
/* Otherwise, the next construction must be a
member-declaration. */
cp_parser_member_declaration (parser);
return;
}
+ /* Check for @defs. */
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_DEFS))
+ {
+ tree ivar, member;
+ tree ivar_chains = cp_parser_objc_defs_expression (parser);
+ ivar = ivar_chains;
+ while (ivar)
+ {
+ member = ivar;
+ ivar = TREE_CHAIN (member);
+ TREE_CHAIN (member) = NULL_TREE;
+ finish_member_declaration (member);
+ }
+ return;
+ }
+
/* Parse the decl-specifier-seq. */
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
prefix_attributes = decl_specifiers.attributes;
decl_specifiers.attributes = NULL_TREE;
/* Check for an invalid type-name. */
- if (cp_parser_parse_and_diagnose_invalid_type_name (parser))
+ if (!decl_specifiers.type
+ && cp_parser_parse_and_diagnose_invalid_type_name (parser))
return;
/* If there is no declarator, then the decl-specifier-seq should
specify a type. */
name of the class. */
if (!decl_specifiers.any_specifiers_p)
{
- if (pedantic)
- pedwarn ("extra semicolon");
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ if (pedantic && !token->in_system_header)
+ pedwarn ("%Hextra %<;%>", &token->location);
}
else
{
/* Create the bitfield declaration. */
decl = grokbitfield (identifier
- ? make_id_declarator (identifier)
+ ? make_id_declarator (NULL_TREE,
+ identifier)
: NULL,
&decl_specifiers,
width);
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
&ctor_dtor_or_conv_p,
- /*parenthesized_p=*/NULL);
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/true);
/* If something went wrong parsing the declarator, make sure
that we at least consume some tokens. */
return;
}
- cp_parser_check_for_definition_in_return_type
- (declarator, declares_class_or_enum);
+ if (declares_class_or_enum & 2)
+ cp_parser_check_for_definition_in_return_type
+ (declarator, decl_specifiers.type);
/* Look for an asm-specification. */
asm_specification = cp_parser_asm_specification_opt (parser);
initializer = NULL_TREE;
/* See if we are probably looking at a function
- definition. We are certainly not looking at at a
+ definition. We are certainly not looking at a
member-declarator. Calling `grokfield' has
side-effects, so we must not do it unless we are sure
that we are looking at a member-declarator. */
else if (cp_lexer_next_token_is_not (parser->lexer,
CPP_SEMICOLON))
{
- cp_parser_error (parser, "expected `;'");
+ cp_parser_error (parser, "expected %<;%>");
/* Skip tokens until we find a `;'. */
cp_parser_skip_to_end_of_statement (parser);
if (!cp_parser_require (parser, CPP_EQ, "`='"))
return error_mark_node;
/* Look for the `0' token. */
- token = cp_parser_require (parser, CPP_NUMBER, "`0'");
- /* Unfortunately, this will accept `0L' and `0x00' as well. We need
- to get information from the lexer about how the number was
- spelled in order to fix this problem. */
- if (!token || !integer_zerop (token->value))
- return error_mark_node;
+ token = cp_lexer_consume_token (parser->lexer);
+ if (token->type != CPP_NUMBER || !integer_zerop (token->value))
+ {
+ cp_parser_error (parser,
+ "invalid pure specifier (only `= 0' is allowed)");
+ cp_parser_skip_to_end_of_statement (parser);
+ return error_mark_node;
+ }
+ /* FIXME: Unfortunately, this will accept `0L' and `0x00' as well.
+ We need to get information from the lexer about how the number
+ was spelled in order to fix this problem. */
return integer_zero_node;
}
if (virtual_p && !duplicate_virtual_error_issued_p)
{
cp_parser_error (parser,
- "`virtual' specified more than once in base-specified");
+ "%<virtual%> specified more than once in base-specified");
duplicate_virtual_error_issued_p = true;
}
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
{
if (!processing_template_decl)
- error ("keyword `typename' not allowed outside of templates");
+ error ("keyword %<typename%> not allowed outside of templates");
else
- error ("keyword `typename' not allowed in this context "
+ error ("keyword %<typename%> not allowed in this context "
"(the base class is implicitly a type)");
cp_lexer_consume_token (parser->lexer);
}
cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/true,
/*check_dependency_p=*/true,
- /*type_p=*/true,
+ typename_type,
/*is_declaration=*/true);
/* If the base class is given by a qualified name, assume that names
we see are type names or templates, as appropriate. */
type = cp_parser_class_name (parser,
class_scope_p,
template_p,
- /*type_p=*/true,
+ typename_type,
/*check_dependency_p=*/true,
/*class_head_p=*/false,
/*is_declaration=*/true);
= "types may not be defined in exception-declarations";
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, &type_specifiers);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifiers);
/* If it's a `)', then there is no declarator. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
declarator = NULL;
else
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER,
/*ctor_dtor_or_conv_p=*/NULL,
- /*parenthesized_p=*/NULL);
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
|| token->type == CPP_COLON)
expression = NULL_TREE;
else
- expression = cp_parser_assignment_expression (parser);
+ expression = cp_parser_assignment_expression (parser,
+ /*cast_p=*/false);
return build_throw (expression);
}
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Look for the string-literal. */
- token = cp_parser_require (parser, CPP_STRING, "string-literal");
- if (token)
- asm_specification = token->value;
- else
- asm_specification = NULL_TREE;
+ asm_specification = cp_parser_string_literal (parser, false, false);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`('");
tree string_literal;
tree expression;
tree name;
- cp_token *token;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
{
else
name = NULL_TREE;
/* Look for the string-literal. */
- token = cp_parser_require (parser, CPP_STRING, "string-literal");
- string_literal = token ? token->value : error_mark_node;
- c_lex_string_translate = 1;
+ string_literal = cp_parser_string_literal (parser, false, false);
+
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Parse the expression. */
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
- c_lex_string_translate = 0;
+
/* Add this operand to the list. */
asm_operands = tree_cons (build_tree_list (name, string_literal),
expression,
while (true)
{
- cp_token *token;
tree string_literal;
/* Look for the string literal. */
- token = cp_parser_require (parser, CPP_STRING, "string-literal");
- string_literal = token ? token->value : error_mark_node;
+ string_literal = cp_parser_string_literal (parser, false, false);
/* Add it to the list. */
clobbers = tree_cons (NULL_TREE, string_literal, clobbers);
/* If the next token is not a `,', then the list is
identifier ( identifier , expression-list )
identifier ( expression-list )
- Returns a TREE_LIST. Each node corresponds to an attribute. THe
- TREE_PURPOSE of each node is the identifier indicating which
- attribute is in use. The TREE_VALUE represents the arguments, if
- any. */
+ Returns a TREE_LIST, or NULL_TREE on error. Each node corresponds
+ to an attribute. The TREE_PURPOSE of each node is the identifier
+ indicating which attribute is in use. The TREE_VALUE represents
+ the arguments, if any. */
static tree
cp_parser_attribute_list (cp_parser* parser)
{
tree attribute_list = NULL_TREE;
+ bool save_translate_strings_p = parser->translate_strings_p;
- c_lex_string_translate = 0;
+ parser->translate_strings_p = false;
while (true)
{
cp_token *token;
/* Look for the identifier. We also allow keywords here; for
example `__attribute__ ((const))' is legal. */
token = cp_lexer_peek_token (parser->lexer);
- if (token->type != CPP_NAME
- && token->type != CPP_KEYWORD)
- return error_mark_node;
- /* Consume the token. */
- token = cp_lexer_consume_token (parser->lexer);
+ if (token->type == CPP_NAME
+ || token->type == CPP_KEYWORD)
+ {
+ /* Consume the token. */
+ token = cp_lexer_consume_token (parser->lexer);
- /* Save away the identifier that indicates which attribute this is. */
- identifier = token->value;
- attribute = build_tree_list (identifier, NULL_TREE);
+ /* Save away the identifier that indicates which attribute
+ this is. */
+ identifier = token->value;
+ attribute = build_tree_list (identifier, NULL_TREE);
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* If it's an `(', then parse the attribute arguments. */
- if (token->type == CPP_OPEN_PAREN)
- {
- tree arguments;
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* If it's an `(', then parse the attribute arguments. */
+ if (token->type == CPP_OPEN_PAREN)
+ {
+ tree arguments;
- arguments = (cp_parser_parenthesized_expression_list
- (parser, true, /*non_constant_p=*/NULL));
- /* Save the identifier and arguments away. */
- TREE_VALUE (attribute) = arguments;
- }
+ arguments = (cp_parser_parenthesized_expression_list
+ (parser, true, /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
+ /* Save the identifier and arguments away. */
+ TREE_VALUE (attribute) = arguments;
+ }
- /* Add this attribute to the list. */
- TREE_CHAIN (attribute) = attribute_list;
- attribute_list = attribute;
+ /* Add this attribute to the list. */
+ TREE_CHAIN (attribute) = attribute_list;
+ attribute_list = attribute;
- /* Now, look for more attributes. */
- token = cp_lexer_peek_token (parser->lexer);
- /* If the next token isn't a `,', we're done. */
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+ /* Now, look for more attributes. If the next token isn't a
+ `,', we're done. */
if (token->type != CPP_COMMA)
break;
/* Consume the comma and keep going. */
cp_lexer_consume_token (parser->lexer);
}
- c_lex_string_translate = 1;
+ parser->translate_strings_p = save_translate_strings_p;
/* We built up the list in reverse order. */
return nreverse (attribute_list);
/* Look for an identifier. */
identifier = cp_parser_identifier (parser);
- /* Declare it as a lobel. */
+ /* If we failed, stop. */
+ if (identifier == error_mark_node)
+ break;
+ /* Declare it as a label. */
finish_label_decl (identifier);
/* If the next token is a `;', stop. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
If there was no entity with the indicated NAME, the ERROR_MARK_NODE
is returned.
- If IS_TYPE is TRUE, bindings that do not refer to types are
- ignored.
+ If TAG_TYPE is not NONE_TYPE, it indicates an explicit type keyword
+ (e.g., "struct") that was used. In that case bindings that do not
+ refer to types are ignored.
If IS_TEMPLATE is TRUE, bindings that do not refer to templates are
ignored.
static tree
cp_parser_lookup_name (cp_parser *parser, tree name,
- bool is_type, bool is_template, bool is_namespace,
+ enum tag_types tag_type,
+ bool is_template, bool is_namespace,
bool check_dependency,
bool *ambiguous_p)
{
/* If that's not a class type, there is no destructor. */
if (!type || !CLASS_TYPE_P (type))
return error_mark_node;
+ if (CLASSTYPE_LAZY_DESTRUCTOR (type))
+ lazily_declare_fn (sfk_destructor, type);
if (!CLASSTYPE_DESTRUCTORS (type))
return error_mark_node;
/* If it was a class type, return the destructor. */
if ((check_dependency || !CLASS_TYPE_P (parser->scope))
&& dependent_p)
{
- if (is_type)
- /* The resolution to Core Issue 180 says that `struct A::B'
- should be considered a type-name, even if `A' is
- dependent. */
- decl = TYPE_NAME (make_typename_type (parser->scope,
- name,
- /*complain=*/1));
+ if (tag_type)
+ {
+ tree type;
+
+ /* The resolution to Core Issue 180 says that `struct
+ A::B' should be considered a type-name, even if `A'
+ is dependent. */
+ type = make_typename_type (parser->scope, name, tag_type,
+ /*complain=*/1);
+ decl = TYPE_NAME (type);
+ }
else if (is_template)
decl = make_unbound_class_template (parser->scope,
- name,
+ name, NULL_TREE,
/*complain=*/1);
else
decl = build_nt (SCOPE_REF, parser->scope, name);
}
else
{
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
/* If PARSER->SCOPE is a dependent type, then it must be a
class type, and we must not be checking dependencies;
that PARSER->SCOPE is not considered a dependent base by
lookup_member, we must enter the scope here. */
if (dependent_p)
- pop_p = push_scope (parser->scope);
- /* If the PARSER->SCOPE is a a template specialization, it
+ pushed_scope = push_scope (parser->scope);
+ /* If the PARSER->SCOPE is a template specialization, it
may be instantiated during name lookup. In that case,
errors may be issued. Even if we rollback the current
tentative parse, those errors are valid. */
- decl = lookup_qualified_name (parser->scope, name, is_type,
+ decl = lookup_qualified_name (parser->scope, name,
+ tag_type != none_type,
/*complain=*/true);
- if (pop_p)
- pop_scope (parser->scope);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
}
parser->qualifying_scope = parser->scope;
parser->object_scope = NULL_TREE;
parse, those errors are valid. */
object_decl = lookup_member (object_type,
name,
- /*protect=*/0, is_type);
+ /*protect=*/0,
+ tag_type != none_type);
/* Look it up in the enclosing context, too. */
- decl = lookup_name_real (name, is_type, /*nonclass=*/0,
+ decl = lookup_name_real (name, tag_type != none_type,
+ /*nonclass=*/0,
/*block_p=*/true, is_namespace,
/*flags=*/0);
parser->object_scope = object_type;
}
else
{
- decl = lookup_name_real (name, is_type, /*nonclass=*/0,
+ decl = lookup_name_real (name, tag_type != none_type,
+ /*nonclass=*/0,
/*block_p=*/true, is_namespace,
/*flags=*/0);
parser->qualifying_scope = NULL_TREE;
}
/* If the lookup failed, let our caller know. */
- if (!decl
- || decl == error_mark_node
- || (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_ANTICIPATED (decl)))
+ if (!decl || decl == error_mark_node)
return error_mark_node;
/* If it's a TREE_LIST, the result of the lookup was ambiguous. */
cp_parser_error, so we incorporate its actions directly. */
if (!cp_parser_simulate_error (parser))
{
- error ("reference to `%D' is ambiguous", name);
+ error ("reference to %qD is ambiguous", name);
print_candidates (decl);
}
return error_mark_node;
cp_parser_lookup_name_simple (cp_parser* parser, tree name)
{
return cp_parser_lookup_name (parser, name,
- /*is_type=*/false,
+ none_type,
/*is_template=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true,
switch (declarator->kind)
{
case cdk_id:
- if (TREE_CODE (declarator->u.id.name) == SCOPE_REF)
+ if (declarator->u.id.qualifying_scope)
{
tree scope;
tree member;
- scope = TREE_OPERAND (declarator->u.id.name, 0);
- member = TREE_OPERAND (declarator->u.id.name, 1);
+ scope = declarator->u.id.qualifying_scope;
+ member = declarator->u.id.unqualified_name;
while (scope && CLASS_TYPE_P (scope))
{
scope = TYPE_CONTEXT (scope);
}
}
-
- /* If the DECLARATOR has the form `X<y>' then it uses one
- additional level of template parameters. */
- if (TREE_CODE (declarator->u.id.name) == TEMPLATE_ID_EXPR)
+ else if (TREE_CODE (declarator->u.id.unqualified_name)
+ == TEMPLATE_ID_EXPR)
+ /* If the DECLARATOR has the form `X<y>' then it uses one
+ additional level of template parameters. */
++num_templates;
return cp_parser_check_template_parameters (parser,
return false;
}
-/* Parse a binary-expression of the general form:
-
- binary-expression:
- <expr>
- binary-expression <token> <expr>
-
- The TOKEN_TREE_MAP maps <token> types to <expr> codes. FN is used
- to parser the <expr>s. If the first production is used, then the
- value returned by FN is returned directly. Otherwise, a node with
- the indicated EXPR_TYPE is returned, with operands corresponding to
- the two sub-expressions. */
-
-static tree
-cp_parser_binary_expression (cp_parser* parser,
- const cp_parser_token_tree_map token_tree_map,
- cp_parser_expression_fn fn)
-{
- tree lhs;
-
- /* Parse the first expression. */
- lhs = (*fn) (parser);
- /* Now, look for more expressions. */
- while (true)
- {
- cp_token *token;
- const cp_parser_token_tree_map_node *map_node;
- tree rhs;
-
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* If the token is `>', and that's not an operator at the
- moment, then we're done. */
- if (token->type == CPP_GREATER
- && !parser->greater_than_is_operator_p)
- break;
- /* If we find one of the tokens we want, build the corresponding
- tree representation. */
- for (map_node = token_tree_map;
- map_node->token_type != CPP_EOF;
- ++map_node)
- if (map_node->token_type == token->type)
- {
- /* Assume that an overloaded operator will not be used. */
- bool overloaded_p = false;
-
- /* Consume the operator token. */
- cp_lexer_consume_token (parser->lexer);
- /* Parse the right-hand side of the expression. */
- rhs = (*fn) (parser);
- /* Build the binary tree node. */
- lhs = build_x_binary_op (map_node->tree_type, lhs, rhs,
- &overloaded_p);
- /* If the binary operator required the use of an
- overloaded operator, then this expression cannot be an
- integral constant-expression. An overloaded operator
- can be used even if both operands are otherwise
- permissible in an integral constant-expression if at
- least one of the operands is of enumeration type. */
- if (overloaded_p
- && (cp_parser_non_integral_constant_expression
- (parser, "calls to overloaded operators")))
- lhs = error_mark_node;
- break;
- }
-
- /* If the token wasn't one of the ones we want, we're done. */
- if (map_node->token_type == CPP_EOF)
- break;
- }
-
- return lhs;
-}
-
/* Parse an optional `::' token indicating that the following name is
from the global namespace. If so, PARSER->SCOPE is set to the
GLOBAL_NAMESPACE. Otherwise, PARSER->SCOPE is set to NULL_TREE,
type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- /*type_p=*/false,
+ none_type,
/*check_dependency_p=*/false,
/*class_head_p=*/false,
/*is_declaration=*/false);
&& !cp_parser_storage_class_specifier_opt (parser))
{
tree type;
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
unsigned saved_num_template_parameter_lists;
/* Names appearing in the type-specifier should be looked up
return false;
}
}
- pop_p = push_scope (type);
+ pushed_scope = push_scope (type);
}
/* Inside the constructor parameter list, surrounding
= saved_num_template_parameter_lists;
/* Leave the scope of the class. */
- if (pop_p)
- pop_scope (type);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
constructor_p = !cp_parser_error_occurred (parser);
}
cp_decl_specifier_seq decl_specifiers;
bool function_definition_p = false;
+ /* This function is only used when processing a template
+ declaration. */
+ gcc_assert (innermost_scope_kind () == sk_template_parms
+ || innermost_scope_kind () == sk_template_spec);
+
/* Defer access checks until we know what is being declared. */
push_deferring_access_checks (dk_deferred);
&declares_class_or_enum);
if (friend_p)
*friend_p = cp_parser_friend_p (&decl_specifiers);
+
+ /* There are no template typedefs. */
+ if (decl_specifiers.specs[(int) ds_typedef])
+ {
+ error ("template declaration of %qs", "typedef");
+ decl = error_mark_node;
+ }
+
/* Gather up the access checks that occurred the
decl-specifier-seq. */
stop_deferring_access_checks ();
if (cp_parser_declares_only_class_p (parser))
{
decl = shadow_tag (&decl_specifiers);
+
+ /* In this case:
+
+ struct C {
+ friend template <typename T> struct A<T>::B;
+ };
+
+ A<T>::B will be represented by a TYPENAME_TYPE, and
+ therefore not recognized by shadow_tag. */
+ if (friend_p && *friend_p
+ && !decl
+ && decl_specifiers.type
+ && TYPE_P (decl_specifiers.type))
+ decl = decl_specifiers.type;
+
if (decl && decl != error_mark_node)
decl = TYPE_NAME (decl);
else
decl = error_mark_node;
}
}
- else
- decl = NULL_TREE;
/* If it's not a template class, try for a template function. If
the next token is a `;', then this declaration does not declare
anything. But, if there were errors in the decl-specifiers, then
parser->object_scope = NULL_TREE;
/* Look for a trailing `;' after the declaration. */
if (!function_definition_p
- && !cp_parser_require (parser, CPP_SEMICOLON, "`;'"))
+ && (decl == error_mark_node
+ || !cp_parser_require (parser, CPP_SEMICOLON, "`;'")))
cp_parser_skip_to_end_of_block_or_statement (parser);
return decl;
static tree
cp_parser_simple_cast_expression (cp_parser *parser)
{
- return cp_parser_cast_expression (parser, /*address_p=*/false);
+ return cp_parser_cast_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false);
}
/* Parse a functional cast to TYPE. Returns an expression
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
+ /*cast_p=*/true,
/*non_constant_p=*/NULL);
cast = build_functional_cast (type, expression_list);
cp_declarator *declarator,
tree attributes)
{
- cp_token_cache *cache;
+ cp_token *first;
+ cp_token *last;
tree fn;
/* Create the function-declaration. */
/* Remember it, if there default args to post process. */
cp_parser_save_default_args (parser, fn);
- /* Create a token cache. */
- cache = cp_token_cache_new ();
/* Save away the tokens that make up the body of the
function. */
- cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/0);
+ first = parser->lexer->next_token;
+ cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
/* Handle function try blocks. */
while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
- cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/0);
+ cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
+ last = parser->lexer->next_token;
/* Save away the inline definition; we will process it when the
class is complete. */
- DECL_PENDING_INLINE_INFO (fn) = cache;
+ DECL_PENDING_INLINE_INFO (fn) = cp_token_cache_new (first, last);
DECL_PENDING_INLINE_P (fn) = 1;
/* We need to know that this was defined in the class, so that
{
if (!saved_greater_than_is_operator_p)
{
- /* If we're in a nested template argument list, the '>>' has to be
- a typo for '> >'. We emit the error message, but we continue
- parsing and we push a '>' as next token, so that the argument
- list will be parsed correctly.. */
- cp_token* token;
- error ("`>>' should be `> >' within a nested template argument list");
- token = cp_lexer_peek_token (parser->lexer);
+ /* If we're in a nested template argument list, the '>>' has
+ to be a typo for '> >'. We emit the error message, but we
+ continue parsing and we push a '>' as next token, so that
+ the argument list will be parsed correctly. Note that the
+ global source location is still on the token before the
+ '>>', so we need to say explicitly where we want it. */
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ error ("%H%<>>%> should be %<> >%> "
+ "within a nested template argument list",
+ &token->location);
+
+ /* ??? Proper recovery should terminate two levels of
+ template argument list here. */
token->type = CPP_GREATER;
}
else
{
- /* If this is not a nested template argument list, the '>>' is
- a typo for '>'. Emit an error message and continue. */
- error ("spurious `>>', use `>' to terminate a template argument list");
+ /* If this is not a nested template argument list, the '>>'
+ is a typo for '>'. Emit an error message and continue.
+ Same deal about the token location, but here we can get it
+ right by consuming the '>>' before issuing the diagnostic. */
cp_lexer_consume_token (parser->lexer);
+ error ("spurious %<>>%>, use %<>%> to terminate "
+ "a template argument list");
}
}
- else if (!cp_parser_require (parser, CPP_GREATER, "`>'"))
- error ("missing `>' to terminate the template argument list");
+ else if (!cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
+ error ("missing %<>%> to terminate the template argument list");
+ else
+ /* It's what we want, a '>'; consume it. */
+ cp_lexer_consume_token (parser->lexer);
/* The `>' token might be a greater-than operator again now. */
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
static void
cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
{
- cp_lexer *saved_lexer;
-
/* If this member is a template, get the underlying
FUNCTION_DECL. */
if (DECL_FUNCTION_TEMPLATE_P (member_function))
tokens = DECL_PENDING_INLINE_INFO (member_function);
DECL_PENDING_INLINE_INFO (member_function) = NULL;
DECL_PENDING_INLINE_P (member_function) = 0;
- /* If this was an inline function in a local class, enter the scope
- of the containing function. */
- function_scope = decl_function_context (member_function);
+
+ /* If this is a local class, enter the scope of the containing
+ function. */
+ function_scope = current_function_decl;
if (function_scope)
push_function_context_to (function_scope);
- /* Save away the current lexer. */
- saved_lexer = parser->lexer;
- /* Make a new lexer to feed us the tokens saved for this function. */
- parser->lexer = cp_lexer_new_from_tokens (tokens);
- parser->lexer->next = saved_lexer;
-
- /* Set the current source position to be the location of the first
- token in the saved inline body. */
- cp_lexer_peek_token (parser->lexer);
+
+ /* Push the body of the function onto the lexer stack. */
+ cp_parser_push_lexer_for_tokens (parser, tokens);
/* Let the front end know that we going to be defining this
function. */
start_preparsed_function (member_function, NULL_TREE,
SF_PRE_PARSED | SF_INCLASS_INLINE);
+ /* Don't do access checking if it is a templated function. */
+ if (processing_template_decl)
+ push_deferring_access_checks (dk_no_check);
+
/* Now, parse the body of the function. */
cp_parser_function_definition_after_declarator (parser,
/*inline_p=*/true);
+ if (processing_template_decl)
+ pop_deferring_access_checks ();
+
/* Leave the scope of the containing function. */
if (function_scope)
pop_function_context_from (function_scope);
- /* Restore the lexer. */
- parser->lexer = saved_lexer;
+ cp_parser_pop_lexer (parser);
}
/* Remove any template parameters from the symbol table. */
static void
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
{
- cp_lexer *saved_lexer;
- cp_token_cache *tokens;
bool saved_local_variables_forbidden_p;
- tree parameters;
+ tree parm;
/* While we're parsing the default args, we might (due to the
statement expression extension) encounter more classes. We want
parser->unparsed_functions_queues
= tree_cons (NULL_TREE, NULL_TREE, parser->unparsed_functions_queues);
- for (parameters = TYPE_ARG_TYPES (TREE_TYPE (fn));
- parameters;
- parameters = TREE_CHAIN (parameters))
+ /* Local variable names (and the `this' keyword) may not appear
+ in a default argument. */
+ saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
+ parser->local_variables_forbidden_p = true;
+
+ for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ parm;
+ parm = TREE_CHAIN (parm))
{
- if (!TREE_PURPOSE (parameters)
- || TREE_CODE (TREE_PURPOSE (parameters)) != DEFAULT_ARG)
+ cp_token_cache *tokens;
+ tree default_arg = TREE_PURPOSE (parm);
+ tree parsed_arg;
+ VEC(tree,gc) *insts;
+ tree copy;
+ unsigned ix;
+
+ if (!default_arg)
continue;
- /* Save away the current lexer. */
- saved_lexer = parser->lexer;
- /* Create a new one, using the tokens we have saved. */
- tokens = DEFARG_TOKENS (TREE_PURPOSE (parameters));
- parser->lexer = cp_lexer_new_from_tokens (tokens);
+ if (TREE_CODE (default_arg) != DEFAULT_ARG)
+ /* This can happen for a friend declaration for a function
+ already declared with default arguments. */
+ continue;
+
+ /* Push the saved tokens for the default argument onto the parser's
+ lexer stack. */
+ tokens = DEFARG_TOKENS (default_arg);
+ cp_parser_push_lexer_for_tokens (parser, tokens);
- /* Set the current source position to be the location of the
- first token in the default argument. */
- cp_lexer_peek_token (parser->lexer);
+ /* Parse the assignment-expression. */
+ parsed_arg = cp_parser_assignment_expression (parser, /*cast_p=*/false);
- /* Local variable names (and the `this' keyword) may not appear
- in a default argument. */
- saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
- parser->local_variables_forbidden_p = true;
- /* Parse the assignment-expression. */
- TREE_PURPOSE (parameters) = cp_parser_assignment_expression (parser);
+ TREE_PURPOSE (parm) = parsed_arg;
+
+ /* Update any instantiations we've already created. */
+ for (insts = DEFARG_INSTANTIATIONS (default_arg), ix = 0;
+ VEC_iterate (tree, insts, ix, copy); ix++)
+ TREE_PURPOSE (copy) = parsed_arg;
/* If the token stream has not been completely used up, then
there was extra junk after the end of the default
argument. */
if (!cp_lexer_next_token_is (parser->lexer, CPP_EOF))
- cp_parser_error (parser, "expected `,'");
+ cp_parser_error (parser, "expected %<,%>");
- /* Restore saved state. */
- parser->lexer = saved_lexer;
- parser->local_variables_forbidden_p = saved_local_variables_forbidden_p;
+ /* Revert to the main lexer. */
+ cp_parser_pop_lexer (parser);
}
+ /* Restore the state of local_variables_forbidden_p. */
+ parser->local_variables_forbidden_p = saved_local_variables_forbidden_p;
+
/* Restore the queue. */
parser->unparsed_functions_queues
= TREE_CHAIN (parser->unparsed_functions_queues);
tree expr = NULL_TREE;
const char *saved_message;
bool saved_integral_constant_expression_p;
+ bool saved_non_integral_constant_expression_p;
/* Initialize FORMAT the first time we get here. */
if (!format)
- format = "types may not be defined in `%s' expressions";
+ format = "types may not be defined in '%s' expressions";
/* Types cannot be defined in a `sizeof' expression. Save away the
old message. */
/* The restrictions on constant-expressions do not apply inside
sizeof expressions. */
- saved_integral_constant_expression_p = parser->integral_constant_expression_p;
+ saved_integral_constant_expression_p
+ = parser->integral_constant_expression_p;
+ saved_non_integral_constant_expression_p
+ = parser->non_integral_constant_expression_p;
parser->integral_constant_expression_p = false;
/* Do not actually evaluate the expression. */
type = cp_parser_type_id (parser);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
/* Now, look for the trailing `)'. */
- cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "%<)%>");
/* If all went well, then we're done. */
if (cp_parser_parse_definitely (parser))
{
/* If the type-id production did not work out, then we must be
looking at the unary-expression production. */
if (!expr)
- expr = cp_parser_unary_expression (parser, /*address_p=*/false);
+ expr = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false);
/* Go back to evaluating expressions. */
--skip_evaluation;
free ((char *) parser->type_definition_forbidden_message);
/* And restore the old one. */
parser->type_definition_forbidden_message = saved_message;
- parser->integral_constant_expression_p = saved_integral_constant_expression_p;
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
return expr;
}
{
decl_specs->any_specifiers_p = true;
- /* If the user tries to redeclare a built-in type (with, for example,
- in "typedef int wchar_t;") we remember that this is what
+ /* If the user tries to redeclare bool or wchar_t (with, for
+ example, in "typedef int wchar_t;") we remember that this is what
happened. In system headers, we ignore these declarations so
that G++ can work with system headers that are not C++-safe. */
if (decl_specs->specs[(int) ds_typedef]
&& !user_defined_p
+ && (type_spec == boolean_type_node
+ || type_spec == wchar_type_node)
&& (decl_specs->type
|| decl_specs->specs[(int) ds_long]
|| decl_specs->specs[(int) ds_short]
}
/* Returns TRUE iff the next token is the "," or ">" ending a
- template-argument. ">>" is also accepted (after the full
- argument was parsed) because it's probably a typo for "> >",
- and there is a specific diagnostic for this. */
+ template-argument. */
static bool
cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
- return (token->type == CPP_COMMA || token->type == CPP_GREATER
- || token->type == CPP_RSHIFT);
+ return (token->type == CPP_COMMA || token->type == CPP_GREATER);
}
/* Returns TRUE iff the n-th token is a ">", or the n-th is a "[" and the
cp_parser_check_class_key (enum tag_types class_key, tree type)
{
if ((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type))
- pedwarn ("`%s' tag used in naming `%#T'",
+ pedwarn ("%qs tag used in naming %q#T",
class_key == union_type ? "union"
: class_key == record_type ? "struct" : "class",
type);
This applies to nested classes and nested class templates.
[class.mem/1]. */
-static void cp_parser_check_access_in_redeclaration (tree decl)
+static void
+cp_parser_check_access_in_redeclaration (tree decl)
{
if (!CLASS_TYPE_P (TREE_TYPE (decl)))
return;
!= (current_access_specifier == access_private_node))
|| (TREE_PROTECTED (decl)
!= (current_access_specifier == access_protected_node)))
- error ("%D redeclared with different access", decl);
+ error ("%qD redeclared with different access", decl);
}
/* Look for the `template' keyword, as a syntactic disambiguator.
template and what is not. */
if (!processing_template_decl)
{
- error ("`template' (as a disambiguator) is only allowed "
+ error ("%<template%> (as a disambiguator) is only allowed "
"within templates");
/* If this part of the token stream is rescanned, the same
error message would be generated. So, we purge the token
parser->object_scope = NULL_TREE;
}
-/* Add tokens to CACHE until a non-nested END token appears. */
+/* Consume tokens up through a non-nested END token. */
static void
-cp_parser_cache_group_1 (cp_parser *parser,
- cp_token_cache *cache,
- enum cpp_ttype end,
- unsigned depth)
+cp_parser_cache_group (cp_parser *parser,
+ enum cpp_ttype end,
+ unsigned depth)
{
while (true)
{
return;
/* Consume the next token. */
token = cp_lexer_consume_token (parser->lexer);
- /* Add this token to the tokens we are saving. */
- cp_token_cache_push_token (cache, token);
/* See if it starts a new group. */
if (token->type == CPP_OPEN_BRACE)
{
- cp_parser_cache_group_1 (parser, cache, CPP_CLOSE_BRACE, depth + 1);
+ cp_parser_cache_group (parser, CPP_CLOSE_BRACE, depth + 1);
if (depth == 0)
return;
}
else if (token->type == CPP_OPEN_PAREN)
- cp_parser_cache_group_1 (parser, cache, CPP_CLOSE_PAREN, depth + 1);
+ cp_parser_cache_group (parser, CPP_CLOSE_PAREN, depth + 1);
else if (token->type == end)
return;
}
}
-/* Convenient interface for cp_parser_cache_group_1 that makes sure we
- preserve string tokens in both translated and untranslated
- forms. */
-
-static void
-cp_parser_cache_group (cp_parser *parser,
- cp_token_cache *cache,
- enum cpp_ttype end,
- unsigned depth)
-{
- int saved_c_lex_string_translate;
-
- saved_c_lex_string_translate = c_lex_string_translate;
- c_lex_string_translate = -1;
-
- cp_parser_cache_group_1 (parser, cache, end, depth);
-
- c_lex_string_translate = saved_c_lex_string_translate;
-}
-
-
/* Begin parsing tentatively. We always save tokens while parsing
tentatively so that if the tentative parsing fails we can restore the
tokens. */
return !error_occurred;
}
-/* Returns true if we are parsing tentatively -- but have decided that
- we will stick with this tentative parse, even if errors occur. */
+/* Returns true if we are parsing tentatively and are not committed to
+ this tentative parse. */
static bool
-cp_parser_committed_to_tentative_parse (cp_parser* parser)
+cp_parser_uncommitted_to_tentative_parse_p (cp_parser* parser)
{
return (cp_parser_parsing_tentatively (parser)
- && parser->context->status == CP_PARSER_STATUS_KIND_COMMITTED);
+ && parser->context->status != CP_PARSER_STATUS_KIND_COMMITTED);
}
/* Returns nonzero iff an error has occurred during the most recent
{
return parser->allow_gnu_extensions_p;
}
+\f
+/* Objective-C++ Productions */
+
+
+/* Parse an Objective-C expression, which feeds into a primary-expression
+ above.
+
+ objc-expression:
+ objc-message-expression
+ objc-string-literal
+ objc-encode-expression
+ objc-protocol-expression
+ objc-selector-expression
+
+ Returns a tree representation of the expression. */
+
+static tree
+cp_parser_objc_expression (cp_parser* parser)
+{
+ /* Try to figure out what kind of declaration is present. */
+ cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+
+ switch (kwd->type)
+ {
+ case CPP_OPEN_SQUARE:
+ return cp_parser_objc_message_expression (parser);
+
+ case CPP_OBJC_STRING:
+ kwd = cp_lexer_consume_token (parser->lexer);
+ return objc_build_string_object (kwd->value);
+
+ case CPP_KEYWORD:
+ switch (kwd->keyword)
+ {
+ case RID_AT_ENCODE:
+ return cp_parser_objc_encode_expression (parser);
+
+ case RID_AT_PROTOCOL:
+ return cp_parser_objc_protocol_expression (parser);
+
+ case RID_AT_SELECTOR:
+ return cp_parser_objc_selector_expression (parser);
+
+ default:
+ break;
+ }
+ default:
+ error ("misplaced `@%D' Objective-C++ construct", kwd->value);
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ }
+
+ return error_mark_node;
+}
+
+/* Parse an Objective-C message expression.
+ objc-message-expression:
+ [ objc-message-receiver objc-message-args ]
+
+ Returns a representation of an Objective-C message. */
+
+static tree
+cp_parser_objc_message_expression (cp_parser* parser)
+{
+ tree receiver, messageargs;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '['. */
+ receiver = cp_parser_objc_message_receiver (parser);
+ messageargs = cp_parser_objc_message_args (parser);
+ cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+
+ return objc_build_message_expr (build_tree_list (receiver, messageargs));
+}
+
+/* Parse an objc-message-receiver.
+
+ objc-message-receiver:
+ expression
+ simple-type-specifier
+
+ Returns a representation of the type or expression. */
+
+static tree
+cp_parser_objc_message_receiver (cp_parser* parser)
+{
+ tree rcv;
+
+ /* An Objective-C message receiver may be either (1) a type
+ or (2) an expression. */
+ cp_parser_parse_tentatively (parser);
+ rcv = cp_parser_expression (parser, false);
+
+ if (cp_parser_parse_definitely (parser))
+ return rcv;
+
+ rcv = cp_parser_simple_type_specifier (parser,
+ /*decl_specs=*/NULL,
+ CP_PARSER_FLAGS_NONE);
+
+ return objc_get_class_reference (rcv);
+}
+
+/* Parse the arguments and selectors comprising an Objective-C message.
+
+ objc-message-args:
+ objc-selector
+ objc-selector-args
+ objc-selector-args , objc-comma-args
+
+ objc-selector-args:
+ objc-selector [opt] : assignment-expression
+ objc-selector-args objc-selector [opt] : assignment-expression
+
+ objc-comma-args:
+ assignment-expression
+ objc-comma-args , assignment-expression
+
+ Returns a TREE_LIST, with TREE_PURPOSE containing a list of
+ selector arguments and TREE_VALUE containing a list of comma
+ arguments. */
+
+static tree
+cp_parser_objc_message_args (cp_parser* parser)
+{
+ tree sel_args = NULL_TREE, addl_args = NULL_TREE;
+ bool maybe_unary_selector_p = true;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
+ {
+ tree selector = NULL_TREE, arg;
+
+ if (token->type != CPP_COLON)
+ selector = cp_parser_objc_selector (parser);
+
+ /* Detect if we have a unary selector. */
+ if (maybe_unary_selector_p
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+ return build_tree_list (selector, NULL_TREE);
+
+ maybe_unary_selector_p = false;
+ cp_parser_require (parser, CPP_COLON, "`:'");
+ arg = cp_parser_assignment_expression (parser, false);
+
+ sel_args
+ = chainon (sel_args,
+ build_tree_list (selector, arg));
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ /* Handle non-selector arguments, if any. */
+ while (token->type == CPP_COMMA)
+ {
+ tree arg;
+
+ cp_lexer_consume_token (parser->lexer);
+ arg = cp_parser_assignment_expression (parser, false);
+
+ addl_args
+ = chainon (addl_args,
+ build_tree_list (NULL_TREE, arg));
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ return build_tree_list (sel_args, addl_args);
+}
+
+/* Parse an Objective-C encode expression.
+
+ objc-encode-expression:
+ @encode objc-typename
+
+ Returns an encoded representation of the type argument. */
+
+static tree
+cp_parser_objc_encode_expression (cp_parser* parser)
+{
+ tree type;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@encode'. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ type = complete_type (cp_parser_type_id (parser));
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ if (!type)
+ {
+ error ("`@encode' must specify a type as an argument");
+ return error_mark_node;
+ }
+
+ return objc_build_encode_expr (type);
+}
+
+/* Parse an Objective-C @defs expression. */
+
+static tree
+cp_parser_objc_defs_expression (cp_parser *parser)
+{
+ tree name;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@defs'. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ name = cp_parser_identifier (parser);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ return objc_get_class_ivars (name);
+}
+
+/* Parse an Objective-C protocol expression.
+
+ objc-protocol-expression:
+ @protocol ( identifier )
+
+ Returns a representation of the protocol expression. */
+
+static tree
+cp_parser_objc_protocol_expression (cp_parser* parser)
+{
+ tree proto;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@protocol'. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ proto = cp_parser_identifier (parser);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ return objc_build_protocol_expr (proto);
+}
+
+/* Parse an Objective-C selector expression.
+
+ objc-selector-expression:
+ @selector ( objc-method-signature )
+
+ objc-method-signature:
+ objc-selector
+ objc-selector-seq
+
+ objc-selector-seq:
+ objc-selector :
+ objc-selector-seq objc-selector :
+
+ Returns a representation of the method selector. */
+
+static tree
+cp_parser_objc_selector_expression (cp_parser* parser)
+{
+ tree sel_seq = NULL_TREE;
+ bool maybe_unary_selector_p = true;
+ cp_token *token;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@selector'. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ token = cp_lexer_peek_token (parser->lexer);
+
+ while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
+ {
+ tree selector = NULL_TREE;
+
+ if (token->type != CPP_COLON)
+ selector = cp_parser_objc_selector (parser);
+
+ /* Detect if we have a unary selector. */
+ if (maybe_unary_selector_p
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+ {
+ sel_seq = selector;
+ goto finish_selector;
+ }
+
+ maybe_unary_selector_p = false;
+ cp_parser_require (parser, CPP_COLON, "`:'");
+
+ sel_seq
+ = chainon (sel_seq,
+ build_tree_list (selector, NULL_TREE));
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ finish_selector:
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ return objc_build_selector_expr (sel_seq);
+}
+
+/* Parse a list of identifiers.
+
+ objc-identifier-list:
+ identifier
+ objc-identifier-list , identifier
+
+ Returns a TREE_LIST of identifier nodes. */
+
+static tree
+cp_parser_objc_identifier_list (cp_parser* parser)
+{
+ tree list = build_tree_list (NULL_TREE, cp_parser_identifier (parser));
+ cp_token *sep = cp_lexer_peek_token (parser->lexer);
+
+ while (sep->type == CPP_COMMA)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat ','. */
+ list = chainon (list,
+ build_tree_list (NULL_TREE,
+ cp_parser_identifier (parser)));
+ sep = cp_lexer_peek_token (parser->lexer);
+ }
+
+ return list;
+}
+
+/* Parse an Objective-C alias declaration.
+
+ objc-alias-declaration:
+ @compatibility_alias identifier identifier ;
+
+ This function registers the alias mapping with the Objective-C front-end.
+ It returns nothing. */
+
+static void
+cp_parser_objc_alias_declaration (cp_parser* parser)
+{
+ tree alias, orig;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@compatibility_alias'. */
+ alias = cp_parser_identifier (parser);
+ orig = cp_parser_identifier (parser);
+ objc_declare_alias (alias, orig);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+}
+
+/* Parse an Objective-C class forward-declaration.
+
+ objc-class-declaration:
+ @class objc-identifier-list ;
+
+ The function registers the forward declarations with the Objective-C
+ front-end. It returns nothing. */
+
+static void
+cp_parser_objc_class_declaration (cp_parser* parser)
+{
+ cp_lexer_consume_token (parser->lexer); /* Eat '@class'. */
+ objc_declare_class (cp_parser_objc_identifier_list (parser));
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+}
+
+/* Parse a list of Objective-C protocol references.
+
+ objc-protocol-refs-opt:
+ objc-protocol-refs [opt]
+
+ objc-protocol-refs:
+ < objc-identifier-list >
+
+ Returns a TREE_LIST of identifiers, if any. */
+
+static tree
+cp_parser_objc_protocol_refs_opt (cp_parser* parser)
+{
+ tree protorefs = NULL_TREE;
+
+ if(cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat '<'. */
+ protorefs = cp_parser_objc_identifier_list (parser);
+ cp_parser_require (parser, CPP_GREATER, "`>'");
+ }
+
+ return protorefs;
+}
+
+/* Parse a Objective-C visibility specification. */
+
+static void
+cp_parser_objc_visibility_spec (cp_parser* parser)
+{
+ cp_token *vis = cp_lexer_peek_token (parser->lexer);
+
+ switch (vis->keyword)
+ {
+ case RID_AT_PRIVATE:
+ objc_set_visibility (2);
+ break;
+ case RID_AT_PROTECTED:
+ objc_set_visibility (0);
+ break;
+ case RID_AT_PUBLIC:
+ objc_set_visibility (1);
+ break;
+ default:
+ return;
+ }
+
+ /* Eat '@private'/'@protected'/'@public'. */
+ cp_lexer_consume_token (parser->lexer);
+}
+
+/* Parse an Objective-C method type. */
+
+static void
+cp_parser_objc_method_type (cp_parser* parser)
+{
+ objc_set_method_type
+ (cp_lexer_consume_token (parser->lexer)->type == CPP_PLUS
+ ? PLUS_EXPR
+ : MINUS_EXPR);
+}
+
+/* Parse an Objective-C protocol qualifier. */
+
+static tree
+cp_parser_objc_protocol_qualifiers (cp_parser* parser)
+{
+ tree quals = NULL_TREE, node;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ node = token->value;
+
+ while (node && TREE_CODE (node) == IDENTIFIER_NODE
+ && (node == ridpointers [(int) RID_IN]
+ || node == ridpointers [(int) RID_OUT]
+ || node == ridpointers [(int) RID_INOUT]
+ || node == ridpointers [(int) RID_BYCOPY]
+ || node == ridpointers [(int) RID_BYREF]
+ || node == ridpointers [(int) RID_ONEWAY]))
+ {
+ quals = tree_cons (NULL_TREE, node, quals);
+ cp_lexer_consume_token (parser->lexer);
+ token = cp_lexer_peek_token (parser->lexer);
+ node = token->value;
+ }
+
+ return quals;
+}
+
+/* Parse an Objective-C typename. */
+
+static tree
+cp_parser_objc_typename (cp_parser* parser)
+{
+ tree typename = NULL_TREE;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ tree proto_quals, cp_type = NULL_TREE;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '('. */
+ proto_quals = cp_parser_objc_protocol_qualifiers (parser);
+
+ /* An ObjC type name may consist of just protocol qualifiers, in which
+ case the type shall default to 'id'. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+ cp_type = cp_parser_type_id (parser);
+
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ typename = build_tree_list (proto_quals, cp_type);
+ }
+
+ return typename;
+}
+
+/* Check to see if TYPE refers to an Objective-C selector name. */
+
+static bool
+cp_parser_objc_selector_p (enum cpp_ttype type)
+{
+ return (type == CPP_NAME || type == CPP_KEYWORD
+ || type == CPP_AND_AND || type == CPP_AND_EQ || type == CPP_AND
+ || type == CPP_OR || type == CPP_COMPL || type == CPP_NOT
+ || type == CPP_NOT_EQ || type == CPP_OR_OR || type == CPP_OR_EQ
+ || type == CPP_XOR || type == CPP_XOR_EQ);
+}
+
+/* Parse an Objective-C selector. */
+
+static tree
+cp_parser_objc_selector (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_consume_token (parser->lexer);
+
+ if (!cp_parser_objc_selector_p (token->type))
+ {
+ error ("invalid Objective-C++ selector name");
+ return error_mark_node;
+ }
+
+ /* C++ operator names are allowed to appear in ObjC selectors. */
+ switch (token->type)
+ {
+ case CPP_AND_AND: return get_identifier ("and");
+ case CPP_AND_EQ: return get_identifier ("and_eq");
+ case CPP_AND: return get_identifier ("bitand");
+ case CPP_OR: return get_identifier ("bitor");
+ case CPP_COMPL: return get_identifier ("compl");
+ case CPP_NOT: return get_identifier ("not");
+ case CPP_NOT_EQ: return get_identifier ("not_eq");
+ case CPP_OR_OR: return get_identifier ("or");
+ case CPP_OR_EQ: return get_identifier ("or_eq");
+ case CPP_XOR: return get_identifier ("xor");
+ case CPP_XOR_EQ: return get_identifier ("xor_eq");
+ default: return token->value;
+ }
+}
+
+/* Parse an Objective-C params list. */
+
+static tree
+cp_parser_objc_method_keyword_params (cp_parser* parser)
+{
+ tree params = NULL_TREE;
+ bool maybe_unary_selector_p = true;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
+ {
+ tree selector = NULL_TREE, typename, identifier;
+
+ if (token->type != CPP_COLON)
+ selector = cp_parser_objc_selector (parser);
+
+ /* Detect if we have a unary selector. */
+ if (maybe_unary_selector_p
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+ return selector;
+
+ maybe_unary_selector_p = false;
+ cp_parser_require (parser, CPP_COLON, "`:'");
+ typename = cp_parser_objc_typename (parser);
+ identifier = cp_parser_identifier (parser);
+
+ params
+ = chainon (params,
+ objc_build_keyword_decl (selector,
+ typename,
+ identifier));
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ return params;
+}
+
+/* Parse the non-keyword Objective-C params. */
+
+static tree
+cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp)
+{
+ tree params = make_node (TREE_LIST);
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ *ellipsisp = false; /* Initially, assume no ellipsis. */
+
+ while (token->type == CPP_COMMA)
+ {
+ cp_parameter_declarator *parmdecl;
+ tree parm;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat ','. */
+ token = cp_lexer_peek_token (parser->lexer);
+
+ if (token->type == CPP_ELLIPSIS)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat '...'. */
+ *ellipsisp = true;
+ break;
+ }
+
+ parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
+ parm = grokdeclarator (parmdecl->declarator,
+ &parmdecl->decl_specifiers,
+ PARM, /*initialized=*/0,
+ /*attrlist=*/NULL);
+
+ chainon (params, build_tree_list (NULL_TREE, parm));
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ return params;
+}
+
+/* Parse a linkage specification, a pragma, an extra semicolon or a block. */
+
+static void
+cp_parser_objc_interstitial_code (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ /* If the next token is `extern' and the following token is a string
+ literal, then we have a linkage specification. */
+ if (token->keyword == RID_EXTERN
+ && cp_parser_is_string_literal (cp_lexer_peek_nth_token (parser->lexer, 2)))
+ cp_parser_linkage_specification (parser);
+ /* Handle #pragma, if any. */
+ else if (token->type == CPP_PRAGMA)
+ cp_lexer_handle_pragma (parser->lexer);
+ /* Allow stray semicolons. */
+ else if (token->type == CPP_SEMICOLON)
+ cp_lexer_consume_token (parser->lexer);
+ /* Finally, try to parse a block-declaration, or a function-definition. */
+ else
+ cp_parser_block_declaration (parser, /*statement_p=*/false);
+}
+
+/* Parse a method signature. */
+
+static tree
+cp_parser_objc_method_signature (cp_parser* parser)
+{
+ tree rettype, kwdparms, optparms;
+ bool ellipsis = false;
+
+ cp_parser_objc_method_type (parser);
+ rettype = cp_parser_objc_typename (parser);
+ kwdparms = cp_parser_objc_method_keyword_params (parser);
+ optparms = cp_parser_objc_method_tail_params_opt (parser, &ellipsis);
+
+ return objc_build_method_signature (rettype, kwdparms, optparms, ellipsis);
+}
+
+/* Pars an Objective-C method prototype list. */
+
+static void
+cp_parser_objc_method_prototype_list (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ while (token->keyword != RID_AT_END)
+ {
+ if (token->type == CPP_PLUS || token->type == CPP_MINUS)
+ {
+ objc_add_method_declaration
+ (cp_parser_objc_method_signature (parser));
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ }
+ else
+ /* Allow for interspersed non-ObjC++ code. */
+ cp_parser_objc_interstitial_code (parser);
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@end'. */
+ objc_finish_interface ();
+}
+
+/* Parse an Objective-C method definition list. */
+
+static void
+cp_parser_objc_method_definition_list (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ while (token->keyword != RID_AT_END)
+ {
+ tree meth;
+
+ if (token->type == CPP_PLUS || token->type == CPP_MINUS)
+ {
+ push_deferring_access_checks (dk_deferred);
+ objc_start_method_definition
+ (cp_parser_objc_method_signature (parser));
+
+ /* For historical reasons, we accept an optional semicolon. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
+
+ perform_deferred_access_checks ();
+ stop_deferring_access_checks ();
+ meth = cp_parser_function_definition_after_declarator (parser,
+ false);
+ pop_deferring_access_checks ();
+ objc_finish_method_definition (meth);
+ }
+ else
+ /* Allow for interspersed non-ObjC++ code. */
+ cp_parser_objc_interstitial_code (parser);
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@end'. */
+ objc_finish_implementation ();
+}
+
+/* Parse Objective-C ivars. */
+
+static void
+cp_parser_objc_class_ivars (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ if (token->type != CPP_OPEN_BRACE)
+ return; /* No ivars specified. */
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '{'. */
+ token = cp_lexer_peek_token (parser->lexer);
+
+ while (token->type != CPP_CLOSE_BRACE)
+ {
+ cp_decl_specifier_seq declspecs;
+ int decl_class_or_enum_p;
+ tree prefix_attributes;
+
+ cp_parser_objc_visibility_spec (parser);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ break;
+
+ cp_parser_decl_specifier_seq (parser,
+ CP_PARSER_FLAGS_OPTIONAL,
+ &declspecs,
+ &decl_class_or_enum_p);
+ prefix_attributes = declspecs.attributes;
+ declspecs.attributes = NULL_TREE;
+
+ /* Keep going until we hit the `;' at the end of the
+ declaration. */
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ {
+ tree width = NULL_TREE, attributes, first_attribute, decl;
+ cp_declarator *declarator = NULL;
+ int ctor_dtor_or_conv_p;
+
+ /* Check for a (possibly unnamed) bitfield declaration. */
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_COLON)
+ goto eat_colon;
+
+ if (token->type == CPP_NAME
+ && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
+ == CPP_COLON))
+ {
+ /* Get the name of the bitfield. */
+ declarator = make_id_declarator (NULL_TREE,
+ cp_parser_identifier (parser));
+
+ eat_colon:
+ cp_lexer_consume_token (parser->lexer); /* Eat ':'. */
+ /* Get the width of the bitfield. */
+ width
+ = cp_parser_constant_expression (parser,
+ /*allow_non_constant=*/false,
+ NULL);
+ }
+ else
+ {
+ /* Parse the declarator. */
+ declarator
+ = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ &ctor_dtor_or_conv_p,
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
+ }
+
+ /* Look for attributes that apply to the ivar. */
+ attributes = cp_parser_attributes_opt (parser);
+ /* Remember which attributes are prefix attributes and
+ which are not. */
+ first_attribute = attributes;
+ /* Combine the attributes. */
+ attributes = chainon (prefix_attributes, attributes);
+
+ if (width)
+ {
+ /* Create the bitfield declaration. */
+ decl = grokbitfield (declarator, &declspecs, width);
+ cplus_decl_attributes (&decl, attributes, /*flags=*/0);
+ }
+ else
+ decl = grokfield (declarator, &declspecs, NULL_TREE,
+ NULL_TREE, attributes);
+
+ /* Add the instance variable. */
+ objc_add_instance_variable (decl);
+
+ /* Reset PREFIX_ATTRIBUTES. */
+ while (attributes && TREE_CHAIN (attributes) != first_attribute)
+ attributes = TREE_CHAIN (attributes);
+ if (attributes)
+ TREE_CHAIN (attributes) = NULL_TREE;
+
+ token = cp_lexer_peek_token (parser->lexer);
+
+ if (token->type == CPP_COMMA)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat ','. */
+ continue;
+ }
+ break;
+ }
+
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '}'. */
+ /* For historical reasons, we accept an optional semicolon. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
+}
+
+/* Parse an Objective-C protocol declaration. */
+
+static void
+cp_parser_objc_protocol_declaration (cp_parser* parser)
+{
+ tree proto, protorefs;
+ cp_token *tok;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@protocol'. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+ {
+ error ("identifier expected after `@protocol'");
+ goto finish;
+ }
+
+ /* See if we have a forward declaration or a definition. */
+ tok = cp_lexer_peek_nth_token (parser->lexer, 2);
+
+ /* Try a forward declaration first. */
+ if (tok->type == CPP_COMMA || tok->type == CPP_SEMICOLON)
+ {
+ objc_declare_protocols (cp_parser_objc_identifier_list (parser));
+ finish:
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ }
+
+ /* Ok, we got a full-fledged definition (or at least should). */
+ else
+ {
+ proto = cp_parser_identifier (parser);
+ protorefs = cp_parser_objc_protocol_refs_opt (parser);
+ objc_start_protocol (proto, protorefs);
+ cp_parser_objc_method_prototype_list (parser);
+ }
+}
+
+/* Parse an Objective-C superclass or category. */
+
+static void
+cp_parser_objc_superclass_or_category (cp_parser *parser, tree *super,
+ tree *categ)
+{
+ cp_token *next = cp_lexer_peek_token (parser->lexer);
+
+ *super = *categ = NULL_TREE;
+ if (next->type == CPP_COLON)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat ':'. */
+ *super = cp_parser_identifier (parser);
+ }
+ else if (next->type == CPP_OPEN_PAREN)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat '('. */
+ *categ = cp_parser_identifier (parser);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ }
+}
+
+/* Parse an Objective-C class interface. */
+
+static void
+cp_parser_objc_class_interface (cp_parser* parser)
+{
+ tree name, super, categ, protos;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@interface'. */
+ name = cp_parser_identifier (parser);
+ cp_parser_objc_superclass_or_category (parser, &super, &categ);
+ protos = cp_parser_objc_protocol_refs_opt (parser);
+
+ /* We have either a class or a category on our hands. */
+ if (categ)
+ objc_start_category_interface (name, categ, protos);
+ else
+ {
+ objc_start_class_interface (name, super, protos);
+ /* Handle instance variable declarations, if any. */
+ cp_parser_objc_class_ivars (parser);
+ objc_continue_interface ();
+ }
+
+ cp_parser_objc_method_prototype_list (parser);
+}
+
+/* Parse an Objective-C class implementation. */
+
+static void
+cp_parser_objc_class_implementation (cp_parser* parser)
+{
+ tree name, super, categ;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@implementation'. */
+ name = cp_parser_identifier (parser);
+ cp_parser_objc_superclass_or_category (parser, &super, &categ);
+
+ /* We have either a class or a category on our hands. */
+ if (categ)
+ objc_start_category_implementation (name, categ);
+ else
+ {
+ objc_start_class_implementation (name, super);
+ /* Handle instance variable declarations, if any. */
+ cp_parser_objc_class_ivars (parser);
+ objc_continue_implementation ();
+ }
+
+ cp_parser_objc_method_definition_list (parser);
+}
+
+/* Consume the @end token and finish off the implementation. */
+
+static void
+cp_parser_objc_end_implementation (cp_parser* parser)
+{
+ cp_lexer_consume_token (parser->lexer); /* Eat '@end'. */
+ objc_finish_implementation ();
+}
+
+/* Parse an Objective-C declaration. */
+
+static void
+cp_parser_objc_declaration (cp_parser* parser)
+{
+ /* Try to figure out what kind of declaration is present. */
+ cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+
+ switch (kwd->keyword)
+ {
+ case RID_AT_ALIAS:
+ cp_parser_objc_alias_declaration (parser);
+ break;
+ case RID_AT_CLASS:
+ cp_parser_objc_class_declaration (parser);
+ break;
+ case RID_AT_PROTOCOL:
+ cp_parser_objc_protocol_declaration (parser);
+ break;
+ case RID_AT_INTERFACE:
+ cp_parser_objc_class_interface (parser);
+ break;
+ case RID_AT_IMPLEMENTATION:
+ cp_parser_objc_class_implementation (parser);
+ break;
+ case RID_AT_END:
+ cp_parser_objc_end_implementation (parser);
+ break;
+ default:
+ error ("misplaced `@%D' Objective-C++ construct", kwd->value);
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ }
+}
+
+/* Parse an Objective-C try-catch-finally statement.
+
+ objc-try-catch-finally-stmt:
+ @try compound-statement objc-catch-clause-seq [opt]
+ objc-finally-clause [opt]
+
+ objc-catch-clause-seq:
+ objc-catch-clause objc-catch-clause-seq [opt]
+
+ objc-catch-clause:
+ @catch ( exception-declaration ) compound-statement
+
+ objc-finally-clause
+ @finally compound-statement
+
+ Returns NULL_TREE. */
+
+static tree
+cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
+ location_t location;
+ tree stmt;
+
+ cp_parser_require_keyword (parser, RID_AT_TRY, "`@try'");
+ location = cp_lexer_peek_token (parser->lexer)->location;
+ /* NB: The @try block needs to be wrapped in its own STATEMENT_LIST
+ node, lest it get absorbed into the surrounding block. */
+ stmt = push_stmt_list ();
+ cp_parser_compound_statement (parser, NULL, false);
+ objc_begin_try_stmt (location, pop_stmt_list (stmt));
+
+ while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH))
+ {
+ cp_parameter_declarator *parmdecl;
+ tree parm;
+
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
+ parm = grokdeclarator (parmdecl->declarator,
+ &parmdecl->decl_specifiers,
+ PARM, /*initialized=*/0,
+ /*attrlist=*/NULL);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ objc_begin_catch_clause (parm);
+ cp_parser_compound_statement (parser, NULL, false);
+ objc_finish_catch_clause ();
+ }
+
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_FINALLY))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ location = cp_lexer_peek_token (parser->lexer)->location;
+ /* NB: The @finally block needs to be wrapped in its own STATEMENT_LIST
+ node, lest it get absorbed into the surrounding block. */
+ stmt = push_stmt_list ();
+ cp_parser_compound_statement (parser, NULL, false);
+ objc_build_finally_clause (location, pop_stmt_list (stmt));
+ }
+
+ return objc_finish_try_stmt ();
+}
+
+/* Parse an Objective-C synchronized statement.
+
+ objc-synchronized-stmt:
+ @synchronized ( expression ) compound-statement
+
+ Returns NULL_TREE. */
+
+static tree
+cp_parser_objc_synchronized_statement (cp_parser *parser) {
+ location_t location;
+ tree lock, stmt;
+
+ cp_parser_require_keyword (parser, RID_AT_SYNCHRONIZED, "`@synchronized'");
+
+ location = cp_lexer_peek_token (parser->lexer)->location;
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ lock = cp_parser_expression (parser, false);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ /* NB: The @synchronized block needs to be wrapped in its own STATEMENT_LIST
+ node, lest it get absorbed into the surrounding block. */
+ stmt = push_stmt_list ();
+ cp_parser_compound_statement (parser, NULL, false);
+
+ return objc_build_synchronized (location, lock, pop_stmt_list (stmt));
+}
+
+/* Parse an Objective-C throw statement.
+
+ objc-throw-stmt:
+ @throw assignment-expression [opt] ;
+
+ Returns a constructed '@throw' statement. */
+
+static tree
+cp_parser_objc_throw_statement (cp_parser *parser) {
+ tree expr = NULL_TREE;
+
+ cp_parser_require_keyword (parser, RID_AT_THROW, "`@throw'");
+
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ expr = cp_parser_assignment_expression (parser, false);
+
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ return objc_build_throw_stmt (expr);
+}
+
+/* Parse an Objective-C statement. */
+
+static tree
+cp_parser_objc_statement (cp_parser * parser) {
+ /* Try to figure out what kind of declaration is present. */
+ cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+
+ switch (kwd->keyword)
+ {
+ case RID_AT_TRY:
+ return cp_parser_objc_try_catch_finally_statement (parser);
+ case RID_AT_SYNCHRONIZED:
+ return cp_parser_objc_synchronized_statement (parser);
+ case RID_AT_THROW:
+ return cp_parser_objc_throw_statement (parser);
+ default:
+ error ("misplaced `@%D' Objective-C++ construct", kwd->value);
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ }
+
+ return error_mark_node;
+}
\f
/* The parser. */