#include "toplev.h"
#include "output.h"
#include "target.h"
+#include "cgraph.h"
#include "c-common.h"
\f
ENUM_BITFIELD (rid) keyword : 8;
/* Token flags. */
unsigned char flags;
+ /* Identifier for the pragma. */
+ ENUM_BITFIELD (pragma_kind) pragma_kind : 6;
/* 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;
+ /* True for a CPP_NAME token that is not a keyword (i.e., for which
+ KEYWORD is RID_MAX) iff this name was looked up and found to be
+ ambiguous. An error has already been reported. */
+ BOOL_BITFIELD ambiguous_p : 1;
/* The value associated with this token, if any. */
tree value;
/* The location at which this token was found. */
static const cp_token eof_token =
{
- CPP_EOF, RID_MAX, 0, 0, 0, NULL_TREE,
+ CPP_EOF, RID_MAX, 0, PRAGMA_NONE, 0, 0, false, NULL_TREE,
#if USE_MAPPED_LOCATION
0
#else
tokens. */
VEC(cp_token_position,heap) *GTY ((skip)) saved_tokens;
+ /* The next lexer in a linked list of lexers. */
+ struct cp_lexer *next;
+
/* True if we should output debugging information. */
bool debugging_p;
- /* The next lexer in a linked list of lexers. */
- struct cp_lexer *next;
+ /* True if we're in the context of parsing a pragma, and should not
+ increment past the end-of-line marker. */
+ bool in_pragma;
} cp_lexer;
/* cp_token_cache is a range of tokens. There is no need to represent
(cp_lexer *);
static void cp_lexer_purge_tokens_after
(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
static cp_token_cache *cp_token_cache_new
(cp_token *, cp_token *);
+static void cp_parser_initial_pragma
+ (cp_token *);
+
/* Manifest constants. */
#define CP_LEXER_BUFFER_SIZE 10000
#define CP_SAVED_TOKEN_STACK 5
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. 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);
+ /* It's possible that parsing the first pragma will load a PCH file,
+ which is a GC collection point. So we have to do that before
+ allocating any memory. */
+ cp_parser_initial_pragma (&first_token);
- /* Tell cpplib we want CPP_PRAGMA tokens. */
- cpp_get_options (parse_in)->defer_pragmas = true;
-
- /* Tell c_lex not to merge string constants. */
+ /* Tell c_lex_with_flags not to merge string constants. */
c_lex_return_raw_strings = true;
c_common_no_more_pch ();
/* Create the buffer. */
alloc = CP_LEXER_BUFFER_SIZE;
- buffer = ggc_alloc (alloc * sizeof (cp_token));
+ buffer = GGC_NEWVEC (cp_token, alloc);
/* Put the first token in the buffer. */
space = alloc;
{
space = alloc;
alloc *= 2;
- buffer = ggc_realloc (buffer, alloc * sizeof (cp_token));
+ buffer = GGC_RESIZEVEC (cp_token, buffer, alloc);
pos = buffer + space;
}
cp_lexer_get_preprocessor_token (lexer, pos);
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;
+ /* Subsequent preprocessor diagnostics should use compiler
+ diagnostic functions to get the compiler source location. */
+ cpp_get_options (parse_in)->client_diagnostic = true;
+ cpp_get_callbacks (parse_in)->error = cp_cpp_error;
gcc_assert (lexer->next_token->type != CPP_PURGED);
return lexer;
/* Get a new token from the preprocessor. */
token->type
= c_lex_with_flags (&token->value, &token->location, &token->flags);
+ token->keyword = RID_MAX;
+ token->pragma_kind = PRAGMA_NONE;
token->in_system_header = in_system_header;
/* On some systems, some header files are surrounded by an
token->implicit_extern_c = is_extern_c > 0;
/* Check to see if this token is a keyword. */
- if (token->type == CPP_NAME
- && C_IS_RESERVED_WORD (token->value))
+ if (token->type == CPP_NAME)
{
- /* Mark this token as a keyword. */
- token->type = CPP_KEYWORD;
- /* Record which keyword. */
- token->keyword = C_RID_CODE (token->value);
- /* Update the value. Some keywords are mapped to particular
- entities, rather than simply having the value of the
- corresponding IDENTIFIER_NODE. For example, `__const' is
- mapped to `const'. */
- token->value = ridpointers[token->keyword];
+ if (C_IS_RESERVED_WORD (token->value))
+ {
+ /* Mark this token as a keyword. */
+ token->type = CPP_KEYWORD;
+ /* Record which keyword. */
+ token->keyword = C_RID_CODE (token->value);
+ /* Update the value. Some keywords are mapped to particular
+ entities, rather than simply having the value of the
+ corresponding IDENTIFIER_NODE. For example, `__const' is
+ mapped to `const'. */
+ token->value = ridpointers[token->keyword];
+ }
+ else
+ {
+ token->ambiguous_p = false;
+ token->keyword = RID_MAX;
+ }
}
/* Handle Objective-C++ keywords. */
else if (token->type == CPP_AT_NAME)
default: token->keyword = C_RID_CODE (token->value);
}
}
- else
- token->keyword = RID_MAX;
+ else if (token->type == CPP_PRAGMA)
+ {
+ /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
+ token->pragma_kind = TREE_INT_CST_LOW (token->value);
+ token->value = NULL;
+ }
}
/* Update the globals input_location and in_system_header from TOKEN. */
static inline bool
cp_lexer_next_token_is_keyword (cp_lexer* lexer, enum rid keyword)
{
- cp_token *token;
-
- /* Peek at the next token. */
- token = cp_lexer_peek_token (lexer);
- /* Check to see if it is the indicated keyword. */
- return token->keyword == keyword;
+ return cp_lexer_peek_token (lexer)->keyword == keyword;
}
/* Return a pointer to the Nth token in the token stream. If N is 1,
cp_token *token;
/* N is 1-based, not zero-based. */
- gcc_assert (n > 0 && lexer->next_token != &eof_token);
-
+ gcc_assert (n > 0);
+
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream,
"cp_lexer: peeking ahead %ld at token: ", (long)n);
--n;
token = lexer->next_token;
+ gcc_assert (!n || token != &eof_token);
while (n != 0)
{
++token;
cp_token *token = lexer->next_token;
gcc_assert (token != &eof_token);
+ gcc_assert (!lexer->in_pragma || token->type != CPP_PRAGMA_EOL);
do
{
}
}
-/* 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. */
case CPP_STRING:
case CPP_WSTRING:
- case CPP_PRAGMA:
fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->value));
break;
\f
/* Decl-specifiers. */
-static void clear_decl_specs
- (cp_decl_specifier_seq *);
-
/* Set *DECL_SPECS to represent an empty decl-specifier-seq. */
static void
static cp_declarator *make_ptrmem_declarator
(cp_cv_quals, tree, cp_declarator *);
-cp_declarator *cp_error_declarator;
+/* An erroneous declarator. */
+static cp_declarator *cp_error_declarator;
/* The obstack on which declarators and related data structures are
allocated. */
return declarator;
}
-/* Make a declarator for a generalized identifier. If non-NULL, the
- identifier is QUALIFYING_SCOPE::UNQUALIFIED_NAME; otherwise, it is
- just UNQUALIFIED_NAME. */
+/* Make a declarator for a generalized identifier. If
+ QUALIFYING_SCOPE is non-NULL, the identifier is
+ QUALIFYING_SCOPE::UNQUALIFIED_NAME; otherwise, it is just
+ UNQUALIFIED_NAME. SFK indicates the kind of special function this
+ is, if any. */
static cp_declarator *
-make_id_declarator (tree qualifying_scope, tree unqualified_name)
+make_id_declarator (tree qualifying_scope, tree unqualified_name,
+ special_function_kind sfk)
{
cp_declarator *declarator;
if (qualifying_scope && TYPE_P (qualifying_scope))
qualifying_scope = TYPE_MAIN_VARIANT (qualifying_scope);
+ gcc_assert (TREE_CODE (unqualified_name) == IDENTIFIER_NODE
+ || TREE_CODE (unqualified_name) == BIT_NOT_EXPR
+ || TREE_CODE (unqualified_name) == TEMPLATE_ID_EXPR);
+
declarator = make_declarator (cdk_id);
declarator->u.id.qualifying_scope = qualifying_scope;
declarator->u.id.unqualified_name = unqualified_name;
- declarator->u.id.sfk = sfk_none;
+ declarator->u.id.sfk = sfk;
return declarator;
}
/* TRUE if we are presently parsing a template-argument-list. */
bool in_template_argument_list_p;
- /* TRUE if we are presently parsing the body of an
- iteration-statement. */
- bool in_iteration_statement_p;
-
- /* TRUE if we are presently parsing the body of a switch
- statement. */
+ /* Set to IN_ITERATION_STMT if parsing an iteration-statement,
+ to IN_OMP_BLOCK if parsing OpenMP structured block and
+ IN_OMP_FOR if parsing OpenMP loop. If parsing a switch statement,
+ this is bitwise ORed with IN_SWITCH_STMT, unless parsing an
+ iteration-statement, OpenMP block or loop within that switch. */
+#define IN_SWITCH_STMT 1
+#define IN_ITERATION_STMT 2
+#define IN_OMP_BLOCK 4
+#define IN_OMP_FOR 8
+ unsigned char in_statement;
+
+ /* TRUE if we are presently parsing the body of a switch statement.
+ Note that this doesn't quite overlap with in_statement above.
+ The difference relates to giving the right sets of error messages:
+ "case not in switch" vs "break statement used with OpenMP...". */
bool in_switch_statement_p;
/* TRUE if we are parsing a type-id in an expression context. In
unsigned num_template_parameter_lists;
} cp_parser;
-/* The type of a function that parses some kind of expression. */
-typedef tree (*cp_parser_expression_fn) (cp_parser *);
-
/* Prototypes. */
/* Constructors and destructors. */
/* Expressions [gram.expr] */
static tree cp_parser_primary_expression
- (cp_parser *, bool, cp_id_kind *, tree *);
+ (cp_parser *, bool, bool, bool, cp_id_kind *);
static tree cp_parser_id_expression
- (cp_parser *, bool, bool, bool *, bool);
+ (cp_parser *, bool, bool, bool *, bool, bool);
static tree cp_parser_unqualified_id
- (cp_parser *, bool, bool, bool);
+ (cp_parser *, bool, bool, bool, bool);
static tree cp_parser_nested_name_specifier_opt
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_nested_name_specifier
/* Statements [gram.stmt.stmt] */
static void cp_parser_statement
- (cp_parser *, tree);
+ (cp_parser *, tree, bool);
static tree cp_parser_labeled_statement
- (cp_parser *, tree);
+ (cp_parser *, tree, bool);
static tree cp_parser_expression_statement
(cp_parser *, tree);
static tree cp_parser_compound_statement
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
- (cp_parser *, cp_decl_specifier_seq *, bool, bool, int, bool *);
+ (cp_parser *, cp_decl_specifier_seq *, tree, bool, bool, int, bool *);
static cp_declarator *cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool *, bool);
static cp_declarator *cp_parser_direct_declarator
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
(cp_parser *);
static tree cp_parser_declarator_id
- (cp_parser *);
+ (cp_parser *, bool);
static tree cp_parser_type_id
(cp_parser *);
static void cp_parser_type_specifier_seq
(cp_parser *, bool *, bool *);
static tree cp_parser_initializer_clause
(cp_parser *, bool *);
-static tree cp_parser_initializer_list
+static VEC(constructor_elt,gc) *cp_parser_initializer_list
(cp_parser *, bool *);
static bool cp_parser_ctor_initializer_opt_and_function_body
static void cp_parser_label_declaration
(cp_parser *);
+enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
+static bool cp_parser_pragma
+ (cp_parser *, enum pragma_context);
+
/* Objective-C++ Productions */
static tree cp_parser_objc_message_receiver
/* Utility Routines */
static tree cp_parser_lookup_name
- (cp_parser *, tree, enum tag_types, bool, bool, bool, bool *);
+ (cp_parser *, tree, enum tag_types, bool, bool, bool, tree *);
static tree cp_parser_lookup_name_simple
(cp_parser *, tree);
static tree cp_parser_maybe_treat_template_as_class
(cp_parser *, bool);
static void cp_parser_template_declaration_after_export
(cp_parser *, bool);
+static void cp_parser_perform_template_parameter_access_checks
+ (tree);
static tree cp_parser_single_declaration
- (cp_parser *, bool, bool *);
+ (cp_parser *, tree, bool, bool *);
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
static bool cp_parser_declares_only_class_p
(cp_parser *);
static void cp_parser_set_storage_class
- (cp_decl_specifier_seq *, cp_storage_class);
+ (cp_parser *, cp_decl_specifier_seq *, enum rid);
static void cp_parser_set_decl_spec_type
(cp_decl_specifier_seq *, tree, bool);
static bool cp_parser_friend_p
(cp_parser *);
static void cp_parser_skip_until_found
(cp_parser *, enum cpp_ttype, const char *);
+static void cp_parser_skip_to_pragma_eol
+ (cp_parser*, cp_token *);
static bool cp_parser_error_occurred
(cp_parser *);
static bool cp_parser_allow_gnu_extensions_p
cp_parser_warn_min_max (void)
{
if (warn_deprecated && !in_system_header)
- warning (0, "minimum/maximum operators are deprecated");
+ warning (OPT_Wdeprecated, "minimum/maximum operators are deprecated");
}
/* If not parsing tentatively, issue a diagnostic of the form
/* 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);
+ cp_parser_skip_to_pragma_eol (parser, token);
return;
}
+
c_parse_error (message,
/* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like
decl = cp_parser_lookup_name_simple (parser, id);
parser->scope = old_scope;
/* If the lookup found a template-name, it means that the user forgot
- to specify an argument list. Emit an useful error message. */
+ to specify an argument list. Emit a useful error message. */
if (TREE_CODE (decl) == TEMPLATE_DECL)
error ("invalid use of template-name %qE without an argument list",
decl);
- else if (!parser->scope || parser->scope == error_mark_node)
+ else if (!parser->scope)
{
/* Issue an error message. */
error ("%qE does not name a type", id);
}
/* Here we diagnose qualified-ids where the scope is actually correct,
but the identifier does not resolve to a valid type name. */
- else
+ else if (parser->scope != error_mark_node)
{
if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
error ("%qE in namespace %qE does not name a type",
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
/*template_p=*/NULL,
- /*declarator_p=*/true);
+ /*declarator_p=*/true,
+ /*optional_p=*/false);
/* After the id-expression, there should be a plain identifier,
otherwise this is not a simple variable declaration. Also, if
the scope is dependent, we cannot do much. */
{
unsigned paren_depth = 0;
unsigned brace_depth = 0;
- int result;
if (recovering && !or_comma
&& cp_parser_uncommitted_to_tentative_parse_p (parser))
while (true)
{
- cp_token *token;
+ cp_token * token = cp_lexer_peek_token (parser->lexer);
- /* If we've run out of tokens, then there is no closing `)'. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+ switch (token->type)
{
- result = 0;
- break;
- }
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ /* If we've run out of tokens, then there is no closing `)'. */
+ return 0;
- token = cp_lexer_peek_token (parser->lexer);
+ case CPP_SEMICOLON:
+ /* This matches the processing in skip_to_end_of_statement. */
+ if (!brace_depth)
+ return 0;
+ break;
- /* This matches the processing in skip_to_end_of_statement. */
- if (token->type == CPP_SEMICOLON && !brace_depth)
- {
- result = 0;
+ case CPP_OPEN_BRACE:
+ ++brace_depth;
break;
- }
- if (token->type == CPP_OPEN_BRACE)
- ++brace_depth;
- if (token->type == CPP_CLOSE_BRACE)
- {
+ case CPP_CLOSE_BRACE:
if (!brace_depth--)
- {
- result = 0;
- break;
- }
- }
- if (recovering && or_comma && token->type == CPP_COMMA
- && !brace_depth && !paren_depth)
- {
- result = -1;
+ return 0;
break;
- }
- if (!brace_depth)
- {
- /* If it is an `(', we have entered another level of nesting. */
- if (token->type == CPP_OPEN_PAREN)
+ case CPP_COMMA:
+ if (recovering && or_comma && !brace_depth && !paren_depth)
+ return -1;
+ break;
+
+ case CPP_OPEN_PAREN:
+ if (!brace_depth)
++paren_depth;
- /* If it is a `)', then we might be done. */
- else if (token->type == CPP_CLOSE_PAREN && !paren_depth--)
+ break;
+
+ case CPP_CLOSE_PAREN:
+ if (!brace_depth && !paren_depth--)
{
if (consume_paren)
cp_lexer_consume_token (parser->lexer);
- {
- result = 1;
- break;
- }
+ return 1;
}
+ break;
+
+ default:
+ break;
}
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
}
-
- return result;
}
/* Consume tokens until we reach the end of the current statement.
while (true)
{
- cp_token *token;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* If we've run out of tokens, stop. */
- if (token->type == CPP_EOF)
- break;
- /* If the next token is a `;', we have reached the end of the
- statement. */
- if (token->type == CPP_SEMICOLON && !nesting_depth)
- break;
- /* If the next token is a non-nested `}', then we have reached
- the end of the current block. */
- if (token->type == CPP_CLOSE_BRACE)
+ switch (token->type)
{
- /* If this is a non-nested `}', stop before consuming it.
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ /* If we've run out of tokens, stop. */
+ return;
+
+ case CPP_SEMICOLON:
+ /* If the next token is a `;', we have reached the end of the
+ statement. */
+ if (!nesting_depth)
+ return;
+ break;
+
+ case CPP_CLOSE_BRACE:
+ /* If this is a non-nested '}', stop before consuming it.
That way, when confronted with something like:
{ 3 + }
- we stop before consuming the closing `}', even though we
+ we stop before consuming the closing '}', even though we
have not yet reached a `;'. */
if (nesting_depth == 0)
- break;
- /* If it is the closing `}' for a block that we have
+ return;
+
+ /* If it is the closing '}' for a block that we have
scanned, stop -- but only after consuming the token.
That way given:
if (--nesting_depth == 0)
{
cp_lexer_consume_token (parser->lexer);
- break;
+ return;
}
+
+ case CPP_OPEN_BRACE:
+ ++nesting_depth;
+ break;
+
+ default:
+ break;
}
- /* If it the next token is a `{', then we are entering a new
- block. Consume the entire block. */
- else if (token->type == CPP_OPEN_BRACE)
- ++nesting_depth;
+
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
}
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
- if (token->type == CPP_EOF)
- break;
-
switch (token->type)
{
case CPP_EOF:
+ case CPP_PRAGMA_EOL:
/* If we've run out of tokens, stop. */
- nesting_depth = -1;
- continue;
+ return;
case CPP_SEMICOLON:
/* Stop if this is an unnested ';'. */
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
-
}
}
while (true)
{
- cp_token *token;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ switch (token->type)
+ {
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ /* If we've run out of tokens, stop. */
+ return;
+
+ case CPP_CLOSE_BRACE:
+ /* If the next token is a non-nested `}', then we have reached
+ the end of the current block. */
+ if (nesting_depth-- == 0)
+ return;
+ break;
+
+ case CPP_OPEN_BRACE:
+ /* If it the next token is a `{', then we are entering a new
+ block. Consume the entire block. */
+ ++nesting_depth;
+ break;
+
+ default:
+ break;
+ }
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* If we've run out of tokens, stop. */
- if (token->type == CPP_EOF)
- break;
- /* If the next token is a non-nested `}', then we have reached
- the end of the current block. */
- if (token->type == CPP_CLOSE_BRACE && nesting_depth-- == 0)
- break;
- /* If it the next token is a `{', then we are entering a new
- block. Consume the entire block. */
- else if (token->type == CPP_OPEN_BRACE)
- ++nesting_depth;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
}
}
+/* Consume tokens until we reach the end of the pragma. The PRAGMA_TOK
+ parameter is the PRAGMA token, allowing us to purge the entire pragma
+ sequence. */
+
+static void
+cp_parser_skip_to_pragma_eol (cp_parser* parser, cp_token *pragma_tok)
+{
+ cp_token *token;
+
+ parser->lexer->in_pragma = false;
+
+ do
+ token = cp_lexer_consume_token (parser->lexer);
+ while (token->type != CPP_PRAGMA_EOL && token->type != CPP_EOF);
+
+ /* Ensure that the pragma is not parsed again. */
+ cp_lexer_purge_tokens_after (parser->lexer, pragma_tok);
+}
+
+/* Require pragma end of line, resyncing with it as necessary. The
+ arguments are as for cp_parser_skip_to_pragma_eol. */
+
+static void
+cp_parser_require_pragma_eol (cp_parser *parser, cp_token *pragma_tok)
+{
+ parser->lexer->in_pragma = false;
+ if (!cp_parser_require (parser, CPP_PRAGMA_EOL, "end of line"))
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+}
+
/* This is a simple wrapper around make_typename_type. When the id is
an unresolved identifier node, we can provide a superior diagnostic
using cp_parser_diagnose_invalid_type_name. */
if (TREE_CODE (id) == IDENTIFIER_NODE)
{
result = make_typename_type (scope, id, typename_type,
- /*complain=*/0);
+ /*complain=*/tf_none);
if (result == error_mark_node)
cp_parser_diagnose_invalid_type_name (parser, scope, id);
return result;
parser->in_template_argument_list_p = false;
/* We are not in an iteration statement. */
- parser->in_iteration_statement_p = false;
+ parser->in_statement = 0;
/* We are not in a switch statement. */
parser->in_switch_statement_p = false;
declarator_obstack_base = obstack_next_free (&declarator_obstack);
}
- while (true)
+ cp_parser_declaration_seq_opt (parser);
+
+ /* If there are no tokens left then all went well. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+ {
+ /* 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 ();
+
+ success = true;
+ }
+ else
{
- cp_parser_declaration_seq_opt (parser);
-
- /* If there are no tokens left then all went well. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
- {
- /* 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 ();
-
- success = true;
- break;
- }
- else
- {
- cp_parser_error (parser, "expected declaration");
- success = false;
- break;
- }
+ cp_parser_error (parser, "expected declaration");
+ success = false;
}
-
+
/* Make sure the declarator obstack was fully cleaned up. */
gcc_assert (obstack_next_free (&declarator_obstack)
== declarator_obstack_base);
primary-expression:
( compound-statement )
__builtin_va_arg ( assignment-expression , type-id )
+ __builtin_offsetof ( type-id , offsetof-expression )
Objective-C++ Extension:
literal:
__null
- CAST_P is true if this primary expression is the target of a cast.
-
- Returns a representation of the expression.
+ ADDRESS_P is true iff this expression was immediately preceded by
+ "&" and therefore might denote a pointer-to-member. CAST_P is true
+ iff this expression is the target of a cast. TEMPLATE_ARG_P is
+ true iff this expression is a template argument.
- *IDK indicates what kind of id-expression (if any) was present.
-
- *QUALIFYING_CLASS is set to a non-NULL value if the id-expression can be
- used as the operand of a pointer-to-member. In that case,
- *QUALIFYING_CLASS gives the class that is used as the qualifying
- class in the pointer-to-member. */
+ Returns a representation of the expression. Upon return, *IDK
+ indicates what kind of id-expression (if any) was present. */
static tree
cp_parser_primary_expression (cp_parser *parser,
+ bool address_p,
bool cast_p,
- cp_id_kind *idk,
- tree *qualifying_class)
+ bool template_arg_p,
+ cp_id_kind *idk)
{
cp_token *token;
/* Assume the primary expression is not an id-expression. */
*idk = CP_ID_KIND_NONE;
- /* And that it cannot be used as pointer-to-member. */
- *qualifying_class = NULL_TREE;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* The end of the cast-expression. */
&& next_token->type != CPP_CLOSE_PAREN
/* The end of an array bound. */
- && next_token->type != CPP_CLOSE_SQUARE)
+ && next_token->type != CPP_CLOSE_SQUARE
+ /* The closing ">" in a template-argument-list. */
+ && (next_token->type != CPP_GREATER
+ || parser->greater_than_is_operator_p))
cast_p = false;
}
tree id_expression;
tree decl;
const char *error_msg;
+ bool template_p;
+ bool done;
id_expression:
/* Parse the id-expression. */
= cp_parser_id_expression (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
- /*template_p=*/NULL,
- /*declarator_p=*/false);
+ &template_p,
+ /*declarator_p=*/false,
+ /*optional_p=*/false);
if (id_expression == error_mark_node)
return error_mark_node;
+ token = cp_lexer_peek_token (parser->lexer);
+ done = (token->type != CPP_OPEN_SQUARE
+ && token->type != CPP_OPEN_PAREN
+ && token->type != CPP_DOT
+ && token->type != CPP_DEREF
+ && token->type != CPP_PLUS_PLUS
+ && token->type != CPP_MINUS_MINUS);
/* If we have a template-id, then no further lookup is
required. If the template-id was for a template-class, we
will sometimes have a TYPE_DECL at this point. */
- else if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
- || TREE_CODE (id_expression) == TYPE_DECL)
+ if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
+ || TREE_CODE (id_expression) == TYPE_DECL)
decl = id_expression;
/* Look up the name. */
else
{
- bool ambiguous_p;
+ tree ambiguous_decls;
decl = cp_parser_lookup_name (parser, id_expression,
none_type,
- /*is_template=*/false,
+ template_p,
/*is_namespace=*/false,
/*check_dependency=*/true,
- &ambiguous_p);
+ &ambiguous_decls);
/* If the lookup was ambiguous, an error will already have
been issued. */
- if (ambiguous_p)
+ if (ambiguous_decls)
return error_mark_node;
/* In Objective-C++, an instance variable (ivar) may be preferred
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. */
+ qualifying scope was dependent. */
if (TREE_CODE (decl) == SCOPE_REF)
- {
- if (TYPE_P (TREE_OPERAND (decl, 0)))
- *qualifying_class = TREE_OPERAND (decl, 0);
- return decl;
- }
+ return decl;
/* Check to see if DECL is a local variable in a context
where that is forbidden. */
if (parser->local_variables_forbidden_p
}
}
- decl = finish_id_expression (id_expression, decl, parser->scope,
- idk, qualifying_class,
- parser->integral_constant_expression_p,
- parser->allow_non_integral_constant_expression_p,
- &parser->non_integral_constant_expression_p,
- &error_msg);
+ decl = (finish_id_expression
+ (id_expression, decl, parser->scope,
+ idk,
+ parser->integral_constant_expression_p,
+ parser->allow_non_integral_constant_expression_p,
+ &parser->non_integral_constant_expression_p,
+ template_p, done, address_p,
+ template_arg_p,
+ &error_msg));
if (error_msg)
cp_parser_error (parser, error_msg);
return decl;
bool template_keyword_p,
bool check_dependency_p,
bool *template_p,
- bool declarator_p)
+ bool declarator_p,
+ bool optional_p)
{
bool global_scope_p;
bool nested_name_specifier_p;
/* Assume the `template' keyword was not used. */
if (template_p)
- *template_p = false;
+ *template_p = template_keyword_p;
/* Look for the optional `::' operator. */
global_scope_p
/* Process the final unqualified-id. */
unqualified_id = cp_parser_unqualified_id (parser, *template_p,
check_dependency_p,
- declarator_p);
+ declarator_p,
+ /*optional_p=*/false);
/* Restore the SAVED_SCOPE for our caller. */
parser->scope = saved_scope;
parser->object_scope = saved_object_scope;
else
return cp_parser_unqualified_id (parser, template_keyword_p,
/*check_dependency_p=*/true,
- declarator_p);
+ declarator_p,
+ optional_p);
}
/* Parse an unqualified-id.
cp_parser_unqualified_id (cp_parser* parser,
bool template_keyword_p,
bool check_dependency_p,
- bool declarator_p)
+ bool declarator_p,
+ bool optional_p)
{
cp_token *token;
else if (type_decl == error_mark_node)
return error_mark_node;
+ /* Check that destructor name and scope match. */
+ if (declarator_p && scope && !check_dtor_name (scope, type_decl))
+ {
+ if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
+ error ("declaration of %<~%T%> as member of %qT",
+ type_decl, scope);
+ return error_mark_node;
+ }
+
/* [class.dtor]
A typedef-name that names a class shall not be used as the
/* Fall through. */
default:
+ if (optional_p)
+ return NULL_TREE;
cp_parser_error (parser, "expected unqualified-id");
return error_mark_node;
}
bool is_declaration)
{
bool success = false;
- tree access_check = NULL_TREE;
cp_token_position start = 0;
cp_token *token;
/* Remember where the nested-name-specifier starts. */
if (cp_parser_uncommitted_to_tentative_parse_p (parser))
- start = cp_lexer_token_position (parser->lexer, false);
-
- push_deferring_access_checks (dk_deferred);
+ {
+ start = cp_lexer_token_position (parser->lexer, false);
+ push_deferring_access_checks (dk_deferred);
+ }
while (true)
{
token = cp_lexer_consume_token (parser->lexer);
if (!error_p)
{
- tree decl;
-
- decl = cp_parser_lookup_name_simple (parser, token->value);
- if (TREE_CODE (decl) == TEMPLATE_DECL)
- error ("%qD used without template parameters", decl);
- else
- cp_parser_name_lookup_error
- (parser, token->value, decl,
- "is not a class or namespace");
- parser->scope = NULL_TREE;
+ if (!token->ambiguous_p)
+ {
+ tree decl;
+ tree ambiguous_decls;
+
+ decl = cp_parser_lookup_name (parser, token->value,
+ none_type,
+ /*is_template=*/false,
+ /*is_namespace=*/false,
+ /*check_dependency=*/true,
+ &ambiguous_decls);
+ if (TREE_CODE (decl) == TEMPLATE_DECL)
+ error ("%qD used without template parameters", decl);
+ else if (ambiguous_decls)
+ {
+ error ("reference to %qD is ambiguous",
+ token->value);
+ print_candidates (ambiguous_decls);
+ decl = error_mark_node;
+ }
+ else
+ cp_parser_name_lookup_error
+ (parser, token->value, decl,
+ "is not a class or namespace");
+ }
+ parser->scope = error_mark_node;
error_p = true;
/* Treat this as a successful nested-name-specifier
due to:
}
break;
}
-
/* We've found one valid nested-name-specifier. */
success = true;
- /* Make sure we look in the right scope the next time through
- the loop. */
- parser->scope = (TREE_CODE (new_scope) == TYPE_DECL
- ? TREE_TYPE (new_scope)
- : new_scope);
+ /* Name lookup always gives us a DECL. */
+ if (TREE_CODE (new_scope) == TYPE_DECL)
+ new_scope = TREE_TYPE (new_scope);
+ /* Uses of "template" must be followed by actual templates. */
+ if (template_keyword_p
+ && !(CLASS_TYPE_P (new_scope)
+ && ((CLASSTYPE_USE_TEMPLATE (new_scope)
+ && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (new_scope)))
+ || CLASSTYPE_IS_TEMPLATE (new_scope)))
+ && !(TREE_CODE (new_scope) == TYPENAME_TYPE
+ && (TREE_CODE (TYPENAME_TYPE_FULLNAME (new_scope))
+ == TEMPLATE_ID_EXPR)))
+ pedwarn (TYPE_P (new_scope)
+ ? "%qT is not a template"
+ : "%qD is not a template",
+ new_scope);
/* If it is a class scope, try to complete it; we are about to
be looking up names inside the class. */
- if (TYPE_P (parser->scope)
+ if (TYPE_P (new_scope)
/* Since checking types for dependency can be expensive,
avoid doing it if the type is already complete. */
- && !COMPLETE_TYPE_P (parser->scope)
+ && !COMPLETE_TYPE_P (new_scope)
/* Do not try to complete dependent types. */
- && !dependent_type_p (parser->scope))
- complete_type (parser->scope);
+ && !dependent_type_p (new_scope))
+ new_scope = complete_type (new_scope);
+ /* Make sure we look in the right scope the next time through
+ the loop. */
+ parser->scope = new_scope;
}
- /* Retrieve any deferred checks. Do not pop this access checks yet
- so the memory will not be reclaimed during token replacing below. */
- access_check = get_deferred_access_checks ();
-
/* If parsing tentatively, replace the sequence of tokens that makes
up the nested-name-specifier with a CPP_NESTED_NAME_SPECIFIER
token. That way, should we re-parse the token stream, we will
we issue duplicate error messages. */
if (success && start)
{
- cp_token *token = cp_lexer_token_at (parser->lexer, start);
+ cp_token *token;
+ tree access_checks;
+ 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);
+ /* Retrieve any deferred checks. Do not pop this access checks yet
+ so the memory will not be reclaimed during token replacing below. */
+ access_checks = get_deferred_access_checks ();
+ token->value = build_tree_list (copy_list (access_checks),
+ parser->scope);
TREE_TYPE (token->value) = parser->qualifying_scope;
token->keyword = RID_MAX;
/* Purge all subsequent tokens. */
cp_lexer_purge_tokens_after (parser->lexer, start);
}
+
+ if (start)
+ pop_to_parent_deferring_access_checks ();
- pop_deferring_access_checks ();
return success ? parser->scope : NULL_TREE;
}
enum rid keyword;
cp_id_kind idk = CP_ID_KIND_NONE;
tree postfix_expression = NULL_TREE;
- /* Non-NULL only if the current postfix-expression can be used to
- form a pointer-to-member. In that case, QUALIFYING_CLASS is the
- class used to qualify the member. */
- tree qualifying_class = NULL_TREE;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
case RID_TYPENAME:
{
- 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. 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
- identifier. */
- cp_parser_parse_tentatively (parser);
- /* Try a template-id. */
- id = cp_parser_template_id (parser, template_p,
- /*check_dependency_p=*/true,
- /*is_declaration=*/true);
- /* If that didn't work, try an identifier. */
- if (!cp_parser_parse_definitely (parser))
- id = cp_parser_identifier (parser);
-
- /* Don't process id if nested name specifier is invalid. */
- if (!scope || 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. */
- 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);
-
+ /* The syntax permitted here is the same permitted for an
+ elaborated-type-specifier. */
+ type = cp_parser_elaborated_type_specifier (parser,
+ /*is_friend=*/false,
+ /*is_declaration=*/false);
postfix_expression = cp_parser_functional_cast (parser, type);
}
break;
if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
- tree initializer_list = NULL_TREE;
+ VEC(constructor_elt,gc) *initializer_list = NULL;
bool saved_in_type_id_in_expr_p;
cp_parser_parse_tentatively (parser);
}
/* It must be a primary-expression. */
- postfix_expression = cp_parser_primary_expression (parser,
- cast_p,
- &idk,
- &qualifying_class);
+ postfix_expression
+ = cp_parser_primary_expression (parser, address_p, cast_p,
+ /*template_arg_p=*/false,
+ &idk);
}
break;
}
- /* If we were avoiding committing to the processing of a
- qualified-id until we knew whether or not we had a
- pointer-to-member, we now know. */
- if (qualifying_class)
- {
- bool done;
-
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- done = (token->type != CPP_OPEN_SQUARE
- && token->type != CPP_OPEN_PAREN
- && token->type != CPP_DOT
- && token->type != CPP_DEREF
- && token->type != CPP_PLUS_PLUS
- && token->type != CPP_MINUS_MINUS);
-
- postfix_expression = finish_qualified_id_expr (qualifying_class,
- postfix_expression,
- done,
- address_p);
- if (done)
- return postfix_expression;
- }
-
/* Keep looping until the postfix-expression is complete. */
while (true)
{
= (build_new_method_call
(instance, fn, args, NULL_TREE,
(idk == CP_ID_KIND_QUALIFIED
- ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
+ ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL),
+ /*fn_p=*/NULL));
else
postfix_expression
= finish_call_expr (postfix_expression, args,
{
tree name;
bool dependent_p;
- bool template_p;
bool pseudo_destructor_p;
tree scope = NULL_TREE;
underlying type here. */
scope = non_reference (scope);
/* The type of the POSTFIX_EXPRESSION must be complete. */
- scope = complete_type_or_else (scope, NULL_TREE);
+ if (scope == unknown_type_node)
+ {
+ error ("%qE does not have class type", postfix_expression);
+ scope = NULL_TREE;
+ }
+ else
+ scope = complete_type_or_else (scope, NULL_TREE);
/* Let the name lookup machinery know that we are processing a
class member access expression. */
parser->context->object_type = scope;
/* If 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);
+ bool template_p;
/* Parse the id-expression. */
- name = cp_parser_id_expression (parser, template_p,
- /*check_dependency_p=*/true,
- /*template_p=*/NULL,
- /*declarator_p=*/false);
+ name = (cp_parser_id_expression
+ (parser,
+ cp_parser_optional_template_keyword (parser),
+ /*check_dependency_p=*/true,
+ &template_p,
+ /*declarator_p=*/false,
+ /*optional_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;
{
if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
{
- name = build_nt (SCOPE_REF, parser->scope, name);
+ name = build_qualified_name (/*type=*/NULL_TREE,
+ parser->scope,
+ name,
+ template_p);
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
adjust_result_of_qualified_name_lookup
(name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
postfix_expression
- = finish_class_member_access_expr (postfix_expression, name);
+ = finish_class_member_access_expr (postfix_expression, name,
+ template_p);
}
}
&& !in_system_header
&& !VOID_TYPE_P (type)
&& current_lang_name != lang_name_c)
- warning (0, "use of old-style cast");
+ warning (OPT_Wold_style_cast, "use of old-style cast");
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
iteration-statement
jump-statement
declaration-statement
- try-block */
+ try-block
+
+ IN_COMPOUND is true when the statement is nested inside a
+ cp_parser_compound_statement; this matters for certain pragmas. */
static void
-cp_parser_statement (cp_parser* parser, tree in_statement_expr)
+cp_parser_statement (cp_parser* parser, tree in_statement_expr,
+ bool in_compound)
{
tree statement;
cp_token *token;
location_t statement_location;
+ restart:
/* There is no statement yet. */
statement = NULL_TREE;
/* Peek at the next token. */
{
case RID_CASE:
case RID_DEFAULT:
- statement = cp_parser_labeled_statement (parser,
- in_statement_expr);
+ statement = cp_parser_labeled_statement (parser, in_statement_expr,
+ in_compound);
break;
case RID_IF:
labeled-statement. */
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_COLON)
- statement = cp_parser_labeled_statement (parser, in_statement_expr);
+ statement = cp_parser_labeled_statement (parser, in_statement_expr,
+ in_compound);
}
/* Anything that starts with a `{' must be a compound-statement. */
else if (token->type == CPP_OPEN_BRACE)
a statement all its own. */
else if (token->type == CPP_PRAGMA)
{
- cp_lexer_handle_pragma (parser->lexer);
+ /* Only certain OpenMP pragmas are attached to statements, and thus
+ are considered statements themselves. All others are not. In
+ the context of a compound, accept the pragma as a "statement" and
+ return so that we can check for a close brace. Otherwise we
+ require a real statement and must go back and read one. */
+ if (in_compound)
+ cp_parser_pragma (parser, pragma_compound);
+ else if (!cp_parser_pragma (parser, pragma_stmt))
+ goto restart;
+ return;
+ }
+ else if (token->type == CPP_EOF)
+ {
+ cp_parser_error (parser, "expected statement");
return;
}
case constant-expression ... constant-expression : statement
Returns the new CASE_LABEL_EXPR, for a `case' or `default' label.
- For an ordinary label, returns a LABEL_EXPR. */
+ For an ordinary label, returns a LABEL_EXPR.
+
+ IN_COMPOUND is as for cp_parser_statement: true when we're nested
+ inside a compound. */
static tree
-cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr)
+cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr,
+ bool in_compound)
{
cp_token *token;
tree statement = error_mark_node;
else
expr_hi = NULL_TREE;
- if (!parser->in_switch_statement_p)
- error ("case label %qE not within a switch statement", expr);
- else
+ if (parser->in_switch_statement_p)
statement = finish_case_label (expr, expr_hi);
+ else
+ error ("case label %qE not within a switch statement", expr);
}
break;
case RID_DEFAULT:
/* Consume the `default' token. */
cp_lexer_consume_token (parser->lexer);
- if (!parser->in_switch_statement_p)
- error ("case label not within a switch statement");
- else
- statement = finish_case_label (NULL_TREE, NULL_TREE);
- break;
+
+ if (parser->in_switch_statement_p)
+ statement = finish_case_label (NULL_TREE, NULL_TREE);
+ else
+ error ("case label not within a switch statement");
+ break;
default:
/* Anything else must be an ordinary label. */
/* Require the `:' token. */
cp_parser_require (parser, CPP_COLON, "`:'");
/* Parse the labeled statement. */
- cp_parser_statement (parser, in_statement_expr);
+ cp_parser_statement (parser, in_statement_expr, in_compound);
/* Return the label, in the case of a `case' or `default' label. */
return statement;
/* Scan statements until there aren't any more. */
while (true)
{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
/* If we're looking at a `}', then we've run out of statements. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)
- || cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+ if (token->type == CPP_CLOSE_BRACE
+ || token->type == CPP_EOF
+ || token->type == CPP_PRAGMA_EOL)
break;
/* Parse the statement. */
- cp_parser_statement (parser, in_statement_expr);
+ cp_parser_statement (parser, in_statement_expr, true);
}
}
else
{
bool in_switch_statement_p;
+ unsigned char in_statement;
/* Add the condition. */
finish_switch_cond (condition, statement);
/* Parse the body of the switch-statement. */
in_switch_statement_p = parser->in_switch_statement_p;
+ in_statement = parser->in_statement;
parser->in_switch_statement_p = true;
+ parser->in_statement |= IN_SWITCH_STMT;
cp_parser_implicitly_scoped_statement (parser);
parser->in_switch_statement_p = in_switch_statement_p;
+ parser->in_statement = in_statement;
/* Now we're all done with the switch-statement. */
finish_switch_stmt (statement);
if (cp_parser_parse_definitely (parser))
{
tree pushed_scope;
+ bool non_constant_p;
/* Create the declaration. */
decl = start_decl (declarator, &type_specifiers,
attributes, /*prefix_attributes=*/NULL_TREE,
&pushed_scope);
/* Parse the assignment-expression. */
- initializer = cp_parser_assignment_expression (parser,
- /*cast_p=*/false);
+ initializer
+ = cp_parser_constant_expression (parser,
+ /*allow_non_constant_p=*/true,
+ &non_constant_p);
+ if (!non_constant_p)
+ initializer = fold_non_dependent_expr (initializer);
/* Process the initializer. */
cp_finish_decl (decl,
- initializer,
+ initializer, !non_constant_p,
asm_specification,
LOOKUP_ONLYCONVERTING);
cp_token *token;
enum rid keyword;
tree statement;
- bool in_iteration_statement_p;
-
+ unsigned char in_statement;
/* Peek at the next token. */
token = cp_parser_require (parser, CPP_KEYWORD, "iteration-statement");
/* Remember whether or not we are already within an iteration
statement. */
- in_iteration_statement_p = parser->in_iteration_statement_p;
+ in_statement = parser->in_statement;
/* See what kind of keyword it is. */
keyword = token->keyword;
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Parse the dependent statement. */
- parser->in_iteration_statement_p = true;
+ parser->in_statement = IN_ITERATION_STMT;
cp_parser_already_scoped_statement (parser);
- parser->in_iteration_statement_p = in_iteration_statement_p;
+ parser->in_statement = in_statement;
/* We're done with the while-statement. */
finish_while_stmt (statement);
}
/* Begin the do-statement. */
statement = begin_do_stmt ();
/* Parse the body of the do-statement. */
- parser->in_iteration_statement_p = true;
+ parser->in_statement = IN_ITERATION_STMT;
cp_parser_implicitly_scoped_statement (parser);
- parser->in_iteration_statement_p = in_iteration_statement_p;
+ parser->in_statement = in_statement;
finish_do_body (statement);
/* Look for the `while' keyword. */
cp_parser_require_keyword (parser, RID_WHILE, "`while'");
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Parse the body of the for-statement. */
- parser->in_iteration_statement_p = true;
+ parser->in_statement = IN_ITERATION_STMT;
cp_parser_already_scoped_statement (parser);
- parser->in_iteration_statement_p = in_iteration_statement_p;
+ parser->in_statement = in_statement;
/* We're done with the for-statement. */
finish_for_stmt (statement);
switch (keyword)
{
case RID_BREAK:
- if (!parser->in_switch_statement_p
- && !parser->in_iteration_statement_p)
+ switch (parser->in_statement)
{
+ case 0:
error ("break statement not within loop or switch");
- statement = error_mark_node;
+ break;
+ default:
+ gcc_assert ((parser->in_statement & IN_SWITCH_STMT)
+ || parser->in_statement == IN_ITERATION_STMT);
+ statement = finish_break_stmt ();
+ break;
+ case IN_OMP_BLOCK:
+ error ("invalid exit from OpenMP structured block");
+ break;
+ case IN_OMP_FOR:
+ error ("break statement used with OpenMP for loop");
+ break;
}
- else
- statement = finish_break_stmt ();
cp_parser_require (parser, CPP_SEMICOLON, "%<;%>");
break;
case RID_CONTINUE:
- if (!parser->in_iteration_statement_p)
+ switch (parser->in_statement & ~IN_SWITCH_STMT)
{
+ case 0:
error ("continue statement not within a loop");
- statement = error_mark_node;
+ break;
+ case IN_ITERATION_STMT:
+ case IN_OMP_FOR:
+ statement = finish_continue_stmt ();
+ break;
+ case IN_OMP_BLOCK:
+ error ("invalid exit from OpenMP structured block");
+ break;
+ default:
+ gcc_unreachable ();
}
- else
- statement = finish_continue_stmt ();
cp_parser_require (parser, CPP_SEMICOLON, "%<;%>");
break;
{
tree statement;
+ /* Mark if () ; with a special NOP_EXPR. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ statement = add_stmt (build_empty_stmt ());
+ }
+ /* if a compound is opened, we simply parse the statement directly. */
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ statement = cp_parser_compound_statement (parser, NULL, false);
/* If the token is not a `{', then we must take special action. */
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
+ else
{
/* Create a compound-statement. */
statement = begin_compound_stmt (0);
/* Parse the dependent-statement. */
- cp_parser_statement (parser, false);
+ cp_parser_statement (parser, NULL_TREE, false);
/* Finish the dummy compound-statement. */
finish_compound_stmt (statement);
}
- /* Otherwise, we simply parse the statement directly. */
- else
- statement = cp_parser_compound_statement (parser, NULL, false);
/* Return the statement. */
return statement;
{
/* If the token is a `{', then we must take special action. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
- cp_parser_statement (parser, false);
+ cp_parser_statement (parser, NULL_TREE, false);
else
{
/* Avoid calling cp_parser_compound_statement, so that we
don't create a new scope. Do everything else by hand. */
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
- cp_parser_statement_seq_opt (parser, false);
+ cp_parser_statement_seq_opt (parser, NULL_TREE);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
}
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_CLOSE_BRACE
- || token->type == CPP_EOF)
+ || token->type == CPP_EOF
+ || token->type == CPP_PRAGMA_EOL)
break;
if (token->type == CPP_SEMICOLON)
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);
+ cp_parser_pragma (parser, pragma_external);
continue;
}
if (token1.type != CPP_EOF)
token2 = *cp_lexer_peek_nth_token (parser->lexer, 2);
+ else
+ {
+ token2.type = CPP_EOF;
+ token2.keyword = RID_MAX;
+ }
/* Get the high-water mark for the DECLARATOR_OBSTACK. */
p = obstack_alloc (&declarator_obstack, 0);
&& (/* A named namespace definition. */
(token2.type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 3)->type
- == CPP_OPEN_BRACE))
+ != CPP_EQ))
/* An unnamed namespace definition. */
- || token2.type == CPP_OPEN_BRACE))
+ || token2.type == CPP_OPEN_BRACE
+ || token2.keyword == RID_ATTRIBUTE))
cp_parser_namespace_definition (parser);
/* Objective-C++ declaration/definition. */
else if (c_dialect_objc () && OBJC_IS_AT_KEYWORD (token1.keyword))
bool function_definition_p;
tree decl;
- saw_declarator = true;
+ if (saw_declarator)
+ {
+ /* If we are processing next declarator, coma is expected */
+ token = cp_lexer_peek_token (parser->lexer);
+ gcc_assert (token->type == CPP_COMMA);
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ saw_declarator = true;
+
/* Parse the init-declarator. */
decl = cp_parser_init_declarator (parser, &decl_specifiers,
+ /*checks=*/NULL_TREE,
function_definition_allowed_p,
/*member_p=*/false,
declares_class_or_enum,
token = cp_lexer_peek_token (parser->lexer);
/* If it's a `,', there are more declarators to come. */
if (token->type == CPP_COMMA)
- cp_lexer_consume_token (parser->lexer);
+ /* will be consumed next time around */;
/* If it's a `;', we are done. */
else if (token->type == CPP_SEMICOLON)
break;
int* declares_class_or_enum)
{
bool constructor_possible_p = !parser->in_declarator_p;
+ cp_decl_spec ds;
/* Clear DECL_SPECS. */
clear_decl_specs (decl_specs);
/* decl-specifier:
friend */
case RID_FRIEND:
- if (decl_specs->specs[(int) ds_friend]++)
- error ("duplicate %<friend%>");
+ ++decl_specs->specs[(int) ds_friend];
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
break;
GNU Extension:
thread */
case RID_AUTO:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- cp_parser_set_storage_class (decl_specs, sc_auto);
- break;
case RID_REGISTER:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- cp_parser_set_storage_class (decl_specs, sc_register);
- break;
case RID_STATIC:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- if (decl_specs->specs[(int) ds_thread])
- {
- error ("%<__thread%> before %<static%>");
- decl_specs->specs[(int) ds_thread] = 0;
- }
- cp_parser_set_storage_class (decl_specs, sc_static);
- break;
case RID_EXTERN:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- if (decl_specs->specs[(int) ds_thread])
- {
- error ("%<__thread%> before %<extern%>");
- decl_specs->specs[(int) ds_thread] = 0;
- }
- cp_parser_set_storage_class (decl_specs, sc_extern);
- break;
case RID_MUTABLE:
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
- cp_parser_set_storage_class (decl_specs, sc_mutable);
+ cp_parser_set_storage_class (parser, decl_specs, token->keyword);
break;
case RID_THREAD:
/* Consume the token. */
flags |= CP_PARSER_FLAGS_OPTIONAL;
}
+ /* Check for repeated decl-specifiers. */
+ for (ds = ds_first; ds != ds_last; ++ds)
+ {
+ unsigned count = decl_specs->specs[(int)ds];
+ if (count < 2)
+ continue;
+ /* The "long" specifier is a special case because of "long long". */
+ if (ds == ds_long)
+ {
+ if (count > 2)
+ error ("%<long long long%> is too long for GCC");
+ else if (pedantic && !in_system_header && warn_long_long)
+ pedwarn ("ISO C++ does not support %<long long%>");
+ }
+ else if (count > 1)
+ {
+ static const char *const decl_spec_names[] = {
+ "signed",
+ "unsigned",
+ "short",
+ "long",
+ "const",
+ "volatile",
+ "restrict",
+ "inline",
+ "virtual",
+ "explicit",
+ "friend",
+ "typedef",
+ "__complex",
+ "__thread"
+ };
+ error ("duplicate %qs", decl_spec_names[(int)ds]);
+ }
+ }
+
/* Don't allow a friend specifier with a class definition. */
if (decl_specs->specs[(int) ds_friend] != 0
&& (*declares_class_or_enum & 2))
break;
case RID_VIRTUAL:
- if (decl_specs)
+ /* 14.5.2.3 [temp.mem]
+
+ A member function template shall not be virtual. */
+ if (PROCESSING_REAL_TEMPLATE_DECL_P ())
+ error ("templates may not be %<virtual%>");
+ else if (decl_specs)
++decl_specs->specs[(int) ds_virtual];
break;
/* Parse the mem-initializer. */
mem_initializer = cp_parser_mem_initializer (parser);
/* Add it to the list, unless it was erroneous. */
- if (mem_initializer)
+ if (mem_initializer != error_mark_node)
{
TREE_CHAIN (mem_initializer) = mem_initializer_list;
mem_initializer_list = mem_initializer;
Returns a TREE_LIST. The TREE_PURPOSE is the TYPE (for a base
class) or FIELD_DECL (for a non-static data member) to initialize;
- the TREE_VALUE is the expression-list. */
+ the TREE_VALUE is the expression-list. An empty initialization
+ list is represented by void_list_node. */
static tree
cp_parser_mem_initializer (cp_parser* parser)
= cp_parser_parenthesized_expression_list (parser, false,
/*cast_p=*/false,
/*non_constant_p=*/NULL);
+ if (expression_list == error_mark_node)
+ return error_mark_node;
if (!expression_list)
expression_list = void_type_node;
in_base_initializer = 0;
- return member ? build_tree_list (member, expression_list) : NULL_TREE;
+ return member ? build_tree_list (member, expression_list) : error_mark_node;
}
/* Parse a mem-initializer-id.
{
tree parameter_list = NULL_TREE;
+ begin_template_parm_list ();
while (true)
{
tree parameter;
cp_lexer_consume_token (parser->lexer);
}
- return parameter_list;
+ return end_template_parm_list (parameter_list);
}
/* Parse a template-parameter.
/* Consume the `=' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the default-argument. */
+ push_deferring_access_checks (dk_no_deferred);
default_argument = cp_parser_type_id (parser);
+ pop_deferring_access_checks ();
}
else
default_argument = NULL_TREE;
/* Look for the `<'. */
cp_parser_require (parser, CPP_LESS, "`<'");
/* Parse the template-parameter-list. */
- begin_template_parm_list ();
- parameter_list
- = cp_parser_template_parameter_list (parser);
- parameter_list = end_template_parm_list (parameter_list);
+ parameter_list = cp_parser_template_parameter_list (parser);
/* Look for the `>'. */
cp_parser_require (parser, CPP_GREATER, "`>'");
/* Look for the `class' keyword. */
/* Consume the `='. */
cp_lexer_consume_token (parser->lexer);
/* Parse the id-expression. */
+ push_deferring_access_checks (dk_no_deferred);
default_argument
= cp_parser_id_expression (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
/*template_p=*/&is_template,
- /*declarator_p=*/false);
+ /*declarator_p=*/false,
+ /*optional_p=*/false);
if (TREE_CODE (default_argument) == TYPE_DECL)
/* If the id-expression was a template-id that refers to
a template-class, we already have the declaration here,
/*is_template=*/is_template,
/*is_namespace=*/false,
/*check_dependency=*/true,
- /*ambiguous_p=*/NULL);
+ /*ambiguous_decls=*/NULL);
/* See if the default argument is valid. */
default_argument
= check_template_template_default_arg (default_argument);
+ pop_deferring_access_checks ();
}
else
default_argument = NULL_TREE;
/*is_template=*/false,
/*is_namespace=*/false,
check_dependency_p,
- /*ambiguous_p=*/NULL);
+ /*ambiguous_decls=*/NULL);
decl = maybe_get_template_decl_from_type_decl (decl);
/* If DECL is a template, then the name was a template-name. */
tree *arg_ary = fixed_args;
tree vec;
bool saved_in_template_argument_list_p;
+ bool saved_ice_p;
+ bool saved_non_ice_p;
saved_in_template_argument_list_p = parser->in_template_argument_list_p;
parser->in_template_argument_list_p = true;
+ /* Even if the template-id appears in an integral
+ constant-expression, the contents of the argument list do
+ not. */
+ saved_ice_p = parser->integral_constant_expression_p;
+ parser->integral_constant_expression_p = false;
+ saved_non_ice_p = parser->non_integral_constant_expression_p;
+ parser->non_integral_constant_expression_p = false;
+ /* Parse the arguments. */
do
{
tree argument;
if (arg_ary == fixed_args)
{
- arg_ary = xmalloc (sizeof (tree) * alloced);
+ arg_ary = XNEWVEC (tree, alloced);
memcpy (arg_ary, fixed_args, sizeof (tree) * n_args);
}
else
- arg_ary = xrealloc (arg_ary, sizeof (tree) * alloced);
+ arg_ary = XRESIZEVEC (tree, arg_ary, alloced);
}
arg_ary[n_args++] = argument;
}
if (arg_ary != fixed_args)
free (arg_ary);
+ parser->non_integral_constant_expression_p = saved_non_ice_p;
+ parser->integral_constant_expression_p = saved_ice_p;
parser->in_template_argument_list_p = saved_in_template_argument_list_p;
return vec;
}
bool maybe_type_id = false;
cp_token *token;
cp_id_kind idk;
- tree qualifying_class;
/* There's really no way to know what we're looking at, so we just
try each alternative in order.
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
&template_p,
- /*declarator_p=*/false);
+ /*declarator_p=*/false,
+ /*optional_p=*/false);
/* If the next token isn't a `,' or a `>', then this argument wasn't
really finished. */
if (!cp_parser_next_token_ends_template_argument_p (parser))
/*is_template=*/template_p,
/*is_namespace=*/false,
/*check_dependency=*/true,
- /*ambiguous_p=*/NULL);
+ /*ambiguous_decls=*/NULL);
if (TREE_CODE (argument) != TEMPLATE_DECL
&& TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
cp_parser_error (parser, "expected template-name");
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
+ /*adress_p=*/false,
/*cast_p=*/false,
- &idk,
- &qualifying_class);
+ /*template_arg_p=*/true,
+ &idk);
if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
|| !cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_simulate_error (parser);
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
+ address_p,
/*cast_p=*/false,
- &idk,
- &qualifying_class);
+ /*template_arg_p=*/true,
+ &idk);
if (cp_parser_error_occurred (parser)
|| !cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_abort_tentative_parse (parser);
argument = TREE_OPERAND (argument, 0);
}
- if (qualifying_class)
- argument = finish_qualified_id_expr (qualifying_class,
- argument,
- /*done=*/true,
- address_p);
+ if (TREE_CODE (argument) == BASELINK)
+ /* We don't need the information about what class was used
+ to name the overloaded functions. */
+ argument = BASELINK_FUNCTIONS (argument);
+
if (TREE_CODE (argument) == VAR_DECL)
{
/* A variable without external linkage might still be a
template instantiation. */
pop_deferring_access_checks ();
if (type)
- do_type_instantiation (type, extension_specifier, /*complain=*/1);
+ do_type_instantiation (type, extension_specifier,
+ /*complain=*/tf_error);
}
else
{
static void
cp_parser_explicit_specialization (cp_parser* parser)
{
+ bool need_lang_pop;
/* Look for the `template' keyword. */
cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'");
/* Look for the `<'. */
cp_parser_require (parser, CPP_GREATER, "`>'");
/* We have processed another parameter list. */
++parser->num_template_parameter_lists;
+ /* [temp]
+
+ A template ... explicit specialization ... shall not have C
+ linkage. */
+ if (current_lang_name == lang_name_c)
+ {
+ error ("template specialization with C linkage");
+ /* Give it C++ linkage to avoid confusing other parts of the
+ front end. */
+ push_lang_context (lang_name_cplusplus);
+ need_lang_pop = true;
+ }
+ else
+ need_lang_pop = false;
/* Let the front end know that we are beginning a specialization. */
begin_specialization ();
-
/* If the next keyword is `template', we need to figure out whether
or not we're looking a template-declaration. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
else
/* Parse the dependent declaration. */
cp_parser_single_declaration (parser,
+ /*checks=*/NULL_TREE,
/*member_p=*/false,
/*friend_p=*/NULL);
-
/* We're done with the specialization. */
end_specialization ();
+ /* For the erroneous case of a template with C linkage, we pushed an
+ implicit C++ linkage scope; exit that scope now. */
+ if (need_lang_pop)
+ pop_lang_context ();
/* We're done with this parameter list. */
--parser->num_template_parameter_lists;
}
&& tag_type == typename_type)
type = make_typename_type (parser->scope, decl,
typename_type,
- /*complain=*/1);
+ /*complain=*/tf_error);
else
type = TREE_TYPE (decl);
}
/*is_template=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true,
- /*ambiguous_p=*/NULL);
+ /*ambiguous_decls=*/NULL);
/* If we are parsing friend declaration, DECL may be a
TEMPLATE_DECL tree node here. However, we need to check
declaration context. */
tag_scope ts;
+ bool template_p;
+
if (is_friend)
/* Friends have special name lookup rules. */
ts = ts_within_enclosing_non_class;
warning (OPT_Wattributes,
"type attributes are honored only at type definition");
- type = xref_tag (tag_type, identifier, ts,
- parser->num_template_parameter_lists);
+ template_p =
+ (parser->num_template_parameter_lists
+ && (cp_parser_next_token_starts_class_definition_p (parser)
+ || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)));
+ /* An unqualified name was used to reference this type, so
+ there were no qualifying templates. */
+ if (!cp_parser_check_template_parameters (parser,
+ /*num_templates=*/0))
+ return error_mark_node;
+ type = xref_tag (tag_type, identifier, ts, template_p);
}
}
if (tag_type != enum_type)
/*is_template=*/false,
/*is_namespace=*/true,
/*check_dependency=*/true,
- /*ambiguous_p=*/NULL);
+ /*ambiguous_decls=*/NULL);
/* If it's not a namespace, issue an error. */
if (namespace_decl == error_mark_node
|| TREE_CODE (namespace_decl) != NAMESPACE_DECL)
{
+ if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
+ error ("%qD is not a namespace-name", identifier);
cp_parser_error (parser, "expected namespace-name");
namespace_decl = error_mark_node;
}
static void
cp_parser_namespace_definition (cp_parser* parser)
{
- tree identifier;
+ tree identifier, attribs;
/* Look for the `namespace' keyword. */
cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
else
identifier = NULL_TREE;
+ /* Parse any specified attributes. */
+ attribs = cp_parser_attributes_opt (parser);
+
/* Look for the `{' to start the namespace. */
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
/* Start the namespace. */
- push_namespace (identifier);
+ push_namespace_with_attribs (identifier, attribs);
/* Parse the body of the namespace. */
cp_parser_namespace_body (parser);
/* Finish the namespace. */
identifier = cp_parser_unqualified_id (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
- /*declarator_p=*/true);
+ /*declarator_p=*/true,
+ /*optional_p=*/false);
/* The function we call to handle a using-declaration is different
depending on what scope we are in. */
- if (identifier == error_mark_node)
+ if (qscope == error_mark_node || identifier == error_mark_node)
;
else if (TREE_CODE (identifier) != IDENTIFIER_NODE
&& TREE_CODE (identifier) != BIT_NOT_EXPR)
}
}
else
- assemble_asm (string);
+ cgraph_add_asm_node (string);
}
/* Declarators [gram.dcl.decl] */
function-definition:
__extension__ function-definition
- The DECL_SPECIFIERS and PREFIX_ATTRIBUTES apply to this declarator.
- Returns a representation of the entity declared. If MEMBER_P is TRUE,
- then this declarator appears in a class scope. The new DECL created
- by this declarator is returned.
+ The DECL_SPECIFIERS apply to this declarator. Returns a
+ representation of the entity declared. If MEMBER_P is TRUE, then
+ this declarator appears in a class scope. The new DECL created by
+ this declarator is returned.
+
+ The CHECKS are access checks that should be performed once we know
+ what entity is being declared (and, therefore, what classes have
+ befriended it).
If FUNCTION_DEFINITION_ALLOWED_P then we handle the declarator and
for a function-definition here as well. If the declarator is a
static tree
cp_parser_init_declarator (cp_parser* parser,
cp_decl_specifier_seq *decl_specifiers,
+ tree checks,
bool function_definition_allowed_p,
bool member_p,
int declares_class_or_enum,
tree decl = NULL_TREE;
tree scope;
bool is_initialized;
- bool is_parenthesized_init;
+ /* Only valid if IS_INITIALIZED is true. In that case, CPP_EQ if
+ initialized with "= ..", CPP_OPEN_PAREN if initialized with
+ "(...)". */
+ enum cpp_ttype initialization_kind;
+ bool is_parenthesized_init = false;
bool is_non_constant_init;
int ctor_dtor_or_conv_p;
bool friend_p;
}
/* An `=' or an `(' indicates an initializer. */
- is_initialized = (token->type == CPP_EQ
- || token->type == CPP_OPEN_PAREN);
- /* If the init-declarator isn't initialized and isn't followed by a
- `,' or `;', it's not a valid init-declarator. */
- if (!is_initialized
- && token->type != CPP_COMMA
- && token->type != CPP_SEMICOLON)
+ if (token->type == CPP_EQ
+ || token->type == CPP_OPEN_PAREN)
{
- cp_parser_error (parser, "expected initializer");
- return error_mark_node;
+ is_initialized = true;
+ initialization_kind = token->type;
+ }
+ else
+ {
+ /* If the init-declarator isn't initialized and isn't followed by a
+ `,' or `;', it's not a valid init-declarator. */
+ if (token->type != CPP_COMMA
+ && token->type != CPP_SEMICOLON)
+ {
+ cp_parser_error (parser, "expected initializer");
+ return error_mark_node;
+ }
+ is_initialized = false;
+ initialization_kind = CPP_EOF;
}
/* Because start_decl has side-effects, we should only call it if we
current_function_decl = decl;
}
+ /* Perform access checks for template parameters. */
+ cp_parser_perform_template_parameter_access_checks (checks);
+
/* Perform the access control checks for the declarator and the
the decl-specifiers. */
perform_deferred_access_checks ();
}
/* Parse the initializer. */
+ initializer = NULL_TREE;
+ is_parenthesized_init = false;
+ is_non_constant_init = true;
if (is_initialized)
- initializer = cp_parser_initializer (parser,
- &is_parenthesized_init,
- &is_non_constant_init);
- else
{
- initializer = NULL_TREE;
- is_parenthesized_init = false;
- is_non_constant_init = true;
+ if (declarator->kind == cdk_function
+ && declarator->declarator->kind == cdk_id
+ && initialization_kind == CPP_EQ)
+ initializer = cp_parser_pure_specifier (parser);
+ else
+ initializer = cp_parser_initializer (parser,
+ &is_parenthesized_init,
+ &is_non_constant_init);
}
/* The old parser allows attributes to appear after a parenthesized
pushed_scope = false;
}
decl = grokfield (declarator, decl_specifiers,
- initializer, /*asmspec=*/NULL_TREE,
- /*attributes=*/NULL_TREE);
+ initializer, !is_non_constant_init,
+ /*asmspec=*/NULL_TREE,
+ prefix_attributes);
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
}
if (!friend_p && decl && decl != error_mark_node)
{
cp_finish_decl (decl,
- initializer,
+ initializer, !is_non_constant_init,
asm_specification,
/* If the initializer is in parentheses, then this is
a direct-initialization, which means that an
if (!friend_p && pushed_scope)
pop_scope (pushed_scope);
- /* Remember whether or not variables were initialized by
- constant-expressions. */
- if (decl && TREE_CODE (decl) == VAR_DECL
- && is_initialized && !is_non_constant_init)
- DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
-
return decl;
}
{
tree qualifying_scope;
tree unqualified_name;
+ special_function_kind sfk;
+ bool abstract_ok;
/* Parse a declarator-id */
- if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
+ abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
+ if (abstract_ok)
cp_parser_parse_tentatively (parser);
- unqualified_name = cp_parser_declarator_id (parser);
+ unqualified_name
+ = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
qualifying_scope = parser->scope;
- if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
+ if (abstract_ok)
{
if (!cp_parser_parse_definitely (parser))
unqualified_name = error_mark_node;
- else if (qualifying_scope
- || (TREE_CODE (unqualified_name)
- != IDENTIFIER_NODE))
+ else if (unqualified_name
+ && (qualifying_scope
+ || (TREE_CODE (unqualified_name)
+ != IDENTIFIER_NODE)))
{
cp_parser_error (parser, "expected unqualified-id");
unqualified_name = error_mark_node;
}
}
+ if (!unqualified_name)
+ return NULL;
if (unqualified_name == error_mark_node)
{
declarator = cp_error_declarator;
qualifying_scope = type;
}
- declarator = make_id_declarator (qualifying_scope,
- unqualified_name);
- declarator->id_loc = token->location;
+ sfk = sfk_none;
if (unqualified_name)
{
tree class_type;
else
class_type = current_class_type;
+ if (TREE_CODE (unqualified_name) == TYPE_DECL)
+ {
+ tree name_type = TREE_TYPE (unqualified_name);
+ if (class_type && same_type_p (name_type, class_type))
+ {
+ if (qualifying_scope
+ && CLASSTYPE_USE_TEMPLATE (name_type))
+ {
+ error ("invalid use of constructor as a template");
+ inform ("use %<%T::%D%> instead of %<%T::%D%> to "
+ "name the constructor in a qualified name",
+ class_type,
+ DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
+ class_type, name_type);
+ declarator = cp_error_declarator;
+ break;
+ }
+ else
+ unqualified_name = constructor_name (class_type);
+ }
+ else
+ {
+ /* We do not attempt to print the declarator
+ here because we do not have enough
+ information about its original syntactic
+ form. */
+ cp_parser_error (parser, "invalid declarator");
+ declarator = cp_error_declarator;
+ break;
+ }
+ }
+
if (class_type)
{
if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR)
- declarator->u.id.sfk = sfk_destructor;
+ sfk = sfk_destructor;
else if (IDENTIFIER_TYPENAME_P (unqualified_name))
- declarator->u.id.sfk = sfk_conversion;
+ sfk = sfk_conversion;
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 (qualifying_scope
- && TREE_CODE (unqualified_name) == TYPE_DECL
- && CLASSTYPE_USE_TEMPLATE (TREE_TYPE (unqualified_name)))
+ && constructor_name_p (unqualified_name,
+ class_type))
{
- 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,
- DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
- class_type, class_type);
+ unqualified_name = constructor_name (class_type);
+ sfk = sfk_constructor;
}
+
+ if (ctor_dtor_or_conv_p && sfk != sfk_none)
+ *ctor_dtor_or_conv_p = -1;
}
}
+ declarator = make_id_declarator (qualifying_scope,
+ unqualified_name,
+ sfk);
+ declarator->id_loc = token->location;
handle_declarator:;
scope = get_scope_of_declarator (declarator);
if (!cp_parser_error_occurred (parser)
&& cp_parser_require (parser, CPP_MULT, "`*'"))
{
- /* The type of which the member is a member is given by the
- current SCOPE. */
- *type = parser->scope;
- /* The next name will not be qualified. */
- parser->scope = NULL_TREE;
- parser->qualifying_scope = NULL_TREE;
- parser->object_scope = NULL_TREE;
/* Indicate that the `*' operator was used. */
code = INDIRECT_REF;
- /* Look for the optional cv-qualifier-seq. */
- *cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
+
+ if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
+ error ("%qD is a namespace", parser->scope);
+ else
+ {
+ /* The type of which the member is a member is given by the
+ current SCOPE. */
+ *type = parser->scope;
+ /* The next name will not be qualified. */
+ parser->scope = NULL_TREE;
+ parser->qualifying_scope = NULL_TREE;
+ parser->object_scope = NULL_TREE;
+ /* Look for the optional cv-qualifier-seq. */
+ *cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
+ }
}
/* If that didn't work we don't have a ptr-operator. */
if (!cp_parser_parse_definitely (parser))
unqualified-id. */
static tree
-cp_parser_declarator_id (cp_parser* parser)
+cp_parser_declarator_id (cp_parser* parser, bool optional_p)
{
+ tree id;
/* 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. */
- return cp_parser_id_expression (parser,
- /*template_keyword_p=*/false,
- /*check_dependency_p=*/false,
- /*template_p=*/NULL,
- /*declarator_p=*/true);
+ id = cp_parser_id_expression (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/false,
+ /*template_p=*/NULL,
+ /*declarator_p=*/true,
+ optional_p);
+ if (id && BASELINK_P (id))
+ id = BASELINK_FUNCTIONS (id);
+ return id;
}
/* Parse a type-id.
if (is_condition && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
}
-
- return;
}
/* Parse a parameter-declaration-clause.
/* If we run out of tokens, issue an error message. */
case CPP_EOF:
+ case CPP_PRAGMA_EOL:
error ("file ends in default argument");
done = true;
break;
saved_local_variables_forbidden_p
= parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
+ /* The default argument expression may cause implicitly
+ defined member functions to be synthesized, which will
+ result in garbage collection. We must treat this
+ situation as if we were within the body of function so as
+ to avoid collecting live data on the stack. */
+ ++function_depth;
/* Parse the assignment-expression. */
+ if (template_parm_p)
+ push_deferring_access_checks (dk_no_deferred);
default_argument
= cp_parser_assignment_expression (parser, /*cast_p=*/false);
+ if (template_parm_p)
+ pop_deferring_access_checks ();
/* Restore saved state. */
+ --function_depth;
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
parser->local_variables_forbidden_p
= initializer-clause
( expression-list )
- Returns a expression representing the initializer. If no
+ Returns an expression representing the initializer. If no
initializer is present, NULL_TREE is returned.
*IS_PARENTHESIZED_INIT is set to TRUE if the `( expression-list )'
returned is simply a representation for the expression.
Otherwise, a CONSTRUCTOR is returned. The CONSTRUCTOR_ELTS will be
- the elements of the initializer-list (or NULL_TREE, if the last
+ the elements of the initializer-list (or NULL, if the last
production is used). The TREE_TYPE for the CONSTRUCTOR will be
NULL_TREE. There is no way to detect whether or not the optional
trailing `,' was provided. NON_CONSTANT_P is as for
identifier : initializer-clause
initializer-list, identifier : initializer-clause
- Returns a TREE_LIST. The TREE_VALUE of each node is an expression
- for the initializer. If the TREE_PURPOSE is non-NULL, it is the
+ Returns a VEC of constructor_elt. The VALUE of each elt is an expression
+ for the initializer. If the INDEX of the elt is non-NULL, it is the
IDENTIFIER_NODE naming the field to initialize. NON_CONSTANT_P is
as for cp_parser_initializer. */
-static tree
+static VEC(constructor_elt,gc) *
cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
{
- tree initializers = NULL_TREE;
+ VEC(constructor_elt,gc) *v = NULL;
/* Assume all of the expressions are constant. */
*non_constant_p = false;
/* If any clause is non-constant, so is the entire initializer. */
if (clause_non_constant_p)
*non_constant_p = true;
- /* Add it to the list. */
- initializers = tree_cons (identifier, initializer, initializers);
+
+ /* Add it to the vector. */
+ CONSTRUCTOR_APPEND_ELT(v, identifier, initializer);
/* If the next token is not a comma, we have reached the end of
the list. */
cp_lexer_consume_token (parser->lexer);
}
- /* The initializers were built up in reverse order, so we need to
- reverse them now. */
- return nreverse (initializers);
+ return v;
}
/* Classes [gram.class] */
if (token->type == CPP_NAME
&& !cp_parser_nth_token_starts_template_argument_list_p (parser, 2))
{
+ cp_token *identifier_token;
tree identifier;
+ bool ambiguous_p;
/* Look for the identifier. */
+ identifier_token = cp_lexer_peek_token (parser->lexer);
+ ambiguous_p = identifier_token->ambiguous_p;
identifier = cp_parser_identifier (parser);
/* If the next token isn't an identifier, we are certainly not
looking at a class-name. */
decl = identifier;
else
{
+ tree ambiguous_decls;
+ /* If we already know that this lookup is ambiguous, then
+ we've already issued an error message; there's no reason
+ to check again. */
+ if (ambiguous_p)
+ {
+ cp_parser_simulate_error (parser);
+ return error_mark_node;
+ }
/* If the next token is a `::', then the name must be a type
name.
/*is_template=*/false,
/*is_namespace=*/false,
check_dependency_p,
- /*ambiguous_p=*/NULL);
+ &ambiguous_decls);
+ if (ambiguous_decls)
+ {
+ error ("reference to %qD is ambiguous", identifier);
+ print_candidates (ambiguous_decls);
+ if (cp_parser_parsing_tentatively (parser))
+ {
+ identifier_token->ambiguous_p = true;
+ cp_parser_simulate_error (parser);
+ }
+ return error_mark_node;
+ }
}
}
else
/* If this is a typename, create a TYPENAME_TYPE. */
if (typename_p && decl != error_mark_node)
{
- decl = make_typename_type (scope, decl, typename_type, /*complain=*/1);
+ decl = make_typename_type (scope, decl, typename_type,
+ /*complain=*/tf_error);
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, 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");
- return error_mark_node;
+ decl = make_typename_type (scope, decl, tag_type, tf_error);
+ if (decl != error_mark_node)
+ decl = TYPE_NAME (decl);
}
+ else if (TREE_CODE (decl) != TYPE_DECL
+ || TREE_TYPE (decl) == error_mark_node
+ || !IS_AGGR_TYPE (TREE_TYPE (decl)))
+ decl = error_mark_node;
+
+ if (decl == error_mark_node)
+ cp_parser_error (parser, "expected class-name");
return decl;
}
tree fn;
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.
This two-phased approach handles cases like:
{
/* Figure out which function we need to process. */
fn = TREE_VALUE (queue_entry);
-
- /* A hack to prevent garbage collection. */
- function_depth++;
-
/* Parse the function. */
cp_parser_late_parsing_for_member (parser, fn);
- function_depth--;
}
}
define a class that has already been declared with this
syntax.
- The proposed resolution for Core Issue 180 says that whever
+ The proposed resolution for Core Issue 180 says that wherever
you see `class T::X' you should treat `X' as a type-name.
It is OK to define an inaccessible class; for example:
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's a `}', or EOF then we've seen all the members. */
- if (token->type == CPP_CLOSE_BRACE || token->type == CPP_EOF)
+ if (token->type == CPP_CLOSE_BRACE
+ || token->type == CPP_EOF
+ || token->type == CPP_PRAGMA_EOL)
break;
/* See if this token is a keyword. */
/* Accept #pragmas at class scope. */
if (token->type == CPP_PRAGMA)
{
- cp_lexer_handle_pragma (parser->lexer);
+ cp_parser_pragma (parser, pragma_external);
break;
}
/* Check for a template-declaration. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
{
- /* Parse the template-declaration. */
- cp_parser_template_declaration (parser, /*member_p=*/true);
+ /* An explicit specialization here is an error condition, and we
+ expect the specialization handler to detect and report this. */
+ if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS
+ && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER)
+ cp_parser_explicit_specialization (parser);
+ else
+ cp_parser_template_declaration (parser, /*member_p=*/true);
return;
}
/* Create the bitfield declaration. */
decl = grokbitfield (identifier
? make_id_declarator (NULL_TREE,
- identifier)
+ identifier,
+ sfk_none)
: NULL,
&decl_specifiers,
width);
for a pure-specifier; otherwise, we look for a
constant-initializer. When we call `grokfield', it will
perform more stringent semantics checks. */
- if (declarator->kind == cdk_function)
+ if (declarator->kind == cdk_function
+ && declarator->declarator->kind == cdk_id)
initializer = cp_parser_pure_specifier (parser);
else
/* Parse the initializer. */
return;
}
else
- {
- /* Create the declaration. */
- decl = grokfield (declarator, &decl_specifiers,
- initializer, asm_specification,
- attributes);
- /* Any initialization must have been from a
- constant-expression. */
- if (decl && TREE_CODE (decl) == VAR_DECL && initializer)
- DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
- }
+ /* Create the declaration. */
+ decl = grokfield (declarator, &decl_specifiers,
+ initializer, /*init_const_expr_p=*/true,
+ asm_specification,
+ attributes);
}
/* Reset PREFIX_ATTRIBUTES. */
return error_mark_node;
/* Look for the `0' token. */
token = cp_lexer_consume_token (parser->lexer);
- if (token->type != CPP_NUMBER || !integer_zerop (token->value))
+ /* c_lex_with_flags marks a single digit '0' with PURE_ZERO. */
+ if (token->type != CPP_NUMBER || !(token->flags & PURE_ZERO))
{
- cp_parser_error (parser,
+ cp_parser_error (parser,
"invalid pure specifier (only `= 0' is allowed)");
cp_parser_skip_to_end_of_statement (parser);
return error_mark_node;
}
+ if (PROCESSING_REAL_TEMPLATE_DECL_P ())
+ {
+ error ("templates may not be %<virtual%>");
+ 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;
}
static bool
cp_parser_function_try_block (cp_parser* parser)
{
+ tree compound_stmt;
tree try_block;
bool ctor_initializer_p;
if (!cp_parser_require_keyword (parser, RID_TRY, "`try'"))
return false;
/* Let the rest of the front-end know where we are. */
- try_block = begin_function_try_block ();
+ try_block = begin_function_try_block (&compound_stmt);
/* Parse the function-body. */
ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
/* Parse the handlers. */
cp_parser_handler_seq (parser);
/* We're done with the handlers. */
- finish_function_handler_sequence (try_block);
+ finish_function_handler_sequence (try_block, compound_stmt);
return ctor_initializer_p;
}
If CHECK_DEPENDENCY is TRUE, names are not looked up in dependent
types.
- If AMBIGUOUS_P is non-NULL, it is set to true if name-lookup
- results in an ambiguity, and false otherwise. */
+ If AMBIGUOUS_DECLS is non-NULL, *AMBIGUOUS_DECLS is set to a
+ TREE_LIST of candidates if name-lookup results in an ambiguity, and
+ NULL_TREE otherwise. */
static tree
cp_parser_lookup_name (cp_parser *parser, tree name,
enum tag_types tag_type,
- bool is_template, bool is_namespace,
+ bool is_template,
+ bool is_namespace,
bool check_dependency,
- bool *ambiguous_p)
+ tree *ambiguous_decls)
{
+ int flags = 0;
tree decl;
tree object_type = parser->context->object_type;
+ if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
+ flags |= LOOKUP_COMPLAIN;
+
/* Assume that the lookup will be unambiguous. */
- if (ambiguous_p)
- *ambiguous_p = false;
+ if (ambiguous_decls)
+ *ambiguous_decls = NULL_TREE;
/* Now that we have looked up the name, the OBJECT_TYPE (if any) is
no longer valid. Note that if we are parsing tentatively, and
A::B' should be considered a type-name, even if `A'
is dependent. */
type = make_typename_type (parser->scope, name, tag_type,
- /*complain=*/1);
+ /*complain=*/tf_error);
decl = TYPE_NAME (type);
}
- else if (is_template)
+ else if (is_template
+ && (cp_parser_next_token_ends_template_argument_p (parser)
+ || cp_lexer_next_token_is (parser->lexer,
+ CPP_CLOSE_PAREN)))
decl = make_unbound_class_template (parser->scope,
name, NULL_TREE,
- /*complain=*/1);
+ /*complain=*/tf_error);
else
- decl = build_nt (SCOPE_REF, parser->scope, name);
+ decl = build_qualified_name (/*type=*/NULL_TREE,
+ parser->scope, name,
+ is_template);
}
else
{
/* Look it up in the enclosing context, too. */
decl = lookup_name_real (name, tag_type != none_type,
/*nonclass=*/0,
- /*block_p=*/true, is_namespace,
- /*flags=*/0);
+ /*block_p=*/true, is_namespace, flags);
parser->object_scope = object_type;
parser->qualifying_scope = NULL_TREE;
if (object_decl)
{
decl = lookup_name_real (name, tag_type != none_type,
/*nonclass=*/0,
- /*block_p=*/true, is_namespace,
- /*flags=*/0);
+ /*block_p=*/true, is_namespace, flags);
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
}
/* If it's a TREE_LIST, the result of the lookup was ambiguous. */
if (TREE_CODE (decl) == TREE_LIST)
{
- if (ambiguous_p)
- *ambiguous_p = true;
+ if (ambiguous_decls)
+ *ambiguous_decls = decl;
/* The error message we have to print is too complicated for
cp_parser_error, so we incorporate its actions directly. */
if (!cp_parser_simulate_error (parser))
/*is_template=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true,
- /*ambiguous_p=*/NULL);
+ /*ambiguous_decls=*/NULL);
}
/* If DECL is a TEMPLATE_DECL that can be treated like a TYPE_DECL in
template <typename T> struct A::B {};
- Similarly, in a elaborated-type-specifier:
+ Similarly, in an elaborated-type-specifier:
namespace N { struct X{}; }
if (!success_p)
{
/* Skip the entire function. */
- error ("invalid function declaration");
cp_parser_skip_to_end_of_block_or_statement (parser);
fn = error_mark_node;
}
/* Issue an error message. */
error ("named return values are no longer supported");
/* Skip tokens until we reach the start of the function body. */
- while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
- && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
- cp_lexer_consume_token (parser->lexer);
+ while (true)
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_OPEN_BRACE
+ || token->type == CPP_EOF
+ || token->type == CPP_PRAGMA_EOL)
+ break;
+ cp_lexer_consume_token (parser->lexer);
+ }
}
/* The `extern' in `extern "C" void f () { ... }' does not apply to
anything declared inside `f'. */
cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
{
tree decl = NULL_TREE;
+ tree checks;
tree parameter_list;
bool friend_p = false;
+ bool need_lang_pop;
/* Look for the `template' keyword. */
if (!cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'"))
/* And the `<'. */
if (!cp_parser_require (parser, CPP_LESS, "`<'"))
return;
+ /* [temp]
+
+ A template ... shall not have C linkage. */
+ if (current_lang_name == lang_name_c)
+ {
+ error ("template with C linkage");
+ /* Give it C++ linkage to avoid confusing other parts of the
+ front end. */
+ push_lang_context (lang_name_cplusplus);
+ need_lang_pop = true;
+ }
+ else
+ need_lang_pop = false;
+
+ /* We cannot perform access checks on the template parameter
+ declarations until we know what is being declared, just as we
+ cannot check the decl-specifier list. */
+ push_deferring_access_checks (dk_deferred);
/* If the next token is `>', then we have an invalid
specialization. Rather than complain about an invalid template
parameter_list = NULL_TREE;
}
else
- {
- /* Parse the template parameters. */
- begin_template_parm_list ();
- parameter_list = cp_parser_template_parameter_list (parser);
- parameter_list = end_template_parm_list (parameter_list);
- }
+ /* Parse the template parameters. */
+ parameter_list = cp_parser_template_parameter_list (parser);
+
+ /* Get the deferred access checks from the parameter list. These
+ will be checked once we know what is being declared, as for a
+ member template the checks must be performed in the scope of the
+ class containing the member. */
+ checks = get_deferred_access_checks ();
/* Look for the `>'. */
cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");
/* There are no access checks when parsing a template, as we do not
know if a specialization will be a friend. */
push_deferring_access_checks (dk_no_check);
-
decl = cp_parser_single_declaration (parser,
+ checks,
member_p,
&friend_p);
-
pop_deferring_access_checks ();
/* If this is a member template declaration, let the front
/* We are done with the current parameter list. */
--parser->num_template_parameter_lists;
+ pop_deferring_access_checks ();
+
/* Finish up. */
finish_template_decl (parameter_list);
/* Register member declarations. */
if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
finish_member_declaration (decl);
-
+ /* For the erroneous case of a template with C linkage, we pushed an
+ implicit C++ linkage scope; exit that scope now. */
+ if (need_lang_pop)
+ pop_lang_context ();
/* If DECL is a function template, we must return to parse it later.
(Even though there is no definition, there might be default
arguments that need handling.) */
TREE_VALUE (parser->unparsed_functions_queues));
}
+/* Perform the deferred access checks from a template-parameter-list.
+ CHECKS is a TREE_LIST of access checks, as returned by
+ get_deferred_access_checks. */
+
+static void
+cp_parser_perform_template_parameter_access_checks (tree checks)
+{
+ ++processing_template_parmlist;
+ perform_access_checks (checks);
+ --processing_template_parmlist;
+}
+
/* Parse a `decl-specifier-seq [opt] init-declarator [opt] ;' or
`function-definition' sequence. MEMBER_P is true, this declaration
appears in a class scope.
static tree
cp_parser_single_declaration (cp_parser* parser,
+ tree checks,
bool member_p,
bool* friend_p)
{
decl = TYPE_NAME (decl);
else
decl = error_mark_node;
+
+ /* Perform access checks for template parameters. */
+ cp_parser_perform_template_parameter_access_checks (checks);
}
}
/* If it's not a template class, try for a template function. If
|| decl_specifiers.type != error_mark_node))
decl = cp_parser_init_declarator (parser,
&decl_specifiers,
+ checks,
/*function_definition_allowed_p=*/true,
member_p,
declares_class_or_enum,
cast = build_functional_cast (type, expression_list);
/* [expr.const]/1: In an integral constant expression "only type
conversions to integral or enumeration type can be used". */
- if (cast != error_mark_node && !type_dependent_expression_p (type)
- && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (type)))
+ if (TREE_CODE (type) == TYPE_DECL)
+ type = TREE_TYPE (type);
+ if (cast != error_mark_node && !dependent_type_p (type)
+ && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
{
if (cp_parser_non_integral_constant_expression
(parser, "a call to a constructor"))
tree saved_qualifying_scope;
tree saved_object_scope;
bool saved_greater_than_is_operator_p;
+ bool saved_skip_evaluation;
/* [temp.names]
saved_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
saved_object_scope = parser->object_scope;
+ /* We need to evaluate the template arguments, even though this
+ template-id may be nested within a "sizeof". */
+ saved_skip_evaluation = skip_evaluation;
+ skip_evaluation = false;
/* Parse the template-argument-list itself. */
if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
arguments = NULL_TREE;
"a 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);
+ cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");
/* The `>' token might be a greater-than operator again now. */
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
parser->object_scope = saved_object_scope;
+ skip_evaluation = saved_skip_evaluation;
return arguments;
}
TREE_PURPOSE (parser->unparsed_functions_queues));
break;
}
- return;
}
/* FN is a FUNCTION_DECL which may contains a parameter with an
/* Parse the assignment-expression. */
parsed_arg = cp_parser_assignment_expression (parser, /*cast_p=*/false);
+ if (!processing_template_decl)
+ parsed_arg = check_default_argument (TREE_VALUE (parm), parsed_arg);
+
TREE_PURPOSE (parm) = parsed_arg;
/* Update any instantiations we've already created. */
cp_parser_pop_lexer (parser);
}
+ /* Make sure no default arg is missing. */
+ check_default_args (fn);
+
/* Restore the state of local_variables_forbidden_p. */
parser->local_variables_forbidden_p = saved_local_variables_forbidden_p;
saved_message = parser->type_definition_forbidden_message;
/* And create the new one. */
parser->type_definition_forbidden_message
- = xmalloc (strlen (format)
+ = XNEWVEC (const char, strlen (format)
+ strlen (IDENTIFIER_POINTER (ridpointers[keyword]))
+ 1 /* `\0' */);
sprintf ((char *) parser->type_definition_forbidden_message,
|| cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
}
-/* Update the DECL_SPECS to reflect the STORAGE_CLASS. */
+/* Update the DECL_SPECS to reflect the storage class indicated by
+ KEYWORD. */
static void
-cp_parser_set_storage_class (cp_decl_specifier_seq *decl_specs,
- cp_storage_class storage_class)
+cp_parser_set_storage_class (cp_parser *parser,
+ cp_decl_specifier_seq *decl_specs,
+ enum rid keyword)
{
- if (decl_specs->storage_class != sc_none)
- decl_specs->multiple_storage_classes_p = true;
- else
- decl_specs->storage_class = storage_class;
+ cp_storage_class storage_class;
+
+ if (parser->in_unbraced_linkage_specification_p)
+ {
+ error ("invalid use of %qD in linkage specification",
+ ridpointers[keyword]);
+ return;
+ }
+ else if (decl_specs->storage_class != sc_none)
+ {
+ decl_specs->multiple_storage_classes_p = true;
+ return;
+ }
+
+ if ((keyword == RID_EXTERN || keyword == RID_STATIC)
+ && decl_specs->specs[(int) ds_thread])
+ {
+ error ("%<__thread%> before %qD", ridpointers[keyword]);
+ decl_specs->specs[(int) ds_thread] = 0;
+ }
+
+ switch (keyword)
+ {
+ case RID_AUTO:
+ storage_class = sc_auto;
+ break;
+ case RID_REGISTER:
+ storage_class = sc_register;
+ break;
+ case RID_STATIC:
+ storage_class = sc_static;
+ break;
+ case RID_EXTERN:
+ storage_class = sc_extern;
+ break;
+ case RID_MUTABLE:
+ storage_class = sc_mutable;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ decl_specs->storage_class = storage_class;
}
/* Update the DECL_SPECS to reflect the TYPE_SPEC. If USER_DEFINED_P
{
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- /* If we've reached the token we want, consume it and
- stop. */
+
+ /* If we've reached the token we want, consume it and stop. */
if (token->type == type && !nesting_depth)
{
cp_lexer_consume_token (parser->lexer);
return;
}
- /* If we've run out of tokens, stop. */
- if (token->type == CPP_EOF)
- return;
- if (token->type == CPP_OPEN_BRACE
- || token->type == CPP_OPEN_PAREN
- || token->type == CPP_OPEN_SQUARE)
- ++nesting_depth;
- else if (token->type == CPP_CLOSE_BRACE
- || token->type == CPP_CLOSE_PAREN
- || token->type == CPP_CLOSE_SQUARE)
+
+ switch (token->type)
{
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ /* If we've run out of tokens, stop. */
+ return;
+
+ case CPP_OPEN_BRACE:
+ case CPP_OPEN_PAREN:
+ case CPP_OPEN_SQUARE:
+ ++nesting_depth;
+ break;
+
+ case CPP_CLOSE_BRACE:
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
if (nesting_depth-- == 0)
return;
+ break;
+
+ default:
+ break;
}
+
/* Consume this token. */
cp_lexer_consume_token (parser->lexer);
}
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
+/* Returns TRUE iff the n-th token is a "<", or the n-th is a "[" and the
(n+1)-th is a ":" (which is a possible digraph typo for "< ::"). */
static bool
&& cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
return;
/* If we've reached the end of the file, stop. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+ if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)
+ || (end != CPP_PRAGMA_EOL
+ && cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL)))
return;
/* Consume the next token. */
token = cp_lexer_consume_token (parser->lexer);
}
else if (token->type == CPP_OPEN_PAREN)
cp_parser_cache_group (parser, CPP_CLOSE_PAREN, depth + 1);
+ else if (token->type == CPP_PRAGMA)
+ cp_parser_cache_group (parser, CPP_PRAGMA_EOL, depth + 1);
else if (token->type == end)
return;
}
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)
+ while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON
+ || token->type == CPP_SCOPE)
{
tree selector = NULL_TREE;
- if (token->type != CPP_COLON)
+ if (token->type != CPP_COLON
+ || token->type == CPP_SCOPE)
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))
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE))
{
- sel_seq = selector;
- goto finish_selector;
+ /* Detect if we have a unary selector. */
+ if (maybe_unary_selector_p)
+ {
+ sel_seq = selector;
+ goto finish_selector;
+ }
+ else
+ {
+ cp_parser_error (parser, "expected %<:%>");
+ }
}
-
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_consume_token (parser->lexer);
+
+ if (token->type == CPP_SCOPE)
+ {
+ sel_seq
+ = chainon (sel_seq,
+ build_tree_list (selector, NULL_TREE));
+ sel_seq
+ = chainon (sel_seq,
+ build_tree_list (NULL_TREE, NULL_TREE));
+ }
+ else
+ sel_seq
+ = chainon (sel_seq,
+ build_tree_list (selector, NULL_TREE));
token = cp_lexer_peek_token (parser->lexer);
}
cp_parser_linkage_specification (parser);
/* Handle #pragma, if any. */
else if (token->type == CPP_PRAGMA)
- cp_lexer_handle_pragma (parser->lexer);
+ cp_parser_pragma (parser, pragma_external);
/* Allow stray semicolons. */
else if (token->type == CPP_SEMICOLON)
cp_lexer_consume_token (parser->lexer);
{
/* Get the name of the bitfield. */
declarator = make_id_declarator (NULL_TREE,
- cp_parser_identifier (parser));
+ cp_parser_identifier (parser),
+ sfk_none);
eat_colon:
cp_lexer_consume_token (parser->lexer); /* Eat ':'. */
cplus_decl_attributes (&decl, attributes, /*flags=*/0);
}
else
- decl = grokfield (declarator, &declspecs, NULL_TREE,
+ decl = grokfield (declarator, &declspecs,
+ NULL_TREE, /*init_const_expr_p=*/false,
NULL_TREE, attributes);
/* Add the instance variable. */
return error_mark_node;
}
\f
-/* The parser. */
-
-static GTY (()) cp_parser *the_parser;
-
+/* OpenMP 2.5 parsing routines. */
+
+/* All OpenMP clauses. OpenMP 2.5. */
+typedef enum pragma_omp_clause {
+ PRAGMA_OMP_CLAUSE_NONE = 0,
+
+ PRAGMA_OMP_CLAUSE_COPYIN,
+ PRAGMA_OMP_CLAUSE_COPYPRIVATE,
+ PRAGMA_OMP_CLAUSE_DEFAULT,
+ PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
+ PRAGMA_OMP_CLAUSE_IF,
+ PRAGMA_OMP_CLAUSE_LASTPRIVATE,
+ PRAGMA_OMP_CLAUSE_NOWAIT,
+ PRAGMA_OMP_CLAUSE_NUM_THREADS,
+ PRAGMA_OMP_CLAUSE_ORDERED,
+ PRAGMA_OMP_CLAUSE_PRIVATE,
+ PRAGMA_OMP_CLAUSE_REDUCTION,
+ PRAGMA_OMP_CLAUSE_SCHEDULE,
+ PRAGMA_OMP_CLAUSE_SHARED
+} pragma_omp_clause;
+
+/* Returns name of the next clause.
+ If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and
+ the token is not consumed. Otherwise appropriate pragma_omp_clause is
+ returned and the token is consumed. */
+
+static pragma_omp_clause
+cp_parser_omp_clause_name (cp_parser *parser)
+{
+ pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE;
+
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_IF))
+ result = PRAGMA_OMP_CLAUSE_IF;
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DEFAULT))
+ result = PRAGMA_OMP_CLAUSE_DEFAULT;
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_PRIVATE))
+ result = PRAGMA_OMP_CLAUSE_PRIVATE;
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ switch (p[0])
+ {
+ case 'c':
+ if (!strcmp ("copyin", p))
+ result = PRAGMA_OMP_CLAUSE_COPYIN;
+ else if (!strcmp ("copyprivate", p))
+ result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
+ break;
+ case 'f':
+ if (!strcmp ("firstprivate", p))
+ result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
+ break;
+ case 'l':
+ if (!strcmp ("lastprivate", p))
+ result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
+ break;
+ case 'n':
+ if (!strcmp ("nowait", p))
+ result = PRAGMA_OMP_CLAUSE_NOWAIT;
+ else if (!strcmp ("num_threads", p))
+ result = PRAGMA_OMP_CLAUSE_NUM_THREADS;
+ break;
+ case 'o':
+ if (!strcmp ("ordered", p))
+ result = PRAGMA_OMP_CLAUSE_ORDERED;
+ break;
+ case 'r':
+ if (!strcmp ("reduction", p))
+ result = PRAGMA_OMP_CLAUSE_REDUCTION;
+ break;
+ case 's':
+ if (!strcmp ("schedule", p))
+ result = PRAGMA_OMP_CLAUSE_SCHEDULE;
+ else if (!strcmp ("shared", p))
+ result = PRAGMA_OMP_CLAUSE_SHARED;
+ break;
+ }
+ }
+
+ if (result != PRAGMA_OMP_CLAUSE_NONE)
+ cp_lexer_consume_token (parser->lexer);
+
+ return result;
+}
+
+/* Validate that a clause of the given type does not already exist. */
+
+static void
+check_no_duplicate_clause (tree clauses, enum tree_code code, const char *name)
+{
+ tree c;
+
+ for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == code)
+ {
+ error ("too many %qs clauses", name);
+ break;
+ }
+}
+
+/* OpenMP 2.5:
+ variable-list:
+ identifier
+ variable-list , identifier
+
+ In addition, we match a closing parenthesis. An opening parenthesis
+ will have been consumed by the caller.
+
+ If KIND is nonzero, create the appropriate node and install the decl
+ in OMP_CLAUSE_DECL and add the node to the head of the list.
+
+ If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE;
+ return the list created. */
+
+static tree
+cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
+ tree list)
+{
+ while (1)
+ {
+ tree name, decl;
+
+ name = cp_parser_id_expression (parser, /*template_p=*/false,
+ /*check_dependency_p=*/true,
+ /*template_p=*/NULL,
+ /*declarator_p=*/false,
+ /*optional_p=*/false);
+ if (name == error_mark_node)
+ goto skip_comma;
+
+ decl = cp_parser_lookup_name_simple (parser, name);
+ if (decl == error_mark_node)
+ cp_parser_name_lookup_error (parser, name, decl, NULL);
+ else if (kind != 0)
+ {
+ tree u = build_omp_clause (kind);
+ OMP_CLAUSE_DECL (u) = decl;
+ OMP_CLAUSE_CHAIN (u) = list;
+ list = u;
+ }
+ else
+ list = tree_cons (decl, NULL_TREE, list);
+
+ get_comma:
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+ break;
+ cp_lexer_consume_token (parser->lexer);
+ }
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+ {
+ int ending;
+
+ /* Try to resync to an unnested comma. Copied from
+ cp_parser_parenthesized_expression_list. */
+ skip_comma:
+ ending = cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/true,
+ /*consume_paren=*/true);
+ if (ending < 0)
+ goto get_comma;
+ }
+
+ return list;
+}
+
+/* Similarly, but expect leading and trailing parenthesis. This is a very
+ common case for omp clauses. */
+
+static tree
+cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list)
+{
+ if (cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+ return cp_parser_omp_var_list_no_open (parser, kind, list);
+ return list;
+}
+
+/* OpenMP 2.5:
+ default ( shared | none ) */
+
+static tree
+cp_parser_omp_clause_default (cp_parser *parser, tree list)
+{
+ enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+ tree c;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+ return list;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ switch (p[0])
+ {
+ case 'n':
+ if (strcmp ("none", p) != 0)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_NONE;
+ break;
+
+ case 's':
+ if (strcmp ("shared", p) != 0)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_SHARED;
+ break;
+
+ default:
+ goto invalid_kind;
+ }
+
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ {
+ invalid_kind:
+ cp_parser_error (parser, "expected %<none%> or %<shared%>");
+ }
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED)
+ return list;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default");
+ c = build_omp_clause (OMP_CLAUSE_DEFAULT);
+ OMP_CLAUSE_CHAIN (c) = list;
+ OMP_CLAUSE_DEFAULT_KIND (c) = kind;
+
+ return c;
+}
+
+/* OpenMP 2.5:
+ if ( expression ) */
+
+static tree
+cp_parser_omp_clause_if (cp_parser *parser, tree list)
+{
+ tree t, c;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+ return list;
+
+ t = cp_parser_condition (parser);
+
+ if (t == error_mark_node
+ || !cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if");
+
+ c = build_omp_clause (OMP_CLAUSE_IF);
+ OMP_CLAUSE_IF_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 2.5:
+ nowait */
+
+static tree
+cp_parser_omp_clause_nowait (cp_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait");
+
+ c = build_omp_clause (OMP_CLAUSE_NOWAIT);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 2.5:
+ num_threads ( expression ) */
+
+static tree
+cp_parser_omp_clause_num_threads (cp_parser *parser, tree list)
+{
+ tree t, c;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+ return list;
+
+ t = cp_parser_expression (parser, false);
+
+ if (t == error_mark_node
+ || !cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads");
+
+ c = build_omp_clause (OMP_CLAUSE_NUM_THREADS);
+ OMP_CLAUSE_NUM_THREADS_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 2.5:
+ ordered */
+
+static tree
+cp_parser_omp_clause_ordered (cp_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");
+
+ c = build_omp_clause (OMP_CLAUSE_ORDERED);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 2.5:
+ reduction ( reduction-operator : variable-list )
+
+ reduction-operator:
+ One of: + * - & ^ | && || */
+
+static tree
+cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
+{
+ enum tree_code code;
+ tree nlist, c;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+ return list;
+
+ switch (cp_lexer_peek_token (parser->lexer)->type)
+ {
+ case CPP_PLUS:
+ code = PLUS_EXPR;
+ break;
+ case CPP_MULT:
+ code = MULT_EXPR;
+ break;
+ case CPP_MINUS:
+ code = MINUS_EXPR;
+ break;
+ case CPP_AND:
+ code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ code = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ code = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ code = TRUTH_ORIF_EXPR;
+ break;
+ default:
+ cp_parser_error (parser, "`+', `*', `-', `&', `^', `|', `&&', or `||'");
+ resync_fail:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ if (!cp_parser_require (parser, CPP_COLON, "`:'"))
+ goto resync_fail;
+
+ nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list);
+ for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_REDUCTION_CODE (c) = code;
+
+ return nlist;
+}
+
+/* OpenMP 2.5:
+ schedule ( schedule-kind )
+ schedule ( schedule-kind , expression )
+
+ schedule-kind:
+ static | dynamic | guided | runtime
+*/
+
+static tree
+cp_parser_omp_clause_schedule (cp_parser *parser, tree list)
+{
+ tree c, t;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ c = build_omp_clause (OMP_CLAUSE_SCHEDULE);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ switch (p[0])
+ {
+ case 'd':
+ if (strcmp ("dynamic", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC;
+ break;
+
+ case 'g':
+ if (strcmp ("guided", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED;
+ break;
+
+ case 'r':
+ if (strcmp ("runtime", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME;
+ break;
+
+ default:
+ goto invalid_kind;
+ }
+ }
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC))
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
+ else
+ goto invalid_kind;
+ cp_lexer_consume_token (parser->lexer);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ {
+ cp_lexer_consume_token (parser->lexer);
+
+ t = cp_parser_assignment_expression (parser, false);
+
+ if (t == error_mark_node)
+ goto resync_fail;
+ else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
+ error ("schedule %<runtime%> does not take "
+ "a %<chunk_size%> parameter");
+ else
+ OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+ goto resync_fail;
+ }
+ else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`,' or `)'"))
+ goto resync_fail;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule");
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ invalid_kind:
+ cp_parser_error (parser, "invalid schedule kind");
+ resync_fail:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+}
+
+/* Parse all OpenMP clauses. The set clauses allowed by the directive
+ is a bitmask in MASK. Return the list of clauses found; the result
+ of clause default goes in *pdefault. */
+
+static tree
+cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask,
+ const char *where, cp_token *pragma_tok)
+{
+ tree clauses = NULL;
+
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+ {
+ pragma_omp_clause c_kind = cp_parser_omp_clause_name (parser);
+ const char *c_name;
+ tree prev = clauses;
+
+ switch (c_kind)
+ {
+ case PRAGMA_OMP_CLAUSE_COPYIN:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYIN, clauses);
+ c_name = "copyin";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYPRIVATE,
+ clauses);
+ c_name = "copyprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEFAULT:
+ clauses = cp_parser_omp_clause_default (parser, clauses);
+ c_name = "default";
+ break;
+ case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE,
+ clauses);
+ c_name = "firstprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_IF:
+ clauses = cp_parser_omp_clause_if (parser, clauses);
+ c_name = "if";
+ break;
+ case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE,
+ clauses);
+ c_name = "lastprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOWAIT:
+ clauses = cp_parser_omp_clause_nowait (parser, clauses);
+ c_name = "nowait";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_THREADS:
+ clauses = cp_parser_omp_clause_num_threads (parser, clauses);
+ c_name = "num_threads";
+ break;
+ case PRAGMA_OMP_CLAUSE_ORDERED:
+ clauses = cp_parser_omp_clause_ordered (parser, clauses);
+ c_name = "ordered";
+ break;
+ case PRAGMA_OMP_CLAUSE_PRIVATE:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE,
+ clauses);
+ c_name = "private";
+ break;
+ case PRAGMA_OMP_CLAUSE_REDUCTION:
+ clauses = cp_parser_omp_clause_reduction (parser, clauses);
+ c_name = "reduction";
+ break;
+ case PRAGMA_OMP_CLAUSE_SCHEDULE:
+ clauses = cp_parser_omp_clause_schedule (parser, clauses);
+ c_name = "schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_SHARED:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_SHARED,
+ clauses);
+ c_name = "shared";
+ break;
+ default:
+ cp_parser_error (parser, "expected %<#pragma omp%> clause");
+ goto saw_error;
+ }
+
+ if (((mask >> c_kind) & 1) == 0)
+ {
+ /* Remove the invalid clause(s) from the list to avoid
+ confusing the rest of the compiler. */
+ clauses = prev;
+ error ("%qs is not valid for %qs", c_name, where);
+ }
+ }
+ saw_error:
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return finish_omp_clauses (clauses);
+}
+
+/* OpenMP 2.5:
+ structured-block:
+ statement
+
+ In practice, we're also interested in adding the statement to an
+ outer node. So it is convenient if we work around the fact that
+ cp_parser_statement calls add_stmt. */
+
+static unsigned
+cp_parser_begin_omp_structured_block (cp_parser *parser)
+{
+ unsigned save = parser->in_statement;
+
+ /* Only move the values to IN_OMP_BLOCK if they weren't false.
+ This preserves the "not within loop or switch" style error messages
+ for nonsense cases like
+ void foo() {
+ #pragma omp single
+ break;
+ }
+ */
+ if (parser->in_statement)
+ parser->in_statement = IN_OMP_BLOCK;
+
+ return save;
+}
+
+static void
+cp_parser_end_omp_structured_block (cp_parser *parser, unsigned save)
+{
+ parser->in_statement = save;
+}
+
+static tree
+cp_parser_omp_structured_block (cp_parser *parser)
+{
+ tree stmt = begin_omp_structured_block ();
+ unsigned int save = cp_parser_begin_omp_structured_block (parser);
+
+ cp_parser_statement (parser, NULL_TREE, false);
+
+ cp_parser_end_omp_structured_block (parser, save);
+ return finish_omp_structured_block (stmt);
+}
+
+/* OpenMP 2.5:
+ # pragma omp atomic new-line
+ expression-stmt
+
+ expression-stmt:
+ x binop= expr | x++ | ++x | x-- | --x
+ binop:
+ +, *, -, /, &, ^, |, <<, >>
+
+ where x is an lvalue expression with scalar type. */
+
+static void
+cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree lhs, rhs;
+ enum tree_code code;
+
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ lhs = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false);
+ switch (TREE_CODE (lhs))
+ {
+ case ERROR_MARK:
+ goto saw_error;
+
+ case PREINCREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ code = PLUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case PREDECREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ code = MINUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ default:
+ switch (cp_lexer_peek_token (parser->lexer)->type)
+ {
+ case CPP_MULT_EQ:
+ code = MULT_EXPR;
+ break;
+ case CPP_DIV_EQ:
+ code = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS_EQ:
+ code = PLUS_EXPR;
+ break;
+ case CPP_MINUS_EQ:
+ code = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT_EQ:
+ code = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT_EQ:
+ code = RSHIFT_EXPR;
+ break;
+ case CPP_AND_EQ:
+ code = BIT_AND_EXPR;
+ break;
+ case CPP_OR_EQ:
+ code = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR_EQ:
+ code = BIT_XOR_EXPR;
+ break;
+ default:
+ cp_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ rhs = cp_parser_expression (parser, false);
+ if (rhs == error_mark_node)
+ goto saw_error;
+ break;
+ }
+ finish_omp_atomic (code, lhs, rhs);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return;
+
+ saw_error:
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+}
+
+
+/* OpenMP 2.5:
+ # pragma omp barrier new-line
+*/
+
+static void
+cp_parser_omp_barrier (cp_parser *parser, cp_token *pragma_tok)
+{
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ finish_omp_barrier ();
+}
+
+/* OpenMP 2.5:
+ # pragma omp critical [(name)] new-line
+ structured-block
+*/
+
+static tree
+cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree stmt, name = NULL;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ cp_lexer_consume_token (parser->lexer);
+
+ name = cp_parser_identifier (parser);
+
+ if (name == error_mark_node
+ || !cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ if (name == error_mark_node)
+ name = NULL;
+ }
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ stmt = cp_parser_omp_structured_block (parser);
+ return c_finish_omp_critical (stmt, name);
+}
+
+/* OpenMP 2.5:
+ # pragma omp flush flush-vars[opt] new-line
+
+ flush-vars:
+ ( variable-list ) */
+
+static void
+cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok)
+{
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ (void) cp_parser_omp_var_list (parser, 0, NULL);
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ finish_omp_flush ();
+}
+
+/* Parse the restricted form of the for statment allowed by OpenMP. */
+
+static tree
+cp_parser_omp_for_loop (cp_parser *parser)
+{
+ tree init, cond, incr, body, decl, pre_body;
+ location_t loc;
+
+ if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
+ {
+ cp_parser_error (parser, "for statement expected");
+ return NULL;
+ }
+ loc = cp_lexer_consume_token (parser->lexer)->location;
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+ return NULL;
+
+ init = decl = NULL;
+ pre_body = push_stmt_list ();
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ {
+ cp_decl_specifier_seq type_specifiers;
+
+ /* First, try to parse as an initialized declaration. See
+ cp_parser_condition, from whence the bulk of this is copied. */
+
+ cp_parser_parse_tentatively (parser);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifiers);
+ if (!cp_parser_error_occurred (parser))
+ {
+ tree asm_specification, attributes;
+ cp_declarator *declarator;
+
+ declarator = cp_parser_declarator (parser,
+ CP_PARSER_DECLARATOR_NAMED,
+ /*ctor_dtor_or_conv_p=*/NULL,
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
+ attributes = cp_parser_attributes_opt (parser);
+ asm_specification = cp_parser_asm_specification_opt (parser);
+
+ cp_parser_require (parser, CPP_EQ, "`='");
+ if (cp_parser_parse_definitely (parser))
+ {
+ tree pushed_scope;
+
+ decl = start_decl (declarator, &type_specifiers,
+ /*initialized_p=*/false, attributes,
+ /*prefix_attributes=*/NULL_TREE,
+ &pushed_scope);
+
+ init = cp_parser_assignment_expression (parser, false);
+
+ cp_finish_decl (decl, NULL_TREE, /*init_const_expr_p=*/false,
+ asm_specification, LOOKUP_ONLYCONVERTING);
+
+ if (pushed_scope)
+ pop_scope (pushed_scope);
+ }
+ }
+ else
+ cp_parser_abort_tentative_parse (parser);
+
+ /* If parsing as an initialized declaration failed, try again as
+ a simple expression. */
+ if (decl == NULL)
+ init = cp_parser_expression (parser, false);
+ }
+ cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+ pre_body = pop_stmt_list (pre_body);
+
+ cond = NULL;
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ cond = cp_parser_condition (parser);
+ cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+
+ incr = NULL;
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+ incr = cp_parser_expression (parser, false);
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ /* Note that we saved the original contents of this flag when we entered
+ the structured block, and so we don't need to re-save it here. */
+ parser->in_statement = IN_OMP_FOR;
+
+ /* Note that the grammar doesn't call for a structured block here,
+ though the loop as a whole is a structured block. */
+ body = push_stmt_list ();
+ cp_parser_statement (parser, NULL_TREE, false);
+ body = pop_stmt_list (body);
+
+ return finish_omp_for (loc, decl, init, cond, incr, body, pre_body);
+}
+
+/* OpenMP 2.5:
+ #pragma omp for for-clause[optseq] new-line
+ for-loop
+*/
+
+#define OMP_FOR_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \
+ | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree clauses, sb, ret;
+ unsigned int save;
+
+ clauses = cp_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
+ "#pragma omp for", pragma_tok);
+
+ sb = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
+
+ ret = cp_parser_omp_for_loop (parser);
+ if (ret)
+ OMP_FOR_CLAUSES (ret) = clauses;
+
+ cp_parser_end_omp_structured_block (parser, save);
+ add_stmt (finish_omp_structured_block (sb));
+
+ return ret;
+}
+
+/* OpenMP 2.5:
+ # pragma omp master new-line
+ structured-block
+*/
+
+static tree
+cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok)
+{
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return c_finish_omp_master (cp_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+ # pragma omp ordered new-line
+ structured-block
+*/
+
+static tree
+cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok)
+{
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return c_finish_omp_ordered (cp_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+
+ section-scope:
+ { section-sequence }
+
+ section-sequence:
+ section-directive[opt] structured-block
+ section-sequence section-directive structured-block */
+
+static tree
+cp_parser_omp_sections_scope (cp_parser *parser)
+{
+ tree stmt, substmt;
+ bool error_suppress = false;
+ cp_token *tok;
+
+ if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
+ return NULL_TREE;
+
+ stmt = push_stmt_list ();
+
+ if (cp_lexer_peek_token (parser->lexer)->pragma_kind != PRAGMA_OMP_SECTION)
+ {
+ unsigned save;
+
+ substmt = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
+
+ while (1)
+ {
+ cp_parser_statement (parser, NULL_TREE, false);
+
+ tok = cp_lexer_peek_token (parser->lexer);
+ if (tok->pragma_kind == PRAGMA_OMP_SECTION)
+ break;
+ if (tok->type == CPP_CLOSE_BRACE)
+ break;
+ if (tok->type == CPP_EOF)
+ break;
+ }
+
+ cp_parser_end_omp_structured_block (parser, save);
+ substmt = finish_omp_structured_block (substmt);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ add_stmt (substmt);
+ }
+
+ while (1)
+ {
+ tok = cp_lexer_peek_token (parser->lexer);
+ if (tok->type == CPP_CLOSE_BRACE)
+ break;
+ if (tok->type == CPP_EOF)
+ break;
+
+ if (tok->pragma_kind == PRAGMA_OMP_SECTION)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_require_pragma_eol (parser, tok);
+ error_suppress = false;
+ }
+ else if (!error_suppress)
+ {
+ cp_parser_error (parser, "expected %<#pragma omp section%> or %<}%>");
+ error_suppress = true;
+ }
+
+ substmt = cp_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ add_stmt (substmt);
+ }
+ cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+
+ substmt = pop_stmt_list (stmt);
+
+ stmt = make_node (OMP_SECTIONS);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_SECTIONS_BODY (stmt) = substmt;
+
+ add_stmt (stmt);
+ return stmt;
+}
+
+/* OpenMP 2.5:
+ # pragma omp sections sections-clause[optseq] newline
+ sections-scope
+*/
+
+#define OMP_SECTIONS_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree clauses, ret;
+
+ clauses = cp_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
+ "#pragma omp sections", pragma_tok);
+
+ ret = cp_parser_omp_sections_scope (parser);
+ if (ret)
+ OMP_SECTIONS_CLAUSES (ret) = clauses;
+
+ return ret;
+}
+
+/* OpenMP 2.5:
+ # pragma parallel parallel-clause new-line
+ # pragma parallel for parallel-for-clause new-line
+ # pragma parallel sections parallel-sections-clause new-line
+*/
+
+#define OMP_PARALLEL_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_IF) \
+ | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+
+static tree
+cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok)
+{
+ enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
+ const char *p_name = "#pragma omp parallel";
+ tree stmt, clauses, par_clause, ws_clause, block;
+ unsigned int mask = OMP_PARALLEL_CLAUSE_MASK;
+ unsigned int save;
+
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ p_kind = PRAGMA_OMP_PARALLEL_FOR;
+ p_name = "#pragma omp parallel for";
+ mask |= OMP_FOR_CLAUSE_MASK;
+ mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ }
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->value;
+ const char *p = IDENTIFIER_POINTER (id);
+ if (strcmp (p, "sections") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
+ p_name = "#pragma omp parallel sections";
+ mask |= OMP_SECTIONS_CLAUSE_MASK;
+ mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ }
+ }
+
+ clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok);
+ block = begin_omp_parallel ();
+ save = cp_parser_begin_omp_structured_block (parser);
+
+ switch (p_kind)
+ {
+ case PRAGMA_OMP_PARALLEL:
+ cp_parser_already_scoped_statement (parser);
+ par_clause = clauses;
+ break;
+
+ case PRAGMA_OMP_PARALLEL_FOR:
+ c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
+ stmt = cp_parser_omp_for_loop (parser);
+ if (stmt)
+ OMP_FOR_CLAUSES (stmt) = ws_clause;
+ break;
+
+ case PRAGMA_OMP_PARALLEL_SECTIONS:
+ c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
+ stmt = cp_parser_omp_sections_scope (parser);
+ if (stmt)
+ OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ cp_parser_end_omp_structured_block (parser, save);
+ stmt = finish_omp_parallel (par_clause, block);
+ if (p_kind != PRAGMA_OMP_PARALLEL)
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+}
+
+/* OpenMP 2.5:
+ # pragma omp single single-clause[optseq] new-line
+ structured-block
+*/
+
+#define OMP_SINGLE_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree stmt = make_node (OMP_SINGLE);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_SINGLE_CLAUSES (stmt)
+ = cp_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
+ "#pragma omp single", pragma_tok);
+ OMP_SINGLE_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 2.5:
+ # pragma omp threadprivate (variable-list) */
+
+static void
+cp_parser_omp_threadprivate (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree vars;
+
+ vars = cp_parser_omp_var_list (parser, 0, NULL);
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ if (!targetm.have_tls)
+ sorry ("threadprivate variables not supported in this target");
+
+ finish_omp_threadprivate (vars);
+}
+
+/* Main entry point to OpenMP statement pragmas. */
+
+static void
+cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree stmt;
+
+ switch (pragma_tok->pragma_kind)
+ {
+ case PRAGMA_OMP_ATOMIC:
+ cp_parser_omp_atomic (parser, pragma_tok);
+ return;
+ case PRAGMA_OMP_CRITICAL:
+ stmt = cp_parser_omp_critical (parser, pragma_tok);
+ break;
+ case PRAGMA_OMP_FOR:
+ stmt = cp_parser_omp_for (parser, pragma_tok);
+ break;
+ case PRAGMA_OMP_MASTER:
+ stmt = cp_parser_omp_master (parser, pragma_tok);
+ break;
+ case PRAGMA_OMP_ORDERED:
+ stmt = cp_parser_omp_ordered (parser, pragma_tok);
+ break;
+ case PRAGMA_OMP_PARALLEL:
+ stmt = cp_parser_omp_parallel (parser, pragma_tok);
+ break;
+ case PRAGMA_OMP_SECTIONS:
+ stmt = cp_parser_omp_sections (parser, pragma_tok);
+ break;
+ case PRAGMA_OMP_SINGLE:
+ stmt = cp_parser_omp_single (parser, pragma_tok);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (stmt)
+ SET_EXPR_LOCATION (stmt, pragma_tok->location);
+}
+\f
+/* The parser. */
+
+static GTY (()) cp_parser *the_parser;
+
+\f
+/* Special handling for the first token or line in the file. The first
+ thing in the file might be #pragma GCC pch_preprocess, which loads a
+ PCH file, which is a GC collection point. So we need to handle this
+ first pragma without benefit of an existing lexer structure.
+
+ Always returns one token to the caller in *FIRST_TOKEN. This is
+ either the true first token of the file, or the first token after
+ the initial pragma. */
+
+static void
+cp_parser_initial_pragma (cp_token *first_token)
+{
+ tree name = NULL;
+
+ cp_lexer_get_preprocessor_token (NULL, first_token);
+ if (first_token->pragma_kind != PRAGMA_GCC_PCH_PREPROCESS)
+ return;
+
+ cp_lexer_get_preprocessor_token (NULL, first_token);
+ if (first_token->type == CPP_STRING)
+ {
+ name = first_token->value;
+
+ cp_lexer_get_preprocessor_token (NULL, first_token);
+ if (first_token->type != CPP_PRAGMA_EOL)
+ error ("junk at end of %<#pragma GCC pch_preprocess%>");
+ }
+ else
+ error ("expected string literal");
+
+ /* Skip to the end of the pragma. */
+ while (first_token->type != CPP_PRAGMA_EOL && first_token->type != CPP_EOF)
+ cp_lexer_get_preprocessor_token (NULL, first_token);
+
+ /* Read one more token to return to our caller. */
+ cp_lexer_get_preprocessor_token (NULL, first_token);
+
+ /* Now actually load the PCH file. */
+ if (name)
+ c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
+}
+
+/* Normal parsing of a pragma token. Here we can (and must) use the
+ regular lexer. */
+
+static bool
+cp_parser_pragma (cp_parser *parser, enum pragma_context context)
+{
+ cp_token *pragma_tok;
+ unsigned int id;
+
+ pragma_tok = cp_lexer_consume_token (parser->lexer);
+ gcc_assert (pragma_tok->type == CPP_PRAGMA);
+ parser->lexer->in_pragma = true;
+
+ id = pragma_tok->pragma_kind;
+ switch (id)
+ {
+ case PRAGMA_GCC_PCH_PREPROCESS:
+ error ("%<#pragma GCC pch_preprocess%> must be first");
+ break;
+
+ case PRAGMA_OMP_BARRIER:
+ switch (context)
+ {
+ case pragma_compound:
+ cp_parser_omp_barrier (parser, pragma_tok);
+ return false;
+ case pragma_stmt:
+ error ("%<#pragma omp barrier%> may only be "
+ "used in compound statements");
+ break;
+ default:
+ goto bad_stmt;
+ }
+ break;
+
+ case PRAGMA_OMP_FLUSH:
+ switch (context)
+ {
+ case pragma_compound:
+ cp_parser_omp_flush (parser, pragma_tok);
+ return false;
+ case pragma_stmt:
+ error ("%<#pragma omp flush%> may only be "
+ "used in compound statements");
+ break;
+ default:
+ goto bad_stmt;
+ }
+ break;
+
+ case PRAGMA_OMP_THREADPRIVATE:
+ cp_parser_omp_threadprivate (parser, pragma_tok);
+ return false;
+
+ case PRAGMA_OMP_ATOMIC:
+ case PRAGMA_OMP_CRITICAL:
+ case PRAGMA_OMP_FOR:
+ case PRAGMA_OMP_MASTER:
+ case PRAGMA_OMP_ORDERED:
+ case PRAGMA_OMP_PARALLEL:
+ case PRAGMA_OMP_SECTIONS:
+ case PRAGMA_OMP_SINGLE:
+ if (context == pragma_external)
+ goto bad_stmt;
+ cp_parser_omp_construct (parser, pragma_tok);
+ return true;
+
+ case PRAGMA_OMP_SECTION:
+ error ("%<#pragma omp section%> may only be used in "
+ "%<#pragma omp sections%> construct");
+ break;
+
+ default:
+ gcc_assert (id >= PRAGMA_FIRST_EXTERNAL);
+ c_invoke_pragma_handler (id);
+ break;
+
+ bad_stmt:
+ cp_parser_error (parser, "expected declaration specifiers");
+ break;
+ }
+
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return false;
+}
+
+/* The interface the pragma parsers have to the lexer. */
+
+enum cpp_ttype
+pragma_lex (tree *value)
+{
+ cp_token *tok;
+ enum cpp_ttype ret;
+
+ tok = cp_lexer_peek_token (the_parser->lexer);
+
+ ret = tok->type;
+ *value = tok->value;
+
+ if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
+ ret = CPP_EOF;
+ else if (ret == CPP_STRING)
+ *value = cp_parser_string_literal (the_parser, false, false);
+ else
+ {
+ cp_lexer_consume_token (the_parser->lexer);
+ if (ret == CPP_KEYWORD)
+ ret = CPP_NAME;
+ }
+
+ return ret;
+}
+
+\f
/* External interface. */
/* Parse one entire translation unit. */