/* C++ Parser.
Copyright (C) 2000, 2001, 2002, 2003, 2004,
- 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "timevar.h"
#include "cpplib.h"
#include "tree.h"
#include "cp-tree.h"
#include "c-family/c-common.h"
#include "c-family/c-objc.h"
#include "plugin.h"
+#include "tree-pretty-print.h"
+#include "parser.h"
\f
/* The lexer. */
/* The cp_lexer_* routines mediate between the lexer proper (in libcpp
and c-lex.c) and the C++ parser. */
-/* A token's value and its associated deferred access checks and
- qualifying scope. */
-
-struct GTY(()) tree_check {
- /* The value associated with the token. */
- tree value;
- /* The checks that have been associated with value. */
- VEC (deferred_access_check, gc)* checks;
- /* The token's qualifying scope (used when it is a
- CPP_NESTED_NAME_SPECIFIER). */
- tree qualifying_scope;
-};
-
-/* A C++ token. */
-
-typedef struct GTY (()) cp_token {
- /* The kind of token. */
- ENUM_BITFIELD (cpp_ttype) type : 8;
- /* If this token is a keyword, this value indicates which keyword.
- Otherwise, this value is RID_MAX. */
- ENUM_BITFIELD (rid) keyword : 8;
- /* Token flags. */
- unsigned char flags;
- /* Identifier for the pragma. */
- ENUM_BITFIELD (pragma_kind) pragma_kind : 6;
- /* 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 location at which this token was found. */
- location_t location;
- /* The value associated with this token, if any. */
- union cp_token_value {
- /* Used for CPP_NESTED_NAME_SPECIFIER and CPP_TEMPLATE_ID. */
- struct tree_check* GTY((tag ("1"))) tree_check_value;
- /* Use for all other tokens. */
- tree GTY((tag ("0"))) value;
- } GTY((desc ("(%1.type == CPP_TEMPLATE_ID) || (%1.type == CPP_NESTED_NAME_SPECIFIER)"))) u;
-} cp_token;
-
-/* We use a stack of token pointer for saving token sets. */
-typedef struct cp_token *cp_token_position;
-DEF_VEC_P (cp_token_position);
-DEF_VEC_ALLOC_P (cp_token_position,heap);
-
static cp_token eof_token =
{
- CPP_EOF, RID_MAX, 0, PRAGMA_NONE, false, 0, 0, { NULL }
+ CPP_EOF, RID_MAX, 0, PRAGMA_NONE, false, false, false, 0, { NULL }
};
-/* The cp_lexer structure represents the C++ lexer. It is responsible
- for managing the token stream from the preprocessor and supplying
- it to the parser. Tokens are never added to the cp_lexer after
- it is created. */
-
-typedef struct GTY (()) cp_lexer {
- /* The memory allocated for the buffer. NULL if this lexer does not
- own the token buffer. */
- cp_token * GTY ((length ("%h.buffer_length"))) buffer;
- /* If the lexer owns the buffer, this is the number of tokens in the
- buffer. */
- size_t buffer_length;
-
- /* A pointer just past the last available token. The tokens
- in this lexer are [buffer, last_token). */
- cp_token_position GTY ((skip)) last_token;
-
- /* The next available token. If NEXT_TOKEN is &eof_token, then there are
- no more available tokens. */
- cp_token_position GTY ((skip)) next_token;
-
- /* A stack indicating positions at which cp_lexer_save_tokens was
- called. The top entry is the most recent position at which we
- began saving tokens. If the stack is non-empty, we are saving
- 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;
-
- /* 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
- allocate heap memory for it, since tokens are never removed from the
- lexer's array. There is also no need for the GC to walk through
- a cp_token_cache, since everything in here is referenced through
- a lexer. */
-
-typedef struct GTY(()) cp_token_cache {
- /* The beginning of the token range. */
- cp_token * GTY((skip)) first;
-
- /* Points immediately after the last token in the range. */
- cp_token * GTY ((skip)) last;
-} cp_token_cache;
-
/* The various kinds of non integral constant we encounter. */
typedef enum non_integral_constant {
NIC_NONE,
(cp_lexer *);
static int cp_lexer_saving_tokens
(const cp_lexer *);
-static cp_token_position cp_lexer_token_position
- (cp_lexer *, bool);
static cp_token *cp_lexer_token_at
(cp_lexer *, cp_token_position);
static void cp_lexer_get_preprocessor_token
#define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
#define CP_SAVED_TOKEN_STACK 5
-/* A token type for keywords, as opposed to ordinary identifiers. */
-#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
-
-/* A token type for template-ids. If a template-id is processed while
- parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
- the value of the CPP_TEMPLATE_ID is whatever was returned by
- cp_parser_template_id. */
-#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
-
-/* A token type for nested-name-specifiers. If a
- nested-name-specifier is processed while parsing tentatively, it is
- replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
- CPP_NESTED_NAME_SPECIFIER is whatever was returned by
- cp_parser_nested_name_specifier_opt. */
-#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
-
-/* A token type for tokens that are not tokens at all; these are used
- to represent slots in the array where there used to be a token
- that has now been deleted. */
-#define CPP_PURGED ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1))
-
-/* The number of token types, including C++-specific ones. */
-#define N_CP_TTYPES ((int) (CPP_PURGED + 1))
-
/* Variables. */
#ifdef ENABLE_CHECKING
sizeof, typeof, or alignof. */
int cp_unevaluated_operand;
-/* Create a new main C++ lexer, the lexer that gets tokens from the
- preprocessor. */
+#ifdef ENABLE_CHECKING
+/* Dump up to NUM tokens in BUFFER to FILE. If NUM is 0, dump all the
+ tokens. */
+
+void
+cp_lexer_dump_tokens (FILE *file, VEC(cp_token,gc) *buffer, unsigned num)
+{
+ unsigned i;
+ cp_token *token;
+
+ fprintf (file, "%u tokens\n", VEC_length (cp_token, buffer));
+
+ if (num == 0)
+ num = VEC_length (cp_token, buffer);
+
+ for (i = 0; VEC_iterate (cp_token, buffer, i, token) && i < num; i++)
+ {
+ cp_lexer_print_token (file, token);
+ switch (token->type)
+ {
+ case CPP_SEMICOLON:
+ case CPP_OPEN_BRACE:
+ case CPP_CLOSE_BRACE:
+ case CPP_EOF:
+ fputc ('\n', file);
+ break;
+
+ default:
+ fputc (' ', file);
+ }
+ }
+
+ if (i == num && i < VEC_length (cp_token, buffer))
+ {
+ fprintf (file, " ... ");
+ cp_lexer_print_token (file, VEC_index (cp_token, buffer,
+ VEC_length (cp_token, buffer) - 1));
+ }
+
+ fprintf (file, "\n");
+}
+
+
+/* Dump all tokens in BUFFER to stderr. */
+
+void
+cp_lexer_debug_tokens (VEC(cp_token,gc) *buffer)
+{
+ cp_lexer_dump_tokens (stderr, buffer, 0);
+}
+#endif
+
+
+/* Allocate memory for a new lexer object and return it. */
static cp_lexer *
-cp_lexer_new_main (void)
+cp_lexer_alloc (void)
{
- cp_token first_token;
cp_lexer *lexer;
- cp_token *pos;
- size_t alloc;
- size_t space;
- cp_token *buffer;
-
- /* 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);
c_common_no_more_pch ();
CP_SAVED_TOKEN_STACK);
/* Create the buffer. */
- alloc = CP_LEXER_BUFFER_SIZE;
- buffer = ggc_alloc_vec_cp_token (alloc);
+ lexer->buffer = VEC_alloc (cp_token, gc, CP_LEXER_BUFFER_SIZE);
+
+ return lexer;
+}
+
+
+/* Create a new main C++ lexer, the lexer that gets tokens from the
+ preprocessor. */
+
+static cp_lexer *
+cp_lexer_new_main (void)
+{
+ cp_lexer *lexer;
+ cp_token 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 (&token);
+
+ lexer = cp_lexer_alloc ();
/* Put the first token in the buffer. */
- space = alloc;
- pos = buffer;
- *pos = first_token;
+ VEC_quick_push (cp_token, lexer->buffer, &token);
/* Get the remaining tokens from the preprocessor. */
- while (pos->type != CPP_EOF)
+ while (token.type != CPP_EOF)
{
- pos++;
- if (!--space)
- {
- space = alloc;
- alloc *= 2;
- buffer = GGC_RESIZEVEC (cp_token, buffer, alloc);
- pos = buffer + space;
- }
- cp_lexer_get_preprocessor_token (lexer, pos);
+ cp_lexer_get_preprocessor_token (lexer, &token);
+ VEC_safe_push (cp_token, gc, lexer->buffer, &token);
}
- lexer->buffer = buffer;
- lexer->buffer_length = alloc - space;
- lexer->last_token = pos;
- lexer->next_token = lexer->buffer_length ? buffer : &eof_token;
+
+ lexer->last_token = VEC_address (cp_token, lexer->buffer)
+ + VEC_length (cp_token, lexer->buffer)
+ - 1;
+ lexer->next_token = VEC_length (cp_token, lexer->buffer)
+ ? VEC_address (cp_token, lexer->buffer)
+ : &eof_token;
/* Subsequent preprocessor diagnostics should use compiler
diagnostic functions to get the compiler source location. */
done_lexing = true;
- gcc_assert (lexer->next_token->type != CPP_PURGED);
+ gcc_assert (!lexer->next_token->purged_p);
return lexer;
}
/* We do not own the buffer. */
lexer->buffer = NULL;
- lexer->buffer_length = 0;
lexer->next_token = first == last ? &eof_token : first;
lexer->last_token = last;
lexer->debugging_p = false;
#endif
- gcc_assert (lexer->next_token->type != CPP_PURGED);
+ gcc_assert (!lexer->next_token->purged_p);
return lexer;
}
static void
cp_lexer_destroy (cp_lexer *lexer)
{
- if (lexer->buffer)
- ggc_free (lexer->buffer);
+ VEC_free (cp_token, gc, lexer->buffer);
VEC_free (cp_token_position, heap, lexer->saved_tokens);
ggc_free (lexer);
}
lexer == NULL ? 0 : C_LEX_STRING_NO_JOIN);
token->keyword = RID_MAX;
token->pragma_kind = PRAGMA_NONE;
+ token->purged_p = false;
/* On some systems, some header files are surrounded by an
implicit extern "C" block. Set a flag in the token if it
case RID_TYPEOF:
/* C++0x extensions. */
case RID_DECLTYPE:
+ case RID_UNDERLYING_TYPE:
return true;
default:
break;
}
- if (token->type != CPP_PURGED)
+ if (!token->purged_p)
--n;
}
}
}
- while (lexer->next_token->type == CPP_PURGED);
+ while (lexer->next_token->purged_p);
cp_lexer_set_source_position_from_token (token);
cp_token *tok = lexer->next_token;
gcc_assert (tok != &eof_token);
- tok->type = CPP_PURGED;
+ tok->purged_p = true;
tok->location = UNKNOWN_LOCATION;
tok->u.value = NULL_TREE;
tok->keyword = RID_MAX;
break;
}
}
- while (tok->type == CPP_PURGED);
+ while (tok->purged_p);
lexer->next_token = tok;
}
for ( tok += 1; tok != peek; tok += 1)
{
- tok->type = CPP_PURGED;
+ tok->purged_p = true;
tok->location = UNKNOWN_LOCATION;
tok->u.value = NULL_TREE;
tok->keyword = RID_MAX;
"KEYWORD",
"TEMPLATE_ID",
"NESTED_NAME_SPECIFIER",
- "PURGED"
};
- /* If we have a name for the token, print it out. Otherwise, we
- simply give the numeric code. */
- gcc_assert (token->type < ARRAY_SIZE(token_names));
- fputs (token_names[token->type], stream);
-
/* For some tokens, print the associated data. */
switch (token->type)
{
fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->u.value));
break;
+ case CPP_NUMBER:
+ print_generic_expr (stream, token->u.value, 0);
+ break;
+
default:
+ /* If we have a name for the token, print it out. Otherwise, we
+ simply give the numeric code. */
+ if (token->type < ARRAY_SIZE(token_names))
+ fputs (token_names[token->type], stream);
+ else
+ fprintf (stream, "[%d]", token->type);
break;
}
}
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
static cp_declarator *make_call_declarator
- (cp_declarator *, tree, cp_cv_quals, tree, tree);
+ (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, tree, tree);
static cp_declarator *make_array_declarator
(cp_declarator *, tree);
static cp_declarator *make_pointer_declarator
make_call_declarator (cp_declarator *target,
tree parms,
cp_cv_quals cv_qualifiers,
+ cp_virt_specifiers virt_specifiers,
tree exception_specification,
tree late_return_type)
{
declarator->declarator = target;
declarator->u.function.parameters = parms;
declarator->u.function.qualifiers = cv_qualifiers;
+ declarator->u.function.virt_specifiers = virt_specifiers;
declarator->u.function.exception_specification = exception_specification;
declarator->u.function.late_return_type = late_return_type;
if (target)
enum cp_parser_prec prec;
} cp_parser_binary_operations_map_node;
-/* The status of a tentative parse. */
-
-typedef enum cp_parser_status_kind
-{
- /* No errors have occurred. */
- CP_PARSER_STATUS_KIND_NO_ERROR,
- /* An error has occurred. */
- CP_PARSER_STATUS_KIND_ERROR,
- /* We are committed to this tentative parse, whether or not an error
- has occurred. */
- CP_PARSER_STATUS_KIND_COMMITTED
-} cp_parser_status_kind;
-
typedef struct cp_parser_expression_stack_entry
{
/* Left hand side of the binary operation we are currently
typedef struct cp_parser_expression_stack_entry
cp_parser_expression_stack[NUM_PREC_VALUES];
-/* Context that is saved and restored when parsing tentatively. */
-typedef struct GTY (()) cp_parser_context {
- /* If this is a tentative parsing context, the status of the
- tentative parse. */
- enum cp_parser_status_kind status;
- /* If non-NULL, we have just seen a `x->' or `x.' expression. Names
- that are looked up in this context must be looked up both in the
- scope given by OBJECT_TYPE (the type of `x' or `*x') and also in
- the context of the containing expression. */
- tree object_type;
-
- /* The next parsing context in the stack. */
- struct cp_parser_context *next;
-} cp_parser_context;
-
/* Prototypes. */
/* Constructors and destructors. */
return context;
}
-/* An entry in a queue of function arguments that require post-processing. */
-
-typedef struct GTY(()) cp_default_arg_entry_d {
- /* The current_class_type when we parsed this arg. */
- tree class_type;
-
- /* The function decl itself. */
- tree decl;
-} cp_default_arg_entry;
-
-DEF_VEC_O(cp_default_arg_entry);
-DEF_VEC_ALLOC_O(cp_default_arg_entry,gc);
-
-/* An entry in a stack for member functions of local classes. */
-
-typedef struct GTY(()) cp_unparsed_functions_entry_d {
- /* Functions with default arguments that require post-processing.
- Functions appear in this list in declaration order. */
- VEC(cp_default_arg_entry,gc) *funs_with_default_args;
-
- /* Functions with defintions that require post-processing. Functions
- appear in this list in declaration order. */
- VEC(tree,gc) *funs_with_definitions;
-} cp_unparsed_functions_entry;
-
-DEF_VEC_O(cp_unparsed_functions_entry);
-DEF_VEC_ALLOC_O(cp_unparsed_functions_entry,gc);
-
-/* The cp_parser structure represents the C++ parser. */
-
-typedef struct GTY(()) cp_parser {
- /* The lexer from which we are obtaining tokens. */
- cp_lexer *lexer;
-
- /* The scope in which names should be looked up. If NULL_TREE, then
- we look up names in the scope that is currently open in the
- source program. If non-NULL, this is either a TYPE or
- NAMESPACE_DECL for the scope in which we should look. It can
- also be ERROR_MARK, when we've parsed a bogus scope.
-
- This value is not cleared automatically after a name is looked
- up, so we must be careful to clear it before starting a new look
- up sequence. (If it is not cleared, then `X::Y' followed by `Z'
- will look up `Z' in the scope of `X', rather than the current
- scope.) Unfortunately, it is difficult to tell when name lookup
- is complete, because we sometimes peek at a token, look it up,
- and then decide not to consume it. */
- tree scope;
-
- /* OBJECT_SCOPE and QUALIFYING_SCOPE give the scopes in which the
- last lookup took place. OBJECT_SCOPE is used if an expression
- like "x->y" or "x.y" was used; it gives the type of "*x" or "x",
- respectively. QUALIFYING_SCOPE is used for an expression of the
- form "X::Y"; it refers to X. */
- tree object_scope;
- tree qualifying_scope;
-
- /* A stack of parsing contexts. All but the bottom entry on the
- stack will be tentative contexts.
-
- We parse tentatively in order to determine which construct is in
- use in some situations. For example, in order to determine
- whether a statement is an expression-statement or a
- declaration-statement we parse it tentatively as a
- declaration-statement. If that fails, we then reparse the same
- token stream as an expression-statement. */
- cp_parser_context *context;
-
- /* True if we are parsing GNU C++. If this flag is not set, then
- GNU extensions are not recognized. */
- bool allow_gnu_extensions_p;
-
- /* TRUE if the `>' token should be interpreted as the greater-than
- operator. FALSE if it is the end of a template-id or
- template-parameter-list. In C++0x mode, this flag also applies to
- `>>' tokens, which are viewed as two consecutive `>' tokens when
- this flag is FALSE. */
- bool greater_than_is_operator_p;
-
- /* TRUE if default arguments are allowed within a parameter list
- that starts at this point. FALSE if only a gnu extension makes
- them permissible. */
- bool default_arg_ok_p;
-
- /* TRUE if we are parsing an integral constant-expression. See
- [expr.const] for a precise definition. */
- bool integral_constant_expression_p;
-
- /* TRUE if we are parsing an integral constant-expression -- but a
- non-constant expression should be permitted as well. This flag
- is used when parsing an array bound so that GNU variable-length
- arrays are tolerated. */
- bool allow_non_integral_constant_expression_p;
-
- /* TRUE if ALLOW_NON_CONSTANT_EXPRESSION_P is TRUE and something has
- been seen that makes the expression non-constant. */
- bool non_integral_constant_expression_p;
-
- /* TRUE if local variable names and `this' are forbidden in the
- current context. */
- bool local_variables_forbidden_p;
-
- /* TRUE if the declaration we are parsing is part of a
- linkage-specification of the form `extern string-literal
- declaration'. */
- bool in_unbraced_linkage_specification_p;
-
- /* TRUE if we are presently parsing a declarator, after the
- direct-declarator. */
- bool in_declarator_p;
-
- /* TRUE if we are presently parsing a template-argument-list. */
- bool in_template_argument_list_p;
-
- /* 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
-#define IN_IF_STMT 16
- 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
- such a situation, both "type (expr)" and "type (type)" are valid
- alternatives. */
- bool in_type_id_in_expr_p;
-
- /* TRUE if we are currently in a header file where declarations are
- implicitly extern "C". */
- bool implicit_extern_c;
-
- /* TRUE if strings in expressions should be translated to the execution
- character set. */
- bool translate_strings_p;
-
- /* TRUE if we are presently parsing the body of a function, but not
- a local class. */
- bool in_function_body;
-
- /* TRUE if we can auto-correct a colon to a scope operator. */
- bool colon_corrects_to_scope_p;
-
- /* If non-NULL, then we are parsing a construct where new type
- definitions are not permitted. The string stored here will be
- issued as an error message if a type is defined. */
- const char *type_definition_forbidden_message;
-
- /* A stack used for member functions of local classes. The lists
- contained in an individual entry can only be processed once the
- outermost class being defined is complete. */
- VEC(cp_unparsed_functions_entry,gc) *unparsed_queues;
-
- /* The number of classes whose definitions are currently in
- progress. */
- unsigned num_classes_being_defined;
-
- /* The number of template parameter lists that apply directly to the
- current declaration. */
- unsigned num_template_parameter_lists;
-} cp_parser;
-
/* Managing the unparsed function queues. */
#define unparsed_funs_with_default_args \
static tree cp_parser_expression_statement
(cp_parser *, tree);
static tree cp_parser_compound_statement
- (cp_parser *, tree, bool);
+ (cp_parser *, tree, bool, bool);
static void cp_parser_statement_seq_opt
(cp_parser *, tree);
static tree cp_parser_selection_statement
(cp_parser *, tree, tree);
static tree cp_parser_range_for
(cp_parser *, tree, tree, tree);
+static tree cp_parser_perform_range_for_lookup
+ (tree, tree *, tree *);
+static tree cp_parser_range_for_member_function
+ (tree, tree);
static tree cp_parser_jump_statement
(cp_parser *);
static void cp_parser_declaration_statement
(cp_parser *, tree *, cp_cv_quals *);
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
(cp_parser *);
+static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
+ (cp_parser *);
static tree cp_parser_late_return_type_opt
(cp_parser *);
static tree cp_parser_declarator_id
location_t location)
{
tree decl, old_scope;
+ cp_parser_commit_to_tentative_parse (parser);
/* Try to lookup the identifier. */
old_scope = parser->scope;
parser->scope = scope;
else
gcc_unreachable ();
}
- cp_parser_commit_to_tentative_parse (parser);
}
/* Check for a common situation where a type-name should be present,
__is_convertible_to ( type-id , type-id )
__is_empty ( type-id )
__is_enum ( type-id )
+ __is_literal_type ( type-id )
__is_pod ( type-id )
__is_polymorphic ( type-id )
+ __is_std_layout ( type-id )
+ __is_trivial ( type-id )
__is_union ( type-id )
Objective-C++ Extension:
/* Start the statement-expression. */
expr = begin_stmt_expr ();
/* Parse the compound-statement. */
- cp_parser_compound_statement (parser, expr, false);
+ cp_parser_compound_statement (parser, expr, false, false);
/* Finish up. */
expr = finish_stmt_expr (expr, false);
}
`&A::B' might be a pointer-to-member, but `&(A::B)' is
not. */
finish_parenthesized_expr (expr);
+ /* DR 705: Wrapping an unqualified name in parentheses
+ suppresses arg-dependent lookup. We want to pass back
+ CP_ID_KIND_QUALIFIED for suppressing vtable lookup
+ (c++/37862), but none of the others. */
+ if (*idk != CP_ID_KIND_QUALIFIED)
+ *idk = CP_ID_KIND_NONE;
}
/* The `>' token might be the end of a template-id or
template-parameter-list now. */
case RID_IS_CONVERTIBLE_TO:
case RID_IS_EMPTY:
case RID_IS_ENUM:
+ case RID_IS_LITERAL_TYPE:
case RID_IS_POD:
case RID_IS_POLYMORPHIC:
case RID_IS_STD_LAYOUT:
case RID_IS_TRIVIAL:
case RID_IS_UNION:
- case RID_IS_LITERAL_TYPE:
return cp_parser_trait_expr (parser, token->keyword);
/* Objective-C++ expressions. */
postfix_expression
= (finish_compound_literal
(type, build_constructor (init_list_type_node,
- initializer_list)));
+ initializer_list),
+ tf_warning_or_error));
break;
}
}
= (build_new_method_call
(instance, fn, &args, NULL_TREE,
(idk == CP_ID_KIND_QUALIFIED
- ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL),
+ ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
+ : LOOKUP_NORMAL),
/*fn_p=*/NULL,
tf_warning_or_error));
}
if (cp_parser_non_integral_constant_expression (parser, NIC_DEL))
return error_mark_node;
- return delete_sanity (expression, NULL_TREE, array_p, global_scope_p);
+ return delete_sanity (expression, NULL_TREE, array_p, global_scope_p,
+ tf_warning_or_error);
}
/* Returns true if TOKEN may start a cast-expression and false
return expr;
}
-/* Parse a trait expression. */
+/* Parse a trait expression.
+
+ Returns a representation of the expression, the underlying type
+ of the type at issue when KEYWORD is RID_UNDERLYING_TYPE. */
static tree
cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
case RID_IS_ENUM:
kind = CPTK_IS_ENUM;
break;
+ case RID_IS_LITERAL_TYPE:
+ kind = CPTK_IS_LITERAL_TYPE;
+ break;
case RID_IS_POD:
kind = CPTK_IS_POD;
break;
case RID_IS_UNION:
kind = CPTK_IS_UNION;
break;
- case RID_IS_LITERAL_TYPE:
- kind = CPTK_IS_LITERAL_TYPE;
+ case RID_UNDERLYING_TYPE:
+ kind = CPTK_UNDERLYING_TYPE;
break;
default:
gcc_unreachable ();
/* Complete the trait expression, which may mean either processing
the trait expr now or saving it for template instantiation. */
- return finish_trait_expr (kind, type1, type2);
+ return kind != CPTK_UNDERLYING_TYPE
+ ? finish_trait_expr (kind, type1, type2)
+ : finish_underlying_type (type1);
}
/* Lambdas that appear in variable initializer or default argument scope
quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr)
? TYPE_UNQUALIFIED : TYPE_QUAL_CONST);
declarator = make_call_declarator (declarator, param_list, quals,
+ VIRT_SPEC_UNSPECIFIED,
exception_spec,
/*late_return_type=*/NULL_TREE);
declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr);
}
/* Anything that starts with a `{' must be a compound-statement. */
else if (token->type == CPP_OPEN_BRACE)
- statement = cp_parser_compound_statement (parser, NULL, false);
+ statement = cp_parser_compound_statement (parser, NULL, false, false);
/* CPP_PRAGMA is a #pragma inside a function body, which constitutes
a statement all its own. */
else if (token->type == CPP_PRAGMA)
static tree
cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr,
- bool in_try)
+ bool in_try, bool function_body)
{
tree compound_stmt;
/* Consume the `{'. */
if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
return error_mark_node;
+ if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && !function_body)
+ pedwarn (input_location, OPT_pedantic,
+ "compound-statement in constexpr function");
/* Begin the compound-statement. */
compound_stmt = begin_compound_stmt (in_try ? BCS_TRY_BLOCK : 0);
/* If the next keyword is `__label__' we have a label declaration. */
if (BRACE_ENCLOSED_INITIALIZER_P (initializer))
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
- if (!non_constant_p)
- initializer = fold_non_dependent_expr (initializer);
-
/* Process the initializer. */
cp_finish_decl (decl,
initializer, !non_constant_p,
}
If RANGE_EXPR is an array:
- BEGIN_EXPR = __range
- END_EXPR = __range + ARRAY_SIZE(__range)
+ BEGIN_EXPR = __range
+ END_EXPR = __range + ARRAY_SIZE(__range)
+ Else if RANGE_EXPR has a member 'begin' or 'end':
+ BEGIN_EXPR = __range.begin()
+ END_EXPR = __range.end()
Else:
BEGIN_EXPR = begin(__range)
END_EXPR = end(__range);
- When calling begin()/end() we must use argument dependent
- lookup, but always considering 'std' as an associated namespace. */
+ If __range has a member 'begin' but not 'end', or vice versa, we must
+ still use the second alternative (it will surely fail, however).
+ When calling begin()/end() in the third alternative we must use
+ argument dependent lookup, but always considering 'std' as an associated
+ namespace. */
tree
cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
else
{
/* Find out the type deduced by the declaration
- * `auto &&__range = range_expr' */
+ `auto &&__range = range_expr'. */
range_type = cp_build_reference_type (make_auto (), true);
range_type = do_auto_deduction (range_type, range_expr,
type_uses_auto (range_type));
- /* Create the __range variable */
+ /* Create the __range variable. */
range_temp = build_decl (input_location, VAR_DECL,
get_identifier ("__for_range"), range_type);
TREE_USED (range_temp) = 1;
LOOKUP_ONLYCONVERTING);
range_temp = convert_from_reference (range_temp);
-
- if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
- {
- /* If RANGE_TEMP is an array we will use pointer arithmetic */
- iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp)));
- begin_expr = range_temp;
- end_expr
- = build_binary_op (input_location, PLUS_EXPR,
- range_temp,
- array_type_nelts_top (TREE_TYPE (range_temp)),
- 0);
- }
- else
- {
- /* If it is not an array, we must call begin(__range)/end__range() */
- VEC(tree,gc) *vec;
-
- begin_expr = get_identifier ("begin");
- vec = make_tree_vector ();
- VEC_safe_push (tree, gc, vec, range_temp);
- begin_expr = perform_koenig_lookup (begin_expr, vec,
- /*include_std=*/true);
- begin_expr = finish_call_expr (begin_expr, &vec, false, true,
- tf_warning_or_error);
- release_tree_vector (vec);
-
- end_expr = get_identifier ("end");
- vec = make_tree_vector ();
- VEC_safe_push (tree, gc, vec, range_temp);
- end_expr = perform_koenig_lookup (end_expr, vec,
- /*include_std=*/true);
- end_expr = finish_call_expr (end_expr, &vec, false, true,
- tf_warning_or_error);
- release_tree_vector (vec);
-
- /* The unqualified type of the __begin and __end temporaries should
- * be the same as required by the multiple auto declaration */
- iter_type = cv_unqualified (TREE_TYPE (begin_expr));
- if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr))))
- error ("inconsistent begin/end types in range-based for: %qT and %qT",
- TREE_TYPE (begin_expr), TREE_TYPE (end_expr));
- }
+ iter_type = cp_parser_perform_range_for_lookup (range_temp,
+ &begin_expr, &end_expr);
}
- /* The new for initialization statement */
+ /* The new for initialization statement. */
begin = build_decl (input_location, VAR_DECL,
get_identifier ("__for_begin"), iter_type);
TREE_USED (begin) = 1;
finish_for_init_stmt (statement);
-/* The new for condition */
+ /* The new for condition. */
condition = build_x_binary_op (NE_EXPR,
begin, ERROR_MARK,
end, ERROR_MARK,
NULL, tf_warning_or_error);
finish_for_cond (condition, statement);
- /* The new increment expression */
+ /* The new increment expression. */
expression = finish_unary_op_expr (PREINCREMENT_EXPR, begin);
finish_for_expr (expression, statement);
- /* The declaration is initialized with *__begin inside the loop body */
+ /* The declaration is initialized with *__begin inside the loop body. */
cp_finish_decl (range_decl,
build_x_indirect_ref (begin, RO_NULL, tf_warning_or_error),
/*is_constant_init*/false, NULL_TREE,
return statement;
}
+/* Solves BEGIN_EXPR and END_EXPR as described in cp_convert_range_for.
+ We need to solve both at the same time because the method used
+ depends on the existence of members begin or end.
+ Returns the type deduced for the iterator expression. */
+
+static tree
+cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
+{
+ if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (range))))
+ {
+ error ("range-based %<for%> expression of type %qT "
+ "has incomplete type", TREE_TYPE (range));
+ *begin = *end = error_mark_node;
+ return error_mark_node;
+ }
+ if (TREE_CODE (TREE_TYPE (range)) == ARRAY_TYPE)
+ {
+ /* If RANGE is an array, we will use pointer arithmetic. */
+ *begin = range;
+ *end = build_binary_op (input_location, PLUS_EXPR,
+ range,
+ array_type_nelts_top (TREE_TYPE (range)),
+ 0);
+ return build_pointer_type (TREE_TYPE (TREE_TYPE (range)));
+ }
+ else
+ {
+ /* If it is not an array, we must do a bit of magic. */
+ tree id_begin, id_end;
+ tree member_begin, member_end;
+
+ *begin = *end = error_mark_node;
+
+ id_begin = get_identifier ("begin");
+ id_end = get_identifier ("end");
+ member_begin = lookup_member (TREE_TYPE (range), id_begin,
+ /*protect=*/2, /*want_type=*/false);
+ member_end = lookup_member (TREE_TYPE (range), id_end,
+ /*protect=*/2, /*want_type=*/false);
+
+ if (member_begin != NULL_TREE || member_end != NULL_TREE)
+ {
+ /* Use the member functions. */
+ if (member_begin != NULL_TREE)
+ *begin = cp_parser_range_for_member_function (range, id_begin);
+ else
+ error ("range-based %<for%> expression of type %qT has an "
+ "%<end%> member but not a %<begin%>", TREE_TYPE (range));
+
+ if (member_end != NULL_TREE)
+ *end = cp_parser_range_for_member_function (range, id_end);
+ else
+ error ("range-based %<for%> expression of type %qT has a "
+ "%<begin%> member but not an %<end%>", TREE_TYPE (range));
+ }
+ else
+ {
+ /* Use global functions with ADL. */
+ VEC(tree,gc) *vec;
+ vec = make_tree_vector ();
+
+ VEC_safe_push (tree, gc, vec, range);
+
+ member_begin = perform_koenig_lookup (id_begin, vec,
+ /*include_std=*/true);
+ *begin = finish_call_expr (member_begin, &vec, false, true,
+ tf_warning_or_error);
+ member_end = perform_koenig_lookup (id_end, vec,
+ /*include_std=*/true);
+ *end = finish_call_expr (member_end, &vec, false, true,
+ tf_warning_or_error);
+
+ release_tree_vector (vec);
+ }
+
+ /* Last common checks. */
+ if (*begin == error_mark_node || *end == error_mark_node)
+ {
+ /* If one of the expressions is an error do no more checks. */
+ *begin = *end = error_mark_node;
+ return error_mark_node;
+ }
+ else
+ {
+ tree iter_type = cv_unqualified (TREE_TYPE (*begin));
+ /* The unqualified type of the __begin and __end temporaries should
+ be the same, as required by the multiple auto declaration. */
+ if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (*end))))
+ error ("inconsistent begin/end types in range-based %<for%> "
+ "statement: %qT and %qT",
+ TREE_TYPE (*begin), TREE_TYPE (*end));
+ return iter_type;
+ }
+ }
+}
+
+/* Helper function for cp_parser_perform_range_for_lookup.
+ Builds a tree for RANGE.IDENTIFIER(). */
+
+static tree
+cp_parser_range_for_member_function (tree range, tree identifier)
+{
+ tree member, res;
+ VEC(tree,gc) *vec;
+
+ member = finish_class_member_access_expr (range, identifier,
+ false, tf_warning_or_error);
+ if (member == error_mark_node)
+ return error_mark_node;
+
+ vec = make_tree_vector ();
+ res = finish_call_expr (member, &vec,
+ /*disallow_virtual=*/false,
+ /*koenig_p=*/false,
+ tf_warning_or_error);
+ release_tree_vector (vec);
+ return res;
+}
/* Parse an iteration-statement.
if (cxx_dialect < cxx0x)
{
error_at (cp_lexer_peek_token (parser->lexer)->location,
- "range-based-for loops are not allowed "
+ "range-based %<for%> loops are not allowed "
"in C++98 mode");
*decl = error_mark_node;
}
}
/* 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);
+ statement = cp_parser_compound_statement (parser, NULL, false, false);
/* If the token is not a `{', then we must take special action. */
else
{
return error_mark_node;
}
- return finish_decltype_type (expr, id_expression_or_member_access_p);
+ return finish_decltype_type (expr, id_expression_or_member_access_p,
+ tf_warning_or_error);
}
/* Special member functions [gram.special] */
cp_decl_specifier_seq decl_specifiers;
tree extension_specifier = NULL_TREE;
+ timevar_push (TV_TEMPLATE_INST);
+
/* Look for an (optional) storage-class-specifier or
function-specifier. */
if (cp_parser_allow_gnu_extensions_p (parser))
end_explicit_instantiation ();
cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ timevar_pop (TV_TEMPLATE_INST);
}
/* Parse an explicit-specialization.
decltype ( expression )
char16_t
char32_t
+ __underlying_type ( type-id )
GNU Extension:
return type;
+ case RID_UNDERLYING_TYPE:
+ type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
+
+ if (decl_specs)
+ cp_parser_set_decl_spec_type (decl_specs, type,
+ token->location,
+ /*user_defined_p=*/true);
+
+ return type;
+
default:
break;
}
elaborated-type-specifier. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
+ timevar_push (TV_PARSE_ENUM);
if (nested_name_specifier)
{
/* The following catches invalid code such as:
if (scoped_enum_p)
finish_scope ();
+ timevar_pop (TV_PARSE_ENUM);
}
else
{
bool is_non_constant_init;
int ctor_dtor_or_conv_p;
bool friend_p;
- tree pushed_scope = NULL;
+ tree pushed_scope = NULL_TREE;
bool range_for_decl_p = false;
/* Gather the attributes that were provided with the
if (pushed_scope)
{
pop_scope (pushed_scope);
- pushed_scope = false;
+ pushed_scope = NULL_TREE;
}
decl = grokfield (declarator, decl_specifiers,
initializer, !is_non_constant_init,
cp_parser_save_default_args (parser, decl);
}
- /* Finish processing the declaration. But, skip friend
+ /* Finish processing the declaration. But, skip member
declarations. */
- if (!friend_p && decl && decl != error_mark_node && !range_for_decl_p)
+ if (!member_p && decl && decl != error_mark_node && !range_for_decl_p)
{
cp_finish_decl (decl,
initializer, !is_non_constant_init,
if (member_p || cp_parser_parse_definitely (parser))
{
cp_cv_quals cv_quals;
+ cp_virt_specifiers virt_specifiers;
tree exception_specification;
tree late_return;
/* And the exception-specification. */
exception_specification
= cp_parser_exception_specification_opt (parser);
+ /* Parse the virt-specifier-seq. */
+ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
late_return
= cp_parser_late_return_type_opt (parser);
declarator = make_call_declarator (declarator,
params,
cv_quals,
+ virt_specifiers,
exception_specification,
late_return);
/* Any subsequent parameter lists are to do with
return cv_quals;
}
+/* Parse an (optional) virt-specifier-seq.
+
+ virt-specifier-seq:
+ virt-specifier virt-specifier-seq [opt]
+
+ virt-specifier:
+ override
+ final
+
+ Returns a bitmask representing the virt-specifiers. */
+
+static cp_virt_specifiers
+cp_parser_virt_specifier_seq_opt (cp_parser* parser)
+{
+ cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
+
+ while (true)
+ {
+ cp_token *token;
+ cp_virt_specifiers virt_specifier;
+
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* See if it's a virt-specifier-qualifier. */
+ if (token->type != CPP_NAME)
+ break;
+ if (!strcmp (IDENTIFIER_POINTER(token->u.value), "override"))
+ virt_specifier = VIRT_SPEC_OVERRIDE;
+ else if (!strcmp (IDENTIFIER_POINTER(token->u.value), "final"))
+ virt_specifier = VIRT_SPEC_FINAL;
+ else
+ break;
+
+ if (virt_specifiers & virt_specifier)
+ {
+ error_at (token->location, "duplicate virt-specifier");
+ cp_lexer_purge_token (parser->lexer);
+ }
+ else
+ {
+ cp_lexer_consume_token (parser->lexer);
+ virt_specifiers |= virt_specifier;
+ }
+ }
+ return virt_specifiers;
+}
+
/* Parse a late-specified return type, if any. This is not a separate
non-terminal, but part of a function declarator, which looks like
static tree cp_parser_template_type_arg (cp_parser *parser)
{
- return cp_parser_type_id_1 (parser, true, false);
+ tree r;
+ const char *saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in template arguments");
+ r = cp_parser_type_id_1 (parser, true, false);
+ parser->type_definition_forbidden_message = saved_message;
+ return r;
}
static tree cp_parser_trailing_type_id (cp_parser *parser)
static void
cp_parser_function_body (cp_parser *parser)
{
- cp_parser_compound_statement (parser, NULL, false);
+ cp_parser_compound_statement (parser, NULL, false, true);
}
/* Parse a ctor-initializer-opt followed by a function-body. Return
Returns the TREE_TYPE representing the class. */
static tree
-cp_parser_class_specifier (cp_parser* parser)
+cp_parser_class_specifier_1 (cp_parser* parser)
{
tree type;
tree attributes = NULL_TREE;
return type;
}
+static tree
+cp_parser_class_specifier (cp_parser* parser)
+{
+ tree ret;
+ timevar_push (TV_PARSE_STRUCT);
+ ret = cp_parser_class_specifier_1 (parser);
+ timevar_pop (TV_PARSE_STRUCT);
+ return ret;
+}
+
/* Parse a class-head.
class-head:
class-key identifier [opt] base-clause [opt]
- class-key nested-name-specifier identifier base-clause [opt]
+ class-key nested-name-specifier identifier class-virt-specifier [opt] base-clause [opt]
class-key nested-name-specifier [opt] template-id
base-clause [opt]
+ class-virt-specifier:
+ final
+
GNU Extensions:
class-key attributes identifier [opt] base-clause [opt]
class-key attributes nested-name-specifier identifier base-clause [opt]
tree id = NULL_TREE;
tree type = NULL_TREE;
tree attributes;
+ cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
bool template_id_p = false;
bool qualified_p = false;
bool invalid_nested_name_p = false;
pop_deferring_access_checks ();
if (id)
- cp_parser_check_for_invalid_template_id (parser, id,
- type_start_token->location);
+ {
+ cp_parser_check_for_invalid_template_id (parser, id,
+ type_start_token->location);
+ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
+ }
/* If it's not a `:' or a `{' then we can't really be looking at a
class-head, since a class-head only appears as part of a
/* At this point, we're going ahead with the class-specifier, even
if some other problem occurs. */
cp_parser_commit_to_tentative_parse (parser);
+ if (virt_specifiers & VIRT_SPEC_OVERRIDE)
+ {
+ cp_parser_error (parser,
+ "cannot specify %<override%> for a class");
+ type = error_mark_node;
+ goto out;
+ }
/* Issue the error about the overly-qualified name now. */
if (qualified_p)
{
if (type)
DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
*attributes_p = attributes;
+ if (type && (virt_specifiers & VIRT_SPEC_FINAL))
+ CLASSTYPE_FINAL (type) = 1;
out:
parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type;
cp_parser_require_keyword (parser, RID_TRY, RT_TRY);
try_block = begin_try_block ();
- cp_parser_compound_statement (parser, NULL, true);
+ cp_parser_compound_statement (parser, NULL, true, false);
finish_try_block (try_block);
cp_parser_handler_seq (parser);
finish_handler_sequence (try_block);
declaration = cp_parser_exception_declaration (parser);
finish_handler_parms (declaration, handler);
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
- cp_parser_compound_statement (parser, NULL, false);
+ cp_parser_compound_statement (parser, NULL, false, false);
finish_handler (handler);
}
pop_nested_class ();
}
else
- fn = cp_parser_function_definition_after_declarator (parser,
+ {
+ timevar_id_t tv;
+ if (DECL_DECLARED_INLINE_P (current_function_decl))
+ tv = TV_PARSE_INLINE;
+ else
+ tv = TV_PARSE_FUNC;
+ timevar_push (tv);
+ fn = cp_parser_function_definition_after_declarator (parser,
/*inline_p=*/false);
+ timevar_pop (tv);
+ }
return fn;
}
}
/* Complain about missing 'typename' or other invalid type names. */
- if (!decl_specifiers.any_type_specifiers_p)
- cp_parser_parse_and_diagnose_invalid_type_name (parser);
+ if (!decl_specifiers.any_type_specifiers_p
+ && cp_parser_parse_and_diagnose_invalid_type_name (parser))
+ {
+ /* cp_parser_parse_and_diagnose_invalid_type_name calls
+ cp_parser_skip_to_end_of_block_or_statement, so don't try to parse
+ the rest of this declaration. */
+ decl = error_mark_node;
+ goto out;
+ }
/* If it's not a template class, try for a template function. If
the next token is a `;', then this declaration does not declare
}
}
+ /* Look for a trailing `;' after the declaration. */
+ if (!function_definition_p
+ && (decl == error_mark_node
+ || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)))
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+
+ out:
pop_deferring_access_checks ();
/* Clear any current qualification; whatever comes next is the start
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
- /* Look for a trailing `;' after the declaration. */
- if (!function_definition_p
- && (decl == error_mark_node
- || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)))
- cp_parser_skip_to_end_of_block_or_statement (parser);
return decl;
}
CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1;
if (TREE_CODE (type) == TYPE_DECL)
type = TREE_TYPE (type);
- return finish_compound_literal (type, expression_list);
+ return finish_compound_literal (type, expression_list,
+ tf_warning_or_error);
}
static void
cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
{
+ timevar_push (TV_PARSE_INMETH);
/* If this member is a template, get the underlying
FUNCTION_DECL. */
if (DECL_FUNCTION_TEMPLATE_P (member_function))
/* Restore the queue. */
pop_unparsed_function_queues (parser);
+ timevar_pop (TV_PARSE_INMETH);
}
/* If DECL contains any default args, remember it on the unparsed
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
+ push_defarg_context (fn);
+
for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn)),
parmdecl = DECL_ARGUMENTS (fn);
parm && parm != void_list_node;
cp_parser_pop_lexer (parser);
}
+ pop_defarg_context ();
+
/* Make sure no default arg is missing. */
check_default_args (fn);
static void
cp_parser_abort_tentative_parse (cp_parser* parser)
{
+ gcc_assert (parser->context->status != CP_PARSER_STATUS_KIND_COMMITTED
+ || errorcount > 0);
cp_parser_simulate_error (parser);
/* Now, pretend that we want to see if the construct was
successfully parsed. */
messageargs = cp_parser_objc_message_args (parser);
cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
- return objc_build_message_expr (build_tree_list (receiver, messageargs));
+ return objc_build_message_expr (receiver, messageargs);
}
/* Parse an objc-message-receiver.
cp_parser_objc_class_declaration (cp_parser* parser)
{
cp_lexer_consume_token (parser->lexer); /* Eat '@class'. */
- objc_declare_class (cp_parser_objc_identifier_list (parser));
+ while (true)
+ {
+ tree id;
+
+ id = cp_parser_identifier (parser);
+ if (id == error_mark_node)
+ break;
+
+ objc_declare_class (id);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
token = cp_lexer_peek_token (parser->lexer);
continue;
}
- objc_start_method_definition (is_class_method, sig, attribute);
+ objc_start_method_definition (is_class_method, sig, attribute,
+ NULL_TREE);
/* For historical reasons, we accept an optional semicolon. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
tok = cp_lexer_peek_token (parser->lexer);
error_at (tok->location, "identifier expected after %<@protocol%>");
- goto finish;
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return;
}
/* See if we have a forward declaration or a definition. */
/* Try a forward declaration first. */
if (tok->type == CPP_COMMA || tok->type == CPP_SEMICOLON)
{
- objc_declare_protocols (cp_parser_objc_identifier_list (parser),
- attributes);
- finish:
+ while (true)
+ {
+ tree id;
+
+ id = cp_parser_identifier (parser);
+ if (id == error_mark_node)
+ break;
+
+ objc_declare_protocol (id, attributes);
+
+ if(cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
/* NB: The @try block needs to be wrapped in its own STATEMENT_LIST
node, lest it get absorbed into the surrounding block. */
stmt = push_stmt_list ();
- cp_parser_compound_statement (parser, NULL, false);
+ cp_parser_compound_statement (parser, NULL, false, false);
objc_begin_try_stmt (location, pop_stmt_list (stmt));
while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH))
forget about the closing parenthesis and keep going. */
}
objc_begin_catch_clause (parameter_declaration);
- cp_parser_compound_statement (parser, NULL, false);
+ cp_parser_compound_statement (parser, NULL, false, false);
objc_finish_catch_clause ();
}
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_FINALLY))
/* NB: The @finally block needs to be wrapped in its own STATEMENT_LIST
node, lest it get absorbed into the surrounding block. */
stmt = push_stmt_list ();
- cp_parser_compound_statement (parser, NULL, false);
+ cp_parser_compound_statement (parser, NULL, false, false);
objc_build_finally_clause (location, pop_stmt_list (stmt));
}
/* NB: The @synchronized block needs to be wrapped in its own STATEMENT_LIST
node, lest it get absorbed into the surrounding block. */
stmt = push_stmt_list ();
- cp_parser_compound_statement (parser, NULL, false);
+ cp_parser_compound_statement (parser, NULL, false, false);
return objc_build_synchronized (location, lock, pop_stmt_list (stmt));
}
/* If decl is an iterator, preserve the operator on decl
until finish_omp_for. */
if (decl
- && (type_dependent_expression_p (decl)
+ && ((type_dependent_expression_p (decl)
+ && !POINTER_TYPE_P (TREE_TYPE (decl)))
|| CLASS_TYPE_P (TREE_TYPE (decl))))
incr = cp_parser_omp_for_incr (parser, decl);
else