You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "toplev.h"
#include "output.h"
#include "target.h"
+#include "c-common.h"
\f
/* The lexer. */
/* We use a stack of token pointer for saving token sets. */
typedef struct cp_token *cp_token_position;
-DEF_VEC_MALLOC_P (cp_token_position);
+DEF_VEC_P (cp_token_position);
+DEF_VEC_ALLOC_P (cp_token_position,heap);
static const cp_token eof_token =
{
/* 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;
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) *GTY ((skip)) saved_tokens;
+ VEC(cp_token_position,heap) *GTY ((skip)) saved_tokens;
/* True if we should output debugging information. */
bool debugging_p;
/* Allocate the memory. */
lexer = GGC_CNEW (cp_lexer);
-#ifdef ENABLE_CHECKING
+#ifdef ENABLE_CHECKING
/* Initially we are not debugging. */
lexer->debugging_p = false;
#endif /* ENABLE_CHECKING */
- lexer->saved_tokens = VEC_alloc (cp_token_position, CP_SAVED_TOKEN_STACK);
-
+ lexer->saved_tokens = VEC_alloc (cp_token_position, heap,
+ CP_SAVED_TOKEN_STACK);
+
/* Create the buffer. */
alloc = CP_LEXER_BUFFER_SIZE;
buffer = ggc_alloc (alloc * sizeof (cp_token));
space = alloc;
pos = buffer;
*pos = first_token;
-
+
/* Get the remaining tokens from the preprocessor. */
while (pos->type != CPP_EOF)
{
lexer->buffer_length = 0;
lexer->next_token = first == last ? (cp_token *)&eof_token : first;
lexer->last_token = last;
-
- lexer->saved_tokens = VEC_alloc (cp_token_position, CP_SAVED_TOKEN_STACK);
+
+ lexer->saved_tokens = VEC_alloc (cp_token_position, heap,
+ CP_SAVED_TOKEN_STACK);
#ifdef ENABLE_CHECKING
/* Initially we are not debugging. */
{
if (lexer->buffer)
ggc_free (lexer->buffer);
- VEC_free (cp_token_position, lexer->saved_tokens);
+ VEC_free (cp_token_position, heap, lexer->saved_tokens);
ggc_free (lexer);
}
cp_lexer_token_position (cp_lexer *lexer, bool previous_p)
{
gcc_assert (!previous_p || lexer->next_token != &eof_token);
-
+
return lexer->next_token - previous_p;
}
static void
cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
- cp_token *token)
+ cp_token *token)
{
static int is_extern_c = 0;
/* Get a new token from the preprocessor. */
- token->type = c_lex_with_flags (&token->value, &token->flags);
- token->location = input_location;
+ token->type
+ = c_lex_with_flags (&token->value, &token->location, &token->flags);
token->in_system_header = in_system_header;
- /* On some systems, some header files are surrounded by an
+ /* On some systems, some header files are surrounded by an
implicit extern "C" block. Set a flag in the token if it
comes from such a header. */
is_extern_c += pending_lang_change;
mapped to `const'. */
token->value = ridpointers[token->keyword];
}
+ /* Handle Objective-C++ keywords. */
+ else if (token->type == CPP_AT_NAME)
+ {
+ token->type = CPP_KEYWORD;
+ switch (C_RID_CODE (token->value))
+ {
+ /* Map 'class' to '@class', 'private' to '@private', etc. */
+ case RID_CLASS: token->keyword = RID_AT_CLASS; break;
+ case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break;
+ case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break;
+ case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break;
+ case RID_THROW: token->keyword = RID_AT_THROW; break;
+ case RID_TRY: token->keyword = RID_AT_TRY; break;
+ case RID_CATCH: token->keyword = RID_AT_CATCH; break;
+ default: token->keyword = C_RID_CODE (token->value);
+ }
+ }
else
token->keyword = RID_MAX;
}
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;
token = (cp_token *)&eof_token;
break;
}
-
+
if (token->type != CPP_PURGED)
--n;
}
cp_token *token = lexer->next_token;
gcc_assert (token != &eof_token);
-
+
do
{
lexer->next_token++;
lexer->next_token = (cp_token *)&eof_token;
break;
}
-
+
}
while (lexer->next_token->type == CPP_PURGED);
-
+
cp_lexer_set_source_position_from_token (token);
-
+
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
{
cp_lexer_print_token (cp_lexer_debug_stream, token);
putc ('\n', cp_lexer_debug_stream);
}
-
+
return token;
}
cp_lexer_purge_token (cp_lexer *lexer)
{
cp_token *tok = lexer->next_token;
-
+
gcc_assert (tok != &eof_token);
tok->type = CPP_PURGED;
tok->location = UNKNOWN_LOCATION;
if (peek == &eof_token)
peek = lexer->last_token;
-
+
gcc_assert (tok < peek);
for ( tok += 1; tok != peek; tok += 1)
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: saving tokens\n");
- VEC_safe_push (cp_token_position, lexer->saved_tokens, lexer->next_token);
+ VEC_safe_push (cp_token_position, heap,
+ lexer->saved_tokens, lexer->next_token);
}
/* Commit to the portion of the token stream most recently saved. */
"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));
make_call_declarator (cp_declarator *target,
cp_parameter_declarator *parms,
cp_cv_quals cv_qualifiers,
- tree exception_specification)
+ tree exception_specification)
{
cp_declarator *declarator;
/* 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.
+ 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
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. */
+ and then decide not to consume it. */
tree scope;
/* OBJECT_SCOPE and QUALIFYING_SCOPE give the scopes in which the
/* 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);
static tree cp_parser_unqualified_id
static tree cp_parser_type_id
(cp_parser *);
static void cp_parser_type_specifier_seq
- (cp_parser *, cp_decl_specifier_seq *);
+ (cp_parser *, bool, cp_decl_specifier_seq *);
static cp_parameter_declarator *cp_parser_parameter_declaration_clause
(cp_parser *);
static cp_parameter_declarator *cp_parser_parameter_declaration_list
(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 *);
+/* Objective-C++ Productions */
+
+static tree cp_parser_objc_message_receiver
+ (cp_parser *);
+static tree cp_parser_objc_message_args
+ (cp_parser *);
+static tree cp_parser_objc_message_expression
+ (cp_parser *);
+static tree cp_parser_objc_encode_expression
+ (cp_parser *);
+static tree cp_parser_objc_defs_expression
+ (cp_parser *);
+static tree cp_parser_objc_protocol_expression
+ (cp_parser *);
+static tree cp_parser_objc_selector_expression
+ (cp_parser *);
+static tree cp_parser_objc_expression
+ (cp_parser *);
+static bool cp_parser_objc_selector_p
+ (enum cpp_ttype);
+static tree cp_parser_objc_selector
+ (cp_parser *);
+static tree cp_parser_objc_protocol_refs_opt
+ (cp_parser *);
+static void cp_parser_objc_declaration
+ (cp_parser *);
+static tree cp_parser_objc_statement
+ (cp_parser *);
+
/* Utility Routines */
static tree cp_parser_lookup_name
return token->keyword == keyword;
}
+/* A minimum or maximum operator has been seen. As these are
+ deprecated, issue a warning. */
+
+static inline void
+cp_parser_warn_min_max (void)
+{
+ if (warn_deprecated && !in_system_header)
+ warning (0, "minimum/maximum operators are deprecated");
+}
+
/* If not parsing tentatively, issue a diagnostic of the form
FILE:LINE: MESSAGE before TOKEN
where TOKEN is the next token in the input stream. MESSAGE
cp_lexer_set_source_position_from_token (token);
if (token->type == CPP_PRAGMA)
{
- error ("%<#pragma%> is not allowed here");
+ error ("%<#pragma%> is not allowed here");
cp_lexer_purge_token (parser->lexer);
return;
}
parser->scope, name);
else if (parser->scope == global_namespace)
error ("%<::%D%> has not been declared", name);
- else if (parser->object_scope
+ else if (parser->object_scope
&& !CLASS_TYPE_P (parser->object_scope))
error ("request for member %qD in non-class type %qT",
name, parser->object_scope);
else if (parser->object_scope)
- error ("%<%T::%D%> has not been declared",
+ error ("%<%T::%D%> has not been declared",
parser->object_scope, name);
else
error ("%qD has not been declared", name);
/* If parsing an integral constant-expression, issue an error message
about the fact that THING appeared and return true. Otherwise,
return false. In either case, set
- PARSER->NON_INTEGRAL_CONSTANT_EXPRESSION_P. */
+ PARSER->NON_INTEGRAL_CONSTANT_EXPRESSION_P. */
static bool
cp_parser_non_integral_constant_expression (cp_parser *parser,
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)
+ else if (!parser->scope || parser->scope == error_mark_node)
{
/* Issue an error message. */
error ("%qE does not name a type", id);
template <typename T> struct B : public A<T> { X x; };
The user should have said "typename A<T>::X". */
- if (processing_template_decl && current_class_type)
+ if (processing_template_decl && current_class_type
+ && TYPE_BINFO (current_class_type))
{
tree b;
&& DECL_NAME (field) == id)
{
inform ("(perhaps %<typename %T::%E%> was intended)",
- BINFO_TYPE (b), id);
+ BINFO_TYPE (b), id);
break;
}
if (field)
scanned, stop -- but only after consuming the token.
That way given:
- void f g () { ... }
+ void f g () { ... }
typedef int I;
we will stop after the body of the erroneously declared
static void
cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser)
{
- unsigned nesting_depth = 0;
+ int nesting_depth = 0;
- while (true)
+ while (nesting_depth >= 0)
{
- 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)
+
+ switch (token->type)
{
- /* Consume the `;'. */
- cp_lexer_consume_token (parser->lexer);
+ case CPP_EOF:
+ /* If we've run out of tokens, stop. */
+ nesting_depth = -1;
+ continue;
+
+ case CPP_SEMICOLON:
+ /* Stop if this is an unnested ';'. */
+ if (!nesting_depth)
+ nesting_depth = -1;
+ break;
+
+ case CPP_CLOSE_BRACE:
+ /* Stop if this is an unnested '}', or closes the outermost
+ nesting level. */
+ nesting_depth--;
+ if (!nesting_depth)
+ nesting_depth = -1;
+ break;
+
+ case CPP_OPEN_BRACE:
+ /* Nest. */
+ nesting_depth++;
+ break;
+
+ default:
break;
}
+
/* Consume the token. */
- token = cp_lexer_consume_token (parser->lexer);
- /* If the next token is a non-nested `}', then we have reached
- the end of the current block. */
- if (token->type == CPP_CLOSE_BRACE
- && (nesting_depth == 0 || --nesting_depth == 0))
- break;
- /* If it the next token is a `{', then we are entering a new
- block. Consume the entire block. */
- if (token->type == CPP_OPEN_BRACE)
- ++nesting_depth;
+ cp_lexer_consume_token (parser->lexer);
+
}
}
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))
{
- 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;
- }
+ /* 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_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);
( compound-statement )
__builtin_va_arg ( assignment-expression , type-id )
- literal:
- __null
+ Objective-C++ Extension:
- CAST_P is true if this primary expression is the target of a cast.
+ primary-expression:
+ objc-expression
- Returns a representation of the expression.
+ literal:
+ __null
- *IDK indicates what kind of id-expression (if any) was present.
+ 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 tempalte argument.
- *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;
}
checked at that point. If we are not within a cast, then
this code is invalid. */
if (!cast_p)
- cp_parser_non_integral_constant_expression
+ cp_parser_non_integral_constant_expression
(parser, "floating-point literal");
}
return token->value;
case CPP_STRING:
case CPP_WSTRING:
/* ??? Should wide strings be allowed when parser->translate_strings_p
- is false (i.e. in attributes)? If not, we can kill the third
+ is false (i.e. in attributes)? If not, we can kill the third
argument to cp_parser_string_literal. */
return cp_parser_string_literal (parser,
parser->translate_strings_p,
/* And they're not allowed outside of a function-body; you
cannot, for example, write:
- int i = ({ int j = 3; j + 1; });
+ int i = ({ int j = 3; j + 1; });
at class or namespace scope. */
if (!at_function_scope_p ())
case RID_OFFSETOF:
return cp_parser_builtin_offsetof (parser);
+ /* Objective-C++ expressions. */
+ case RID_AT_ENCODE:
+ case RID_AT_PROTOCOL:
+ case RID_AT_SELECTOR:
+ return cp_parser_objc_expression (parser);
+
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
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,
+ &template_p,
/*declarator_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
decl = cp_parser_lookup_name (parser, id_expression,
none_type,
- /*is_template=*/false,
+ template_p,
/*is_namespace=*/false,
/*check_dependency=*/true,
&ambiguous_p);
been issued. */
if (ambiguous_p)
return error_mark_node;
+
+ /* In Objective-C++, an instance variable (ivar) may be preferred
+ to whatever cp_parser_lookup_name() found. */
+ decl = objc_lookup_ivar (decl, id_expression);
+
/* If name lookup gives us a SCOPE_REF, then the
- qualifying scope was dependent. Just propagate the
- name. */
+ 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;
/* Anything else is an error. */
default:
+ /* ...unless we have an Objective-C++ message or string literal, that is. */
+ if (c_dialect_objc ()
+ && (token->type == CPP_OPEN_SQUARE || token->type == CPP_OBJC_STRING))
+ return cp_parser_objc_expression (parser);
+
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
/* 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
static tree
cp_parser_unqualified_id (cp_parser* parser,
- bool template_keyword_p,
+ bool template_keyword_p,
bool check_dependency_p,
bool declarator_p)
{
template <typename T> struct S { ~S (); };
template <typename T> S<T>::~S() {}
- is invalid, since `~' must be followed by a class-name, but
+ is invalid, since `~' must be followed by a class-name, but
`S<T>' is dependent, and so not known to be a class.
That's not right; we need to look in uninstantiated
templates. A further complication arises from:
Yet another issue is:
- struct S {
- int S;
- ~S();
- };
+ struct S {
+ int S;
+ ~S();
+ };
- S::~S() {}
+ S::~S() {}
- The standard does not seem to say that the `S' in `~S'
+ The standard does not seem to say that the `S' in `~S'
should refer to the type `S' and not the data member
`S::S'. */
look up names in "X<T>::I" in order to determine that "Y" is
a template. So, if we have a typename at this point, we make
an effort to look through it. */
- if (is_declaration
+ if (is_declaration
&& !typename_keyword_p
- && parser->scope
+ && parser->scope
&& TREE_CODE (parser->scope) == TYPENAME_TYPE)
- parser->scope = resolve_typename_type (parser->scope,
+ parser->scope = resolve_typename_type (parser->scope,
/*only_current_p=*/false);
/* Parse the qualifying entity. */
new_scope
}
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
if (success && start)
{
cp_token *token = cp_lexer_token_at (parser->lexer, start);
-
+
/* Reset the contents of the START token. */
token->type = CPP_NESTED_NAME_SPECIFIER;
token->value = build_tree_list (access_check, parser->scope);
TREE_TYPE (token->value) = parser->qualifying_scope;
token->keyword = RID_MAX;
-
+
/* Purge all subsequent tokens. */
cp_lexer_purge_tokens_after (parser->lexer, start);
}
/* Parse a nested-name-specifier. See
cp_parser_nested_name_specifier_opt for details. This function
behaves identically, except that it will an issue an error if no
- nested-name-specifier is present, and it will return
- ERROR_MARK_NODE, rather than NULL_TREE, if no nested-name-specifier
- is present. */
+ nested-name-specifier is present. */
static tree
cp_parser_nested_name_specifier (cp_parser *parser,
{
cp_parser_error (parser, "expected nested-name-specifier");
parser->scope = NULL_TREE;
- return error_mark_node;
}
return scope;
If ADDRESS_P is true, the postfix expression is the operand of the
`&' operator. CAST_P is true if this expression is the target of a
- cast.
+ cast.
Returns a representation of the expression. */
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);
bool template_p = false;
tree id;
tree type;
+ tree scope;
/* Consume the `typename' token. */
cp_lexer_consume_token (parser->lexer);
+
/* Look for the optional `::' operator. */
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
- /* Look for the nested-name-specifier. */
- cp_parser_nested_name_specifier (parser,
- /*typename_keyword_p=*/true,
- /*check_dependency_p=*/true,
- /*type_p=*/true,
- /*is_declaration=*/true);
+ /* Look for the nested-name-specifier. In case of error here,
+ consume the trailing id to avoid subsequent error messages
+ for usual cases. */
+ scope = cp_parser_nested_name_specifier (parser,
+ /*typename_keyword_p=*/true,
+ /*check_dependency_p=*/true,
+ /*type_p=*/true,
+ /*is_declaration=*/true);
+
/* Look for the optional `template' keyword. */
template_p = cp_parser_optional_template_keyword (parser);
/* We don't know whether we're looking at a template-id or an
/* If that didn't work, try an identifier. */
if (!cp_parser_parse_definitely (parser))
id = cp_parser_identifier (parser);
+
+ /* Don't process id if nested name specifier is invalid. */
+ if (!scope || scope == error_mark_node)
+ return error_mark_node;
/* If we look up a template-id in a non-dependent qualifying
scope, there's no need to create a dependent type. */
if (TREE_CODE (id) == TYPE_DECL
- && !dependent_type_p (parser->scope))
+ && (!TYPE_P (scope)
+ || !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. */
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)
{
/* postfix-expression ( expression-list [opt] ) */
{
bool koenig_p;
- tree args = (cp_parser_parenthesized_expression_list
- (parser, false,
- /*cast_p=*/false,
- /*non_constant_p=*/NULL));
+ bool is_builtin_constant_p;
+ bool saved_integral_constant_expression_p = false;
+ bool saved_non_integral_constant_expression_p = false;
+ tree args;
+
+ is_builtin_constant_p
+ = DECL_IS_BUILTIN_CONSTANT_P (postfix_expression);
+ if (is_builtin_constant_p)
+ {
+ /* The whole point of __builtin_constant_p is to allow
+ non-constant expressions to appear as arguments. */
+ saved_integral_constant_expression_p
+ = parser->integral_constant_expression_p;
+ saved_non_integral_constant_expression_p
+ = parser->non_integral_constant_expression_p;
+ parser->integral_constant_expression_p = false;
+ }
+ args = (cp_parser_parenthesized_expression_list
+ (parser, /*is_attribute_list=*/false,
+ /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
+ if (is_builtin_constant_p)
+ {
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
+ }
if (args == error_mark_node)
{
{
tree name;
bool dependent_p;
- bool template_p;
bool pseudo_destructor_p;
tree scope = NULL_TREE;
/* 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));
/* In general, build a SCOPE_REF if the member name is qualified.
However, if the name was not dependent and has already been
resolved; there is no need to build the SCOPE_REF. For example;
- struct X { void f(); };
- template <typename T> void f(T* t) { t->X::f(); }
+ struct X { void f(); };
+ template <typename T> void f(T* t) { t->X::f(); }
Even though "t" is dependent, "X::f" is not and has been resolved
to a BASELINK; there is no need to include scope information. */
{
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);
}
}
static void
cp_parser_pseudo_destructor_name (cp_parser* parser,
- tree* scope,
- tree* type)
+ tree* scope,
+ tree* type)
{
bool nested_name_specifier_p;
token = cp_lexer_consume_token (parser->lexer);
/* Parse the cast-expression. */
cast_expression
- = cp_parser_cast_expression (parser,
+ = cp_parser_cast_expression (parser,
unary_operator == ADDR_EXPR,
/*cast_p=*/false);
/* Now, build an appropriate representation. */
non_constant_p = (unary_operator == PREINCREMENT_EXPR
? "`++'" : "`--'");
/* Fall through. */
- case CONVERT_EXPR:
+ case UNARY_PLUS_EXPR:
case NEGATE_EXPR:
case TRUTH_NOT_EXPR:
expression = finish_unary_op_expr (unary_operator, cast_expression);
return ADDR_EXPR;
case CPP_PLUS:
- return CONVERT_EXPR;
+ return UNARY_PLUS_EXPR;
case CPP_MINUS:
return NEGATE_EXPR;
/* Look for the closing `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* There should not be a direct-new-declarator in this production,
- but GCC used to allowed this, so we check and emit a sensible error
+ but GCC used to allowed this, so we check and emit a sensible error
message for this case. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
{
parser->type_definition_forbidden_message
= "types may not be defined in a new-type-id";
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, &type_specifier_seq);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifier_seq);
/* Restore the old message. */
parser->type_definition_forbidden_message = saved_message;
/* Parse the new-declarator. */
*nelts = declarator->u.array.bounds;
if (*nelts == error_mark_node)
*nelts = integer_one_node;
-
+
if (outer_declarator)
outer_declarator->declarator = declarator->declarator;
else
if (!expression)
{
error ("expression in new-declarator must have integral "
- "or enumeration type");
+ "or enumeration type");
expression = error_mark_node;
}
}
parser->type_definition_forbidden_message = saved_message;
/* If ok so far, parse the dependent expression. We cannot be
- sure it is a cast. Consider `(T ())'. It is a parenthesized
- ctor of T, but looks like a cast to function returning T
- without a dependent expression. */
+ sure it is a cast. Consider `(T ())'. It is a parenthesized
+ ctor of T, but looks like a cast to function returning T
+ without a dependent expression. */
if (!cp_parser_error_occurred (parser))
- expr = cp_parser_cast_expression (parser,
+ expr = cp_parser_cast_expression (parser,
/*address_p=*/false,
/*cast_p=*/true);
&& !in_system_header
&& !VOID_TYPE_P (type)
&& current_lang_name != lang_name_c)
- warning ("use of old-style cast");
+ warning (0, "use of old-style cast");
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
relational-expression >= shift-expression
GNU Extension:
-
+
relational-expression:
relational-expression <? shift-expression
relational-expression >? shift-expression
{
/* Get an operator token. */
token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_MIN || token->type == CPP_MAX)
+ cp_parser_warn_min_max ();
+
new_prec = TOKEN_PRECEDENCE (token);
/* Popping an entry off the stack means we completed a subexpression:
- - either we found a token which is not an operator (`>' where it is not
- an operator, or prec == PREC_NOT_OPERATOR), in which case popping
- will happen repeatedly;
- - or, we found an operator which has lower priority. This is the case
- where the recursive descent *ascends*, as in `3 * 4 + 5' after
- parsing `3 * 4'. */
+ - either we found a token which is not an operator (`>' where it is not
+ an operator, or prec == PREC_NOT_OPERATOR), in which case popping
+ will happen repeatedly;
+ - or, we found an operator which has lower priority. This is the case
+ where the recursive descent *ascends*, as in `3 * 4 + 5' after
+ parsing `3 * 4'. */
if (new_prec <= prec)
- {
- if (sp == stack)
+ {
+ if (sp == stack)
break;
- else
+ else
goto pop;
- }
+ }
get_rhs:
tree_type = binops_by_token[token->type].tree_type;
cp_lexer_consume_token (parser->lexer);
/* Extract another operand. It may be the RHS of this expression
- or the LHS of a new, higher priority expression. */
+ or the LHS of a new, higher priority expression. */
rhs = cp_parser_simple_cast_expression (parser);
/* Get another operator token. Look up its precedence to avoid
- building a useless (immediately popped) stack entry for common
- cases such as 3 + 4 + 5 or 3 * 4 + 5. */
+ building a useless (immediately popped) stack entry for common
+ cases such as 3 + 4 + 5 or 3 * 4 + 5. */
token = cp_lexer_peek_token (parser->lexer);
lookahead_prec = TOKEN_PRECEDENCE (token);
if (lookahead_prec > new_prec)
- {
- /* ... and prepare to parse the RHS of the new, higher priority
- expression. Since precedence levels on the stack are
+ {
+ /* ... and prepare to parse the RHS of the new, higher priority
+ expression. Since precedence levels on the stack are
monotonically increasing, we do not have to care about
stack overflows. */
- sp->prec = prec;
- sp->tree_type = tree_type;
- sp->lhs = lhs;
- sp++;
- lhs = rhs;
- prec = new_prec;
- new_prec = lookahead_prec;
- goto get_rhs;
-
- pop:
- /* If the stack is not empty, we have parsed into LHS the right side
+ sp->prec = prec;
+ sp->tree_type = tree_type;
+ sp->lhs = lhs;
+ sp++;
+ lhs = rhs;
+ prec = new_prec;
+ new_prec = lookahead_prec;
+ goto get_rhs;
+
+ pop:
+ /* If the stack is not empty, we have parsed into LHS the right side
(`4' in the example above) of an expression we had suspended.
- We can use the information on the stack to recover the LHS (`3')
+ We can use the information on the stack to recover the LHS (`3')
from the stack together with the tree code (`MULT_EXPR'), and
the precedence of the higher level subexpression
(`PREC_ADDITIVE_EXPRESSION'). TOKEN is the CPP_PLUS token,
which will be used to actually build the additive expression. */
- --sp;
+ --sp;
prec = sp->prec;
- tree_type = sp->tree_type;
- rhs = lhs;
- lhs = sp->lhs;
- }
+ tree_type = sp->tree_type;
+ rhs = lhs;
+ lhs = sp->lhs;
+ }
overloaded_p = false;
lhs = build_x_binary_op (tree_type, lhs, rhs, &overloaded_p);
/* If the binary operator required the use of an overloaded operator,
- then this expression cannot be an integral constant-expression.
- An overloaded operator can be used even if both operands are
- otherwise permissible in an integral constant-expression if at
- least one of the operands is of enumeration type. */
+ then this expression cannot be an integral constant-expression.
+ An overloaded operator can be used even if both operands are
+ otherwise permissible in an integral constant-expression if at
+ least one of the operands is of enumeration type. */
if (overloaded_p
- && (cp_parser_non_integral_constant_expression
- (parser, "calls to overloaded operators")))
- return error_mark_node;
+ && (cp_parser_non_integral_constant_expression
+ (parser, "calls to overloaded operators")))
+ return error_mark_node;
}
return lhs;
case CPP_MIN_EQ:
op = MIN_EXPR;
+ cp_parser_warn_min_max ();
break;
case CPP_MAX_EQ:
op = MAX_EXPR;
+ cp_parser_warn_min_max ();
break;
default:
constant. */
expression = cp_parser_assignment_expression (parser, /*cast_p=*/false);
/* Restore the old settings. */
- parser->integral_constant_expression_p
+ parser->integral_constant_expression_p
= saved_integral_constant_expression_p;
parser->allow_non_integral_constant_expression_p
= saved_allow_non_integral_constant_expression_p;
*non_constant_p = parser->non_integral_constant_expression_p;
else if (parser->non_integral_constant_expression_p)
expression = error_mark_node;
- parser->non_integral_constant_expression_p
+ parser->non_integral_constant_expression_p
= saved_non_integral_constant_expression_p;
return expression;
statement = cp_parser_jump_statement (parser);
break;
+ /* Objective-C++ exception-handling constructs. */
+ case RID_AT_TRY:
+ case RID_AT_CATCH:
+ case RID_AT_FINALLY:
+ case RID_AT_SYNCHRONIZED:
+ case RID_AT_THROW:
+ statement = cp_parser_objc_statement (parser);
+ break;
+
case RID_TRY:
statement = cp_parser_try_block (parser);
break;
cp_lexer_handle_pragma (parser->lexer);
return;
}
+ else if (token->type == CPP_EOF)
+ {
+ cp_parser_error (parser, "expected statement");
+ return;
+ }
/* Everything else must be a declaration-statement or an
expression-statement. Try for the declaration-statement
ellipsis = cp_lexer_peek_token (parser->lexer);
if (ellipsis->type == CPP_ELLIPSIS)
{
- /* Consume the `...' token. */
+ /* Consume the `...' token. */
cp_lexer_consume_token (parser->lexer);
expr_hi =
cp_parser_constant_expression (parser,
- /*allow_non_constant_p=*/false,
+ /*allow_non_constant_p=*/false,
NULL);
/* We don't need to emit warnings here, as the common code
will do this for us. */
parser->type_definition_forbidden_message
= "types may not be defined in conditions";
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, &type_specifiers);
+ cp_parser_type_specifier_seq (parser, /*is_condition==*/true,
+ &type_specifiers);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
/* If all is well, we might be looking at a declaration. */
for sure. */
if (cp_parser_parse_definitely (parser))
{
- tree pushed_scope;
+ tree pushed_scope;
/* Create the declaration. */
decl = start_decl (declarator, &type_specifiers,
if (token1.type != CPP_EOF)
token2 = *cp_lexer_peek_nth_token (parser->lexer, 2);
+ else
+ token2.type = token2.keyword = RID_MAX;
/* Get the high-water mark for the DECLARATOR_OBSTACK. */
p = obstack_alloc (&declarator_obstack, 0);
/* An unnamed namespace definition. */
|| token2.type == CPP_OPEN_BRACE))
cp_parser_namespace_definition (parser);
+ /* Objective-C++ declaration/definition. */
+ else if (c_dialect_objc () && OBJC_IS_AT_KEYWORD (token1.keyword))
+ cp_parser_objc_declaration (parser);
/* We must have either a block declaration or a function
definition. */
else
static void
cp_parser_simple_declaration (cp_parser* parser,
- bool function_definition_allowed_p)
+ bool function_definition_allowed_p)
{
cp_decl_specifier_seq decl_specifiers;
int declares_class_or_enum;
/* Give up. */
goto done;
}
-
+
/* If we have seen at least one decl-specifier, and the next token
is not a parenthesis, then we must be looking at a declaration.
(After "int (" we might be looking at a functional cast.) */
- if (decl_specifiers.any_specifiers_p
+ if (decl_specifiers.any_specifiers_p
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
cp_parser_commit_to_tentative_parse (parser);
/* After the first time around, a function-definition is not
allowed -- even if it was OK at first. For example:
- int i, f() {}
+ int i, f() {}
- is not valid. */
+ is not valid. */
function_definition_allowed_p = false;
}
flags:
1: one of the decl-specifiers is an elaborated-type-specifier
- (i.e., a type declaration)
+ (i.e., a type declaration)
2: one of the decl-specifiers is an enum-specifier or a
- class-specifier (i.e., a type definition)
+ class-specifier (i.e., a type definition)
*/
extern
mutable
- GNU Extension:
+ GNU Extension:
thread */
case RID_AUTO:
/* Consume the token. */
conversion-type-id. For example, consider:
struct S {
- typedef int I;
+ typedef int I;
operator I();
};
/* Parse the attributes. */
attributes = cp_parser_attributes_opt (parser);
/* Parse the type-specifiers. */
- cp_parser_type_specifier_seq (parser, &type_specifiers);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifiers);
/* If that didn't work, stop. */
if (type_specifiers.type == error_mark_node)
return error_mark_node;
declarator = cp_parser_conversion_declarator_opt (parser);
type_specified = grokdeclarator (declarator, &type_specifiers, TYPENAME,
- /*initialized=*/0, &attributes);
+ /*initialized=*/0, &attributes);
if (attributes)
cplus_decl_attributes (&type_specified, attributes, /*flags=*/0);
return type_specified;
/* Extensions. */
case CPP_MIN:
id = ansi_opname (MIN_EXPR);
+ cp_parser_warn_min_max ();
break;
case CPP_MAX:
id = ansi_opname (MAX_EXPR);
+ cp_parser_warn_min_max ();
break;
case CPP_MIN_EQ:
id = ansi_assopname (MIN_EXPR);
+ cp_parser_warn_min_max ();
break;
case CPP_MAX_EQ:
id = ansi_assopname (MAX_EXPR);
+ cp_parser_warn_min_max ();
break;
default:
/* Consume the `export' token. */
cp_lexer_consume_token (parser->lexer);
/* Warn that we do not support `export'. */
- warning ("keyword %<export%> not implemented, and will be ignored");
+ warning (0, "keyword %<export%> not implemented, and will be ignored");
}
cp_parser_template_declaration_after_export (parser, member_p);
tree default_argument;
/* If the next token is an identifier, then it names the
- parameter. */
+ parameter. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
identifier = cp_parser_identifier (parser);
else
/* Change `:' into `::'. */
next_token_2->type = CPP_SCOPE;
/* Consume the first token (CPP_OPEN_SQUARE - which we pretend it is
- CPP_LESS. */
+ CPP_LESS. */
cp_lexer_consume_token (parser->lexer);
/* Parse the arguments. */
arguments = cp_parser_enclosed_template_argument_list (parser);
return error_mark_node;
}
/* Otherwise, emit an error about the invalid digraph, but continue
- parsing because we got our argument list. */
+ parsing because we got our argument list. */
pedwarn ("%<<::%> cannot begin a template-argument list");
inform ("%<<:%> is an alternate spelling for %<[%>. Insert whitespace "
"between %<<%> and %<::%>");
if (start_of_id)
{
cp_token *token = cp_lexer_token_at (parser->lexer, start_of_id);
-
+
/* Reset the contents of the START_OF_ID token. */
token->type = CPP_TEMPLATE_ID;
token->value = build_tree_list (access_check, template_id);
token->keyword = RID_MAX;
-
+
/* Purge all subsequent tokens. */
cp_lexer_purge_tokens_after (parser->lexer, start_of_id);
static tree
cp_parser_template_name (cp_parser* parser,
- bool template_keyword_p,
- bool check_dependency_p,
+ bool template_keyword_p,
+ bool check_dependency_p,
bool is_declaration,
bool *is_identifier)
{
identifier = cp_parser_operator_function_id (parser);
/* If that didn't work, try a conversion-function-id. */
if (!cp_parser_parse_definitely (parser))
- {
+ {
cp_parser_error (parser, "expected template-name");
return error_mark_node;
- }
+ }
}
/* Look for the identifier. */
else
&& !constructor_name_p (identifier, parser->scope))
{
cp_token_position start = 0;
-
+
/* Explain what went wrong. */
error ("non-template %qD used as template", identifier);
inform ("use %<%T::template %D%> to indicate that it is a template",
;
else
{
+ tree fn = NULL_TREE;
+
/* The standard does not explicitly indicate whether a name that
names a set of overloaded declarations, some of which are
templates, is a template-name. However, such a name should
template-id for the overloaded templates. */
fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;
if (TREE_CODE (fns) == OVERLOAD)
- {
- tree fn;
+ for (fn = fns; fn; fn = OVL_NEXT (fn))
+ if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
+ break;
- for (fn = fns; fn; fn = OVL_NEXT (fn))
- if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
- break;
- }
- else
+ if (!fn)
{
- /* Otherwise, the name does not name a template. */
+ /* The name does not name a template. */
cp_parser_error (parser, "expected template-name");
return error_mark_node;
}
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)
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.
in [temp.arg.nontype]:
-- an integral constant-expression of integral or enumeration
- type; or
+ type; or
-- the name of a non-type template-parameter; or
{
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);
gcc_assert (REFERENCE_REF_P (argument));
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
if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_BRACE
|| (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type
- == CPP_OPEN_BRACE))
+ == CPP_OPEN_BRACE))
{
if (parser->num_template_parameter_lists)
{
followed by a "<". That usually indicates that the user thought
that the type was a template. */
if (type && type != error_mark_node)
- cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type));
+ {
+ /* As a last-ditch effort, see if TYPE is an Objective-C type.
+ If it is, then the '<'...'>' enclose protocol names rather than
+ template arguments, and so everything is fine. */
+ if (c_dialect_objc ()
+ && (objc_is_id (type) || objc_is_class_name (type)))
+ {
+ tree protos = cp_parser_objc_protocol_refs_opt (parser);
+ tree qual_type = objc_get_protocol_qualified_type (type, protos);
+
+ /* Clobber the "unqualified" type previously entered into
+ DECL_SPECS with the new, improved protocol-qualified version. */
+ if (decl_specs)
+ decl_specs->type = qual_type;
+
+ return qual_type;
+ }
+
+ cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type));
+ }
return type;
}
/* Look up the type-name. */
type_decl = cp_parser_lookup_name_simple (parser, identifier);
+
+ if (TREE_CODE (type_decl) != TYPE_DECL
+ && (objc_is_id (identifier) || objc_is_class_name (identifier)))
+ {
+ /* See if this is an Objective-C type. */
+ tree protos = cp_parser_objc_protocol_refs_opt (parser);
+ tree type = objc_get_protocol_qualified_type (identifier, protos);
+ if (type)
+ type_decl = TYPE_NAME (type);
+ }
+
/* Issue an error if we did not find a type-name. */
if (TREE_CODE (type_decl) != TYPE_DECL)
{
elaborated-type-specifier:
class-key attributes :: [opt] nested-name-specifier [opt] identifier
class-key attributes :: [opt] nested-name-specifier [opt]
- template [opt] template-id
+ template [opt] template-id
enum attributes :: [opt] nested-name-specifier [opt] identifier
If IS_FRIEND is TRUE, then this elaborated-type-specifier is being
static tree
cp_parser_elaborated_type_specifier (cp_parser* parser,
- bool is_friend,
- bool is_declaration)
+ bool is_friend,
+ bool is_declaration)
{
enum tag_types tag_type;
tree identifier;
/* Look for the nested-name-specifier. */
if (tag_type == typename_type)
{
- if (cp_parser_nested_name_specifier (parser,
+ if (!cp_parser_nested_name_specifier (parser,
/*typename_keyword_p=*/true,
/*check_dependency_p=*/true,
/*type_p=*/true,
- is_declaration)
- == error_mark_node)
+ is_declaration))
return error_mark_node;
}
else
/* Allow the `template' keyword. */
template_p = cp_parser_optional_template_keyword (parser);
/* If we didn't see `template', we don't know if there's a
- template-id or not. */
+ template-id or not. */
if (!template_p)
cp_parser_parse_tentatively (parser);
/* Parse the template-id. */
/*check_dependency_p=*/true,
is_declaration);
/* If we didn't find a template-id, look for an ordinary
- identifier. */
+ identifier. */
if (!template_p && !cp_parser_parse_definitely (parser))
;
/* If DECL is a TEMPLATE_ID_EXPR, and the `typename' keyword is
}
/* For a `typename', we needn't call xref_tag. */
- if (tag_type == typename_type
+ if (tag_type == typename_type
&& TREE_CODE (parser->scope) != NAMESPACE_DECL)
return cp_parser_make_typename_type (parser, parser->scope,
identifier);
if (TREE_CODE (decl) != TYPE_DECL)
{
- cp_parser_diagnose_invalid_type_name (parser,
+ cp_parser_diagnose_invalid_type_name (parser,
parser->scope,
identifier);
return error_mark_node;
declaration context. */
tag_scope ts;
+ bool template_p;
+
if (is_friend)
/* Friends have special name lookup rules. */
ts = ts_within_enclosing_non_class;
else
ts = ts_global;
- /* Warn about attributes. They are ignored. */
- if (attributes)
- warning ("type attributes are honored only at type definition");
-
- type = xref_tag (tag_type, identifier, ts,
- parser->num_template_parameter_lists);
+ /* Warn about attributes. They are ignored. */
+ if (attributes)
+ warning (OPT_Wattributes,
+ "type attributes are honored only at type definition");
+
+ 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)));
+ type = xref_tag (tag_type, identifier, ts, template_p);
}
}
if (tag_type != enum_type)
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;
}
asm volatile [opt] ( string-literal ) ;
asm volatile [opt] ( string-literal : asm-operand-list [opt] ) ;
asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt] ) ;
+ : asm-operand-list [opt] ) ;
asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt]
- : asm-operand-list [opt] ) ; */
+ : asm-operand-list [opt]
+ : asm-operand-list [opt] ) ; */
static void
cp_parser_asm_definition (cp_parser* parser)
tree temp = asm_stmt;
if (TREE_CODE (temp) == CLEANUP_POINT_EXPR)
temp = TREE_OPERAND (temp, 0);
-
+
ASM_INPUT_P (temp) = 1;
}
}
attributes -- but ignores them. */
if (cp_parser_allow_gnu_extensions_p (parser) && is_parenthesized_init)
if (cp_parser_attributes_opt (parser))
- warning ("attributes after parenthesized initializer ignored");
+ warning (OPT_Wattributes,
+ "attributes after parenthesized initializer ignored");
/* For an in-class declaration, use `grokfield' to create the
declaration. */
}
decl = grokfield (declarator, decl_specifiers,
initializer, /*asmspec=*/NULL_TREE,
- /*attributes=*/NULL_TREE);
+ prefix_attributes);
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
}
expression, not a declaration.)
If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to true iff
- the declarator is a direct-declarator of the form "(...)".
+ the declarator is a direct-declarator of the form "(...)".
MEMBER_P is true iff this declarator is a member-declarator. */
static cp_declarator *
cp_parser_declarator (cp_parser* parser,
- cp_parser_declarator_kind dcl_kind,
- int* ctor_dtor_or_conv_p,
+ cp_parser_declarator_kind dcl_kind,
+ int* ctor_dtor_or_conv_p,
bool* parenthesized_p,
bool member_p)
{
static cp_declarator *
cp_parser_direct_declarator (cp_parser* parser,
- cp_parser_declarator_kind dcl_kind,
- int* ctor_dtor_or_conv_p,
+ cp_parser_declarator_kind dcl_kind,
+ int* ctor_dtor_or_conv_p,
bool member_p)
{
cp_token *token;
if (token->type == CPP_OPEN_PAREN)
{
/* This is either a parameter-declaration-clause, or a
- parenthesized declarator. When we know we are parsing a
- named declarator, it must be a parenthesized declarator
- if FIRST is true. For instance, `(int)' is a
- parameter-declaration-clause, with an omitted
- direct-abstract-declarator. But `((*))', is a
- parenthesized abstract declarator. Finally, when T is a
- template parameter `(T)' is a
- parameter-declaration-clause, and not a parenthesized
- named declarator.
+ parenthesized declarator. When we know we are parsing a
+ named declarator, it must be a parenthesized declarator
+ if FIRST is true. For instance, `(int)' is a
+ parameter-declaration-clause, with an omitted
+ direct-abstract-declarator. But `((*))', is a
+ parenthesized abstract declarator. Finally, when T is a
+ template parameter `(T)' is a
+ parameter-declaration-clause, and not a parenthesized
+ named declarator.
We first try and parse a parameter-declaration-clause,
and then try a nested declarator (if FIRST is true).
these two alternatives should be selected. Even more
complex are examples like:
- int i (int (a));
+ int i (int (a));
int i (int (3));
The former is a function-declaration; the latter is a
= saved_num_template_parameter_lists;
/* If all went well, parse the cv-qualifier-seq and the
- exception-specification. */
+ exception-specification. */
if (member_p || cp_parser_parse_definitely (parser))
{
cp_cv_quals cv_quals;
cv_quals,
exception_specification);
/* Any subsequent parameter lists are to do with
- return type, so are not those of the declared
- function. */
+ return type, so are not those of the declared
+ function. */
parser->default_arg_ok_p = false;
/* Repeat the main loop. */
bounds = fold_non_dependent_expr (bounds);
/* Normally, the array bound must be an integral constant
expression. However, as an extension, we allow VLAs
- in function scopes. */
+ in function scopes. */
else if (!at_function_scope_p ())
{
error ("array bound is not an integer constant");
if (!cp_parser_parse_definitely (parser))
unqualified_name = error_mark_node;
else if (qualifying_scope
- || (TREE_CODE (unqualified_name)
+ || (TREE_CODE (unqualified_name)
!= IDENTIFIER_NODE))
{
cp_parser_error (parser, "expected unqualified-id");
&& TREE_CODE (qualifying_scope) == TYPENAME_TYPE)
{
/* In the declaration of a member of a template class
- outside of the class itself, the SCOPE will sometimes
- be a TYPENAME_TYPE. For example, given:
+ outside of the class itself, the SCOPE will sometimes
+ be a TYPENAME_TYPE. For example, given:
- template <typename T>
- int S<T>::R::i = 3;
+ template <typename T>
+ int S<T>::R::i = 3;
- the SCOPE will be a TYPENAME_TYPE for `S<T>::R'. In
- this context, we must resolve S<T>::R to an ordinary
- type, rather than a typename type.
+ the SCOPE will be a TYPENAME_TYPE for `S<T>::R'. In
+ this context, we must resolve S<T>::R to an ordinary
+ type, rather than a typename type.
- The reason we normally avoid resolving TYPENAME_TYPEs
- is that a specialization of `S' might render
- `S<T>::R' not a type. However, if `S' is
- specialized, then this `i' will not be used, so there
- is no harm in resolving the types here. */
+ The reason we normally avoid resolving TYPENAME_TYPEs
+ is that a specialization of `S' might render
+ `S<T>::R' not a type. However, if `S' is
+ specialized, then this `i' will not be used, so there
+ is no harm in resolving the types here. */
tree type;
-
+
/* Resolve the TYPENAME_TYPE. */
type = resolve_typename_type (qualifying_scope,
/*only_current_p=*/false);
qualifying_scope = type;
}
- declarator = make_id_declarator (qualifying_scope,
+ declarator = make_id_declarator (qualifying_scope,
unqualified_name);
+ declarator->id_loc = token->location;
if (unqualified_name)
{
tree class_type;
&& (constructor_name_p (unqualified_name,
class_type)
|| (TREE_CODE (unqualified_name) == TYPE_DECL
- && (same_type_p
+ && (same_type_p
(TREE_TYPE (unqualified_name),
class_type)))))
declarator->u.id.sfk = sfk_constructor;
{
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,
+ "the constructor in a qualified name",
+ class_type,
DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
class_type, class_type);
}
static enum tree_code
cp_parser_ptr_operator (cp_parser* parser,
- tree* type,
+ tree* type,
cp_cv_quals *cv_quals)
{
enum tree_code code = ERROR_MARK;
cp_declarator *abstract_declarator;
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, &type_specifier_seq);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifier_seq);
if (type_specifier_seq.type == error_mark_node)
return error_mark_node;
type-specifier-seq:
attributes type-specifier-seq [opt]
+ If IS_CONDITION is true, we are at the start of a "condition",
+ e.g., we've just seen "if (".
+
Sets *TYPE_SPECIFIER_SEQ to represent the sequence. */
static void
cp_parser_type_specifier_seq (cp_parser* parser,
+ bool is_condition,
cp_decl_specifier_seq *type_specifier_seq)
{
bool seen_type_specifier = false;
+ cp_parser_flags flags = CP_PARSER_FLAGS_OPTIONAL;
/* Clear the TYPE_SPECIFIER_SEQ. */
clear_decl_specs (type_specifier_seq);
while (true)
{
tree type_specifier;
+ bool is_cv_qualifier;
/* Check for attributes first. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
/* Look for the type-specifier. */
type_specifier = cp_parser_type_specifier (parser,
- CP_PARSER_FLAGS_OPTIONAL,
+ flags,
type_specifier_seq,
/*is_declaration=*/false,
NULL,
- NULL);
- /* If the first type-specifier could not be found, this is not a
- type-specifier-seq at all. */
- if (!seen_type_specifier && !type_specifier)
+ &is_cv_qualifier);
+ if (!type_specifier)
{
- cp_parser_error (parser, "expected type-specifier");
- type_specifier_seq->type = error_mark_node;
- return;
+ /* If the first type-specifier could not be found, this is not a
+ type-specifier-seq at all. */
+ if (!seen_type_specifier)
+ {
+ cp_parser_error (parser, "expected type-specifier");
+ type_specifier_seq->type = error_mark_node;
+ return;
+ }
+ /* If subsequent type-specifiers could not be found, the
+ type-specifier-seq is complete. */
+ break;
}
- /* If subsequent type-specifiers could not be found, the
- type-specifier-seq is complete. */
- else if (seen_type_specifier && !type_specifier)
- break;
seen_type_specifier = true;
+ /* The standard says that a condition can be:
+
+ type-specifier-seq declarator = assignment-expression
+
+ However, given:
+
+ struct S {};
+ if (int S = ...)
+
+ we should treat the "S" as a declarator, not as a
+ type-specifier. The standard doesn't say that explicitly for
+ type-specifier-seq, but it does say that for
+ decl-specifier-seq in an ordinary declaration. Perhaps it
+ would be clearer just to allow a decl-specifier-seq here, and
+ then add a semantic restriction that if any decl-specifiers
+ that are not type-specifiers appear, the program is invalid. */
+ if (is_condition && !is_cv_qualifier)
+ flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
}
return;
/* Peek at the next token. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
- || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
+ /* These are for Objective-C++ */
+ || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+ || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
/* The parameter-declaration-list is complete. */
break;
else if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
/* When parsing something like:
- int i(float f, double d)
+ int i(float f, double d)
- we can tell after seeing the declaration for "f" that we
+ we can tell after seeing the declaration for "f" that we
are not looking at an initialization of a variable "i",
but rather at the declaration of a function "i".
}
/* Create a DEFAULT_ARG to represented the unparsed default
- argument. */
+ argument. */
default_argument = make_node (DEFAULT_ARG);
DEFARG_TOKENS (default_argument)
- = cp_token_cache_new (first_token, token);
+ = cp_token_cache_new (first_token, token);
+ DEFARG_INSTANTIATIONS (default_argument) = NULL;
}
/* Outside of a class definition, we can just parse the
- assignment-expression. */
+ assignment-expression. */
else
{
bool saved_local_variables_forbidden_p;
= parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
/* Parse the assignment-expression. */
- default_argument
+ default_argument
= cp_parser_assignment_expression (parser, /*cast_p=*/false);
/* Restore saved state. */
parser->greater_than_is_operator_p
if (!parser->default_arg_ok_p)
{
if (!flag_pedantic_errors)
- warning ("deprecated use of default argument for parameter of non-function");
+ warning (0, "deprecated use of default argument for parameter of non-function");
else
{
error ("default arguments are only permitted for function parameters");
= 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] */
class-specifier for that class. Consider:
struct A {
- struct B { void f() { sizeof (A); } };
+ struct B { void f() { sizeof (A); } };
};
If `f' were processed before the processing of `A' were
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:
struct S {
- void f() { g(); }
- void g(int i = 3);
- };
+ void f() { g(); }
+ void g(int i = 3);
+ };
- */
+ */
for (TREE_PURPOSE (parser->unparsed_functions_queues)
= nreverse (TREE_PURPOSE (parser->unparsed_functions_queues));
(queue_entry = TREE_PURPOSE (parser->unparsed_functions_queues));
{
/* 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--;
}
}
involving a nested-name-specifier was used, and FALSE otherwise.
Returns error_mark_node if this is not a class-head.
-
+
Returns NULL_TREE if the class-head is syntactically valid, but
semantically invalid in a way that means we should skip the entire
body of the class. */
It is OK to define an inaccessible class; for example:
- class A { class B; };
- class A::B {};
+ class A { class B; };
+ class A::B {};
- We do not know if we will see a class-name, or a
+ We do not know if we will see a class-name, or a
template-name. We look for a class-name first, in case the
class-name is a template-id; if we looked for the
template-name first we would stop after the template-name. */
if (scope && !is_ancestor (scope, nested_name_specifier))
{
error ("declaration of %qD in %qD which does not enclose %qD",
- type, scope, nested_name_specifier);
+ type, scope, nested_name_specifier);
type = NULL_TREE;
goto done;
}
/* [dcl.meaning]
- A declarator-id shall not be qualified exception of the
+ A declarator-id shall not be qualified exception of the
definition of a ... nested class outside of its class
... [or] a the definition or explicit instantiation of a
class member of a namespace outside of its namespace. */
goto done;
}
}
-
+
type = TREE_TYPE (type);
*nested_name_specifier_p = true;
}
if (type != error_mark_node && COMPLETE_TYPE_P (type))
{
error ("redefinition of %q#T", type);
- cp_error_at ("previous definition of %q#T", type);
- type = error_mark_node;
+ error ("previous definition of %q+#T", type);
+ type = NULL_TREE;
+ goto done;
}
/* We will have entered the scope containing the class; the names of
return;
}
+ /* Check for @defs. */
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_DEFS))
+ {
+ tree ivar, member;
+ tree ivar_chains = cp_parser_objc_defs_expression (parser);
+ ivar = ivar_chains;
+ while (ivar)
+ {
+ member = ivar;
+ ivar = TREE_CHAIN (member);
+ TREE_CHAIN (member) = NULL_TREE;
+ finish_member_declaration (member);
+ }
+ return;
+ }
+
/* Parse the decl-specifier-seq. */
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
/* In this case:
template <typename T> struct A {
- friend struct A<T>::B;
- };
+ friend struct A<T>::B;
+ };
A<T>::B will be represented by a TYPENAME_TYPE, and
therefore not recognized by check_tag_decl. */
= "types may not be defined in exception-declarations";
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, &type_specifiers);
+ cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+ &type_specifiers);
/* If it's a `)', then there is no declarator. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
declarator = NULL;
token = cp_lexer_consume_token (parser->lexer);
/* Save away the identifier that indicates which attribute
- this is. */
+ this is. */
identifier = token->value;
attribute = build_tree_list (identifier, NULL_TREE);
tree arguments;
arguments = (cp_parser_parenthesized_expression_list
- (parser, true, /*cast_p=*/false,
+ (parser, true, /*cast_p=*/false,
/*non_constant_p=*/NULL));
/* Save the identifier and arguments away. */
TREE_VALUE (attribute) = arguments;
/* Look for an identifier. */
identifier = cp_parser_identifier (parser);
- /* Declare it as a lobel. */
+ /* If we failed, stop. */
+ if (identifier == error_mark_node)
+ break;
+ /* Declare it as a label. */
finish_label_decl (identifier);
/* If the next token is a `;', stop. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
are ignored.
If CHECK_DEPENDENCY is TRUE, names are not looked up in dependent
- types.
+ types.
If AMBIGUOUS_P is non-NULL, it is set to true if name-lookup
results in an ambiguity, and false 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)
{
+ 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;
/*complain=*/1);
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);
else
- decl = build_nt (SCOPE_REF, parser->scope, name);
+ decl = build_qualified_name (/*type=*/NULL_TREE,
+ parser->scope, name,
+ is_template);
}
else
{
may be instantiated during name lookup. In that case,
errors may be issued. Even if we rollback the current
tentative parse, those errors are valid. */
- decl = lookup_qualified_name (parser->scope, name,
- tag_type != none_type,
+ decl = lookup_qualified_name (parser->scope, name,
+ tag_type != none_type,
/*complain=*/true);
if (pushed_scope)
pop_scope (pushed_scope);
parse, those errors are valid. */
object_decl = lookup_member (object_type,
name,
- /*protect=*/0,
+ /*protect=*/0,
tag_type != none_type);
/* Look it up in the enclosing context, too. */
- decl = lookup_name_real (name, tag_type != none_type,
+ 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)
}
else
{
- decl = lookup_name_real (name, tag_type != none_type,
+ 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 the lookup failed, let our caller know. */
- if (!decl
- || decl == error_mark_node
- || (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_ANTICIPATED (decl)))
+ if (!decl || decl == error_mark_node)
return error_mark_node;
/* If it's a TREE_LIST, the result of the lookup was ambiguous. */
the translation from TEMPLATE_DECL to TYPE_DECL occurs:
struct A {
- template <typename T> struct B;
+ template <typename T> struct B;
};
template <typename T> struct A::B {};
- Similarly, in a elaborated-type-specifier:
+ Similarly, in an elaborated-type-specifier:
namespace N { struct X{}; }
struct A {
- template <typename T> friend struct N::X;
+ template <typename T> friend struct N::X;
};
However, if the DECL refers to a class type, and we are in
than a TEMPLATE_DECL. For example, in:
template <class T> struct S {
- S s;
+ S s;
};
there is no need to handle such case. */
scope = TYPE_CONTEXT (scope);
}
}
- else if (TREE_CODE (declarator->u.id.unqualified_name)
+ else if (TREE_CODE (declarator->u.id.unqualified_name)
== TEMPLATE_ID_EXPR)
/* If the DECLARATOR has the form `X<y>' then it uses one
additional level of template parameters. */
static bool
cp_parser_check_template_parameters (cp_parser* parser,
- unsigned num_templates)
+ unsigned num_templates)
{
/* If there are more template classes than parameter lists, we have
something like:
else
{
/* There are no access checks when parsing a template, as we do not
- know if a specialization will be a friend. */
+ know if a specialization will be a friend. */
push_deferring_access_checks (dk_no_check);
decl = cp_parser_single_declaration (parser,
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;
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
parser->object_scope = saved_object_scope;
+ skip_evaluation = saved_skip_evaluation;
return arguments;
}
tokens = DECL_PENDING_INLINE_INFO (member_function);
DECL_PENDING_INLINE_INFO (member_function) = NULL;
DECL_PENDING_INLINE_P (member_function) = 0;
-
+
/* If this is a local class, enter the scope of the containing
function. */
function_scope = current_function_decl;
if (function_scope)
push_function_context_to (function_scope);
+
/* Push the body of the function onto the lexer stack. */
cp_parser_push_lexer_for_tokens (parser, tokens);
start_preparsed_function (member_function, NULL_TREE,
SF_PRE_PARSED | SF_INCLASS_INLINE);
+ /* Don't do access checking if it is a templated function. */
+ if (processing_template_decl)
+ push_deferring_access_checks (dk_no_check);
+
/* Now, parse the body of the function. */
cp_parser_function_definition_after_declarator (parser,
/*inline_p=*/true);
+ if (processing_template_decl)
+ pop_deferring_access_checks ();
+
/* Leave the scope of the containing function. */
if (function_scope)
pop_function_context_from (function_scope);
parm = TREE_CHAIN (parm))
{
cp_token_cache *tokens;
+ tree default_arg = TREE_PURPOSE (parm);
+ tree parsed_arg;
+ VEC(tree,gc) *insts;
+ tree copy;
+ unsigned ix;
+
+ if (!default_arg)
+ continue;
- if (!TREE_PURPOSE (parm)
- || TREE_CODE (TREE_PURPOSE (parm)) != DEFAULT_ARG)
+ if (TREE_CODE (default_arg) != DEFAULT_ARG)
+ /* This can happen for a friend declaration for a function
+ already declared with default arguments. */
continue;
/* Push the saved tokens for the default argument onto the parser's
lexer stack. */
- tokens = DEFARG_TOKENS (TREE_PURPOSE (parm));
+ tokens = DEFARG_TOKENS (default_arg);
cp_parser_push_lexer_for_tokens (parser, tokens);
/* Parse the assignment-expression. */
- TREE_PURPOSE (parm) = cp_parser_assignment_expression (parser,
- /*cast_p=*/false);
+ 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. */
+ for (insts = DEFARG_INSTANTIATIONS (default_arg), ix = 0;
+ VEC_iterate (tree, insts, ix, copy); ix++)
+ TREE_PURPOSE (copy) = parsed_arg;
/* If the token stream has not been completely used up, then
there was extra junk after the end of the default
/* The restrictions on constant-expressions do not apply inside
sizeof expressions. */
- saved_integral_constant_expression_p
+ saved_integral_constant_expression_p
= parser->integral_constant_expression_p;
saved_non_integral_constant_expression_p
= parser->non_integral_constant_expression_p;
free ((char *) parser->type_definition_forbidden_message);
/* And restore the old one. */
parser->type_definition_forbidden_message = saved_message;
- parser->integral_constant_expression_p
+ parser->integral_constant_expression_p
= saved_integral_constant_expression_p;
parser->non_integral_constant_expression_p
= saved_non_integral_constant_expression_p;
static cp_token *
cp_parser_require (cp_parser* parser,
- enum cpp_ttype type,
- const char* token_desc)
+ enum cpp_ttype type,
+ const char* token_desc)
{
if (cp_lexer_next_token_is (parser->lexer, type))
return cp_lexer_consume_token (parser->lexer);
static void
cp_parser_skip_until_found (cp_parser* parser,
- enum cpp_ttype type,
- const char* token_desc)
+ enum cpp_ttype type,
+ const char* token_desc)
{
cp_token *token;
unsigned nesting_depth = 0;
static cp_token *
cp_parser_require_keyword (cp_parser* parser,
- enum rid keyword,
- const char* token_desc)
+ enum rid keyword,
+ const char* token_desc)
{
cp_token *token = cp_parser_require (parser, CPP_KEYWORD, token_desc);
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
{
return parser->allow_gnu_extensions_p;
}
+\f
+/* Objective-C++ Productions */
+
+
+/* Parse an Objective-C expression, which feeds into a primary-expression
+ above.
+
+ objc-expression:
+ objc-message-expression
+ objc-string-literal
+ objc-encode-expression
+ objc-protocol-expression
+ objc-selector-expression
+
+ Returns a tree representation of the expression. */
+
+static tree
+cp_parser_objc_expression (cp_parser* parser)
+{
+ /* Try to figure out what kind of declaration is present. */
+ cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+
+ switch (kwd->type)
+ {
+ case CPP_OPEN_SQUARE:
+ return cp_parser_objc_message_expression (parser);
+
+ case CPP_OBJC_STRING:
+ kwd = cp_lexer_consume_token (parser->lexer);
+ return objc_build_string_object (kwd->value);
+
+ case CPP_KEYWORD:
+ switch (kwd->keyword)
+ {
+ case RID_AT_ENCODE:
+ return cp_parser_objc_encode_expression (parser);
+
+ case RID_AT_PROTOCOL:
+ return cp_parser_objc_protocol_expression (parser);
+
+ case RID_AT_SELECTOR:
+ return cp_parser_objc_selector_expression (parser);
+
+ default:
+ break;
+ }
+ default:
+ error ("misplaced %<@%D%> Objective-C++ construct", kwd->value);
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ }
+
+ return error_mark_node;
+}
+
+/* Parse an Objective-C message expression.
+
+ objc-message-expression:
+ [ objc-message-receiver objc-message-args ]
+
+ Returns a representation of an Objective-C message. */
+
+static tree
+cp_parser_objc_message_expression (cp_parser* parser)
+{
+ tree receiver, messageargs;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '['. */
+ receiver = cp_parser_objc_message_receiver (parser);
+ messageargs = cp_parser_objc_message_args (parser);
+ cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+
+ return objc_build_message_expr (build_tree_list (receiver, messageargs));
+}
+
+/* Parse an objc-message-receiver.
+
+ objc-message-receiver:
+ expression
+ simple-type-specifier
+
+ Returns a representation of the type or expression. */
+
+static tree
+cp_parser_objc_message_receiver (cp_parser* parser)
+{
+ tree rcv;
+
+ /* An Objective-C message receiver may be either (1) a type
+ or (2) an expression. */
+ cp_parser_parse_tentatively (parser);
+ rcv = cp_parser_expression (parser, false);
+
+ if (cp_parser_parse_definitely (parser))
+ return rcv;
+
+ rcv = cp_parser_simple_type_specifier (parser,
+ /*decl_specs=*/NULL,
+ CP_PARSER_FLAGS_NONE);
+
+ return objc_get_class_reference (rcv);
+}
+
+/* Parse the arguments and selectors comprising an Objective-C message.
+
+ objc-message-args:
+ objc-selector
+ objc-selector-args
+ objc-selector-args , objc-comma-args
+
+ objc-selector-args:
+ objc-selector [opt] : assignment-expression
+ objc-selector-args objc-selector [opt] : assignment-expression
+
+ objc-comma-args:
+ assignment-expression
+ objc-comma-args , assignment-expression
+
+ Returns a TREE_LIST, with TREE_PURPOSE containing a list of
+ selector arguments and TREE_VALUE containing a list of comma
+ arguments. */
+
+static tree
+cp_parser_objc_message_args (cp_parser* parser)
+{
+ tree sel_args = NULL_TREE, addl_args = NULL_TREE;
+ bool maybe_unary_selector_p = true;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
+ {
+ tree selector = NULL_TREE, arg;
+
+ if (token->type != CPP_COLON)
+ selector = cp_parser_objc_selector (parser);
+
+ /* Detect if we have a unary selector. */
+ if (maybe_unary_selector_p
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+ return build_tree_list (selector, NULL_TREE);
+
+ maybe_unary_selector_p = false;
+ cp_parser_require (parser, CPP_COLON, "`:'");
+ arg = cp_parser_assignment_expression (parser, false);
+
+ sel_args
+ = chainon (sel_args,
+ build_tree_list (selector, arg));
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ /* Handle non-selector arguments, if any. */
+ while (token->type == CPP_COMMA)
+ {
+ tree arg;
+
+ cp_lexer_consume_token (parser->lexer);
+ arg = cp_parser_assignment_expression (parser, false);
+
+ addl_args
+ = chainon (addl_args,
+ build_tree_list (NULL_TREE, arg));
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ return build_tree_list (sel_args, addl_args);
+}
+
+/* Parse an Objective-C encode expression.
+
+ objc-encode-expression:
+ @encode objc-typename
+
+ Returns an encoded representation of the type argument. */
+
+static tree
+cp_parser_objc_encode_expression (cp_parser* parser)
+{
+ tree type;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@encode'. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ type = complete_type (cp_parser_type_id (parser));
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ if (!type)
+ {
+ error ("%<@encode%> must specify a type as an argument");
+ return error_mark_node;
+ }
+
+ return objc_build_encode_expr (type);
+}
+
+/* Parse an Objective-C @defs expression. */
+
+static tree
+cp_parser_objc_defs_expression (cp_parser *parser)
+{
+ tree name;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@defs'. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ name = cp_parser_identifier (parser);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ return objc_get_class_ivars (name);
+}
+
+/* Parse an Objective-C protocol expression.
+
+ objc-protocol-expression:
+ @protocol ( identifier )
+
+ Returns a representation of the protocol expression. */
+
+static tree
+cp_parser_objc_protocol_expression (cp_parser* parser)
+{
+ tree proto;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@protocol'. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ proto = cp_parser_identifier (parser);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ return objc_build_protocol_expr (proto);
+}
+
+/* Parse an Objective-C selector expression.
+
+ objc-selector-expression:
+ @selector ( objc-method-signature )
+
+ objc-method-signature:
+ objc-selector
+ objc-selector-seq
+
+ objc-selector-seq:
+ objc-selector :
+ objc-selector-seq objc-selector :
+
+ Returns a representation of the method selector. */
+
+static tree
+cp_parser_objc_selector_expression (cp_parser* parser)
+{
+ tree sel_seq = NULL_TREE;
+ bool maybe_unary_selector_p = true;
+ cp_token *token;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@selector'. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ token = cp_lexer_peek_token (parser->lexer);
+
+ while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON
+ || token->type == CPP_SCOPE)
+ {
+ tree selector = NULL_TREE;
+
+ if (token->type != CPP_COLON
+ || token->type == CPP_SCOPE)
+ selector = cp_parser_objc_selector (parser);
+
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE))
+ {
+ /* 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;
+ 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);
+ }
+
+ finish_selector:
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ return objc_build_selector_expr (sel_seq);
+}
+
+/* Parse a list of identifiers.
+
+ objc-identifier-list:
+ identifier
+ objc-identifier-list , identifier
+
+ Returns a TREE_LIST of identifier nodes. */
+
+static tree
+cp_parser_objc_identifier_list (cp_parser* parser)
+{
+ tree list = build_tree_list (NULL_TREE, cp_parser_identifier (parser));
+ cp_token *sep = cp_lexer_peek_token (parser->lexer);
+
+ while (sep->type == CPP_COMMA)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat ','. */
+ list = chainon (list,
+ build_tree_list (NULL_TREE,
+ cp_parser_identifier (parser)));
+ sep = cp_lexer_peek_token (parser->lexer);
+ }
+
+ return list;
+}
+
+/* Parse an Objective-C alias declaration.
+
+ objc-alias-declaration:
+ @compatibility_alias identifier identifier ;
+
+ This function registers the alias mapping with the Objective-C front-end.
+ It returns nothing. */
+
+static void
+cp_parser_objc_alias_declaration (cp_parser* parser)
+{
+ tree alias, orig;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@compatibility_alias'. */
+ alias = cp_parser_identifier (parser);
+ orig = cp_parser_identifier (parser);
+ objc_declare_alias (alias, orig);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+}
+
+/* Parse an Objective-C class forward-declaration.
+
+ objc-class-declaration:
+ @class objc-identifier-list ;
+
+ The function registers the forward declarations with the Objective-C
+ front-end. It returns nothing. */
+
+static void
+cp_parser_objc_class_declaration (cp_parser* parser)
+{
+ cp_lexer_consume_token (parser->lexer); /* Eat '@class'. */
+ objc_declare_class (cp_parser_objc_identifier_list (parser));
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+}
+
+/* Parse a list of Objective-C protocol references.
+
+ objc-protocol-refs-opt:
+ objc-protocol-refs [opt]
+
+ objc-protocol-refs:
+ < objc-identifier-list >
+
+ Returns a TREE_LIST of identifiers, if any. */
+
+static tree
+cp_parser_objc_protocol_refs_opt (cp_parser* parser)
+{
+ tree protorefs = NULL_TREE;
+
+ if(cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat '<'. */
+ protorefs = cp_parser_objc_identifier_list (parser);
+ cp_parser_require (parser, CPP_GREATER, "`>'");
+ }
+
+ return protorefs;
+}
+
+/* Parse a Objective-C visibility specification. */
+
+static void
+cp_parser_objc_visibility_spec (cp_parser* parser)
+{
+ cp_token *vis = cp_lexer_peek_token (parser->lexer);
+
+ switch (vis->keyword)
+ {
+ case RID_AT_PRIVATE:
+ objc_set_visibility (2);
+ break;
+ case RID_AT_PROTECTED:
+ objc_set_visibility (0);
+ break;
+ case RID_AT_PUBLIC:
+ objc_set_visibility (1);
+ break;
+ default:
+ return;
+ }
+
+ /* Eat '@private'/'@protected'/'@public'. */
+ cp_lexer_consume_token (parser->lexer);
+}
+
+/* Parse an Objective-C method type. */
+
+static void
+cp_parser_objc_method_type (cp_parser* parser)
+{
+ objc_set_method_type
+ (cp_lexer_consume_token (parser->lexer)->type == CPP_PLUS
+ ? PLUS_EXPR
+ : MINUS_EXPR);
+}
+
+/* Parse an Objective-C protocol qualifier. */
+
+static tree
+cp_parser_objc_protocol_qualifiers (cp_parser* parser)
+{
+ tree quals = NULL_TREE, node;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ node = token->value;
+
+ while (node && TREE_CODE (node) == IDENTIFIER_NODE
+ && (node == ridpointers [(int) RID_IN]
+ || node == ridpointers [(int) RID_OUT]
+ || node == ridpointers [(int) RID_INOUT]
+ || node == ridpointers [(int) RID_BYCOPY]
+ || node == ridpointers [(int) RID_BYREF]
+ || node == ridpointers [(int) RID_ONEWAY]))
+ {
+ quals = tree_cons (NULL_TREE, node, quals);
+ cp_lexer_consume_token (parser->lexer);
+ token = cp_lexer_peek_token (parser->lexer);
+ node = token->value;
+ }
+
+ return quals;
+}
+
+/* Parse an Objective-C typename. */
+
+static tree
+cp_parser_objc_typename (cp_parser* parser)
+{
+ tree typename = NULL_TREE;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ tree proto_quals, cp_type = NULL_TREE;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '('. */
+ proto_quals = cp_parser_objc_protocol_qualifiers (parser);
+ /* An ObjC type name may consist of just protocol qualifiers, in which
+ case the type shall default to 'id'. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+ cp_type = cp_parser_type_id (parser);
+
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ typename = build_tree_list (proto_quals, cp_type);
+ }
+
+ return typename;
+}
+
+/* Check to see if TYPE refers to an Objective-C selector name. */
+
+static bool
+cp_parser_objc_selector_p (enum cpp_ttype type)
+{
+ return (type == CPP_NAME || type == CPP_KEYWORD
+ || type == CPP_AND_AND || type == CPP_AND_EQ || type == CPP_AND
+ || type == CPP_OR || type == CPP_COMPL || type == CPP_NOT
+ || type == CPP_NOT_EQ || type == CPP_OR_OR || type == CPP_OR_EQ
+ || type == CPP_XOR || type == CPP_XOR_EQ);
+}
+
+/* Parse an Objective-C selector. */
+
+static tree
+cp_parser_objc_selector (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_consume_token (parser->lexer);
+
+ if (!cp_parser_objc_selector_p (token->type))
+ {
+ error ("invalid Objective-C++ selector name");
+ return error_mark_node;
+ }
+
+ /* C++ operator names are allowed to appear in ObjC selectors. */
+ switch (token->type)
+ {
+ case CPP_AND_AND: return get_identifier ("and");
+ case CPP_AND_EQ: return get_identifier ("and_eq");
+ case CPP_AND: return get_identifier ("bitand");
+ case CPP_OR: return get_identifier ("bitor");
+ case CPP_COMPL: return get_identifier ("compl");
+ case CPP_NOT: return get_identifier ("not");
+ case CPP_NOT_EQ: return get_identifier ("not_eq");
+ case CPP_OR_OR: return get_identifier ("or");
+ case CPP_OR_EQ: return get_identifier ("or_eq");
+ case CPP_XOR: return get_identifier ("xor");
+ case CPP_XOR_EQ: return get_identifier ("xor_eq");
+ default: return token->value;
+ }
+}
+
+/* Parse an Objective-C params list. */
+
+static tree
+cp_parser_objc_method_keyword_params (cp_parser* parser)
+{
+ tree params = NULL_TREE;
+ bool maybe_unary_selector_p = true;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
+ {
+ tree selector = NULL_TREE, typename, identifier;
+
+ if (token->type != CPP_COLON)
+ selector = cp_parser_objc_selector (parser);
+
+ /* Detect if we have a unary selector. */
+ if (maybe_unary_selector_p
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+ return selector;
+
+ maybe_unary_selector_p = false;
+ cp_parser_require (parser, CPP_COLON, "`:'");
+ typename = cp_parser_objc_typename (parser);
+ identifier = cp_parser_identifier (parser);
+
+ params
+ = chainon (params,
+ objc_build_keyword_decl (selector,
+ typename,
+ identifier));
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ return params;
+}
+
+/* Parse the non-keyword Objective-C params. */
+
+static tree
+cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp)
+{
+ tree params = make_node (TREE_LIST);
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ *ellipsisp = false; /* Initially, assume no ellipsis. */
+
+ while (token->type == CPP_COMMA)
+ {
+ cp_parameter_declarator *parmdecl;
+ tree parm;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat ','. */
+ token = cp_lexer_peek_token (parser->lexer);
+
+ if (token->type == CPP_ELLIPSIS)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat '...'. */
+ *ellipsisp = true;
+ break;
+ }
+
+ parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
+ parm = grokdeclarator (parmdecl->declarator,
+ &parmdecl->decl_specifiers,
+ PARM, /*initialized=*/0,
+ /*attrlist=*/NULL);
+
+ chainon (params, build_tree_list (NULL_TREE, parm));
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ return params;
+}
+
+/* Parse a linkage specification, a pragma, an extra semicolon or a block. */
+
+static void
+cp_parser_objc_interstitial_code (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ /* If the next token is `extern' and the following token is a string
+ literal, then we have a linkage specification. */
+ if (token->keyword == RID_EXTERN
+ && cp_parser_is_string_literal (cp_lexer_peek_nth_token (parser->lexer, 2)))
+ cp_parser_linkage_specification (parser);
+ /* Handle #pragma, if any. */
+ else if (token->type == CPP_PRAGMA)
+ cp_lexer_handle_pragma (parser->lexer);
+ /* Allow stray semicolons. */
+ else if (token->type == CPP_SEMICOLON)
+ cp_lexer_consume_token (parser->lexer);
+ /* Finally, try to parse a block-declaration, or a function-definition. */
+ else
+ cp_parser_block_declaration (parser, /*statement_p=*/false);
+}
+
+/* Parse a method signature. */
+
+static tree
+cp_parser_objc_method_signature (cp_parser* parser)
+{
+ tree rettype, kwdparms, optparms;
+ bool ellipsis = false;
+
+ cp_parser_objc_method_type (parser);
+ rettype = cp_parser_objc_typename (parser);
+ kwdparms = cp_parser_objc_method_keyword_params (parser);
+ optparms = cp_parser_objc_method_tail_params_opt (parser, &ellipsis);
+
+ return objc_build_method_signature (rettype, kwdparms, optparms, ellipsis);
+}
+
+/* Pars an Objective-C method prototype list. */
+
+static void
+cp_parser_objc_method_prototype_list (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ while (token->keyword != RID_AT_END)
+ {
+ if (token->type == CPP_PLUS || token->type == CPP_MINUS)
+ {
+ objc_add_method_declaration
+ (cp_parser_objc_method_signature (parser));
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ }
+ else
+ /* Allow for interspersed non-ObjC++ code. */
+ cp_parser_objc_interstitial_code (parser);
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@end'. */
+ objc_finish_interface ();
+}
+
+/* Parse an Objective-C method definition list. */
+
+static void
+cp_parser_objc_method_definition_list (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ while (token->keyword != RID_AT_END)
+ {
+ tree meth;
+
+ if (token->type == CPP_PLUS || token->type == CPP_MINUS)
+ {
+ push_deferring_access_checks (dk_deferred);
+ objc_start_method_definition
+ (cp_parser_objc_method_signature (parser));
+
+ /* For historical reasons, we accept an optional semicolon. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
+
+ perform_deferred_access_checks ();
+ stop_deferring_access_checks ();
+ meth = cp_parser_function_definition_after_declarator (parser,
+ false);
+ pop_deferring_access_checks ();
+ objc_finish_method_definition (meth);
+ }
+ else
+ /* Allow for interspersed non-ObjC++ code. */
+ cp_parser_objc_interstitial_code (parser);
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@end'. */
+ objc_finish_implementation ();
+}
+
+/* Parse Objective-C ivars. */
+
+static void
+cp_parser_objc_class_ivars (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ if (token->type != CPP_OPEN_BRACE)
+ return; /* No ivars specified. */
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '{'. */
+ token = cp_lexer_peek_token (parser->lexer);
+
+ while (token->type != CPP_CLOSE_BRACE)
+ {
+ cp_decl_specifier_seq declspecs;
+ int decl_class_or_enum_p;
+ tree prefix_attributes;
+
+ cp_parser_objc_visibility_spec (parser);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ break;
+
+ cp_parser_decl_specifier_seq (parser,
+ CP_PARSER_FLAGS_OPTIONAL,
+ &declspecs,
+ &decl_class_or_enum_p);
+ prefix_attributes = declspecs.attributes;
+ declspecs.attributes = NULL_TREE;
+
+ /* Keep going until we hit the `;' at the end of the
+ declaration. */
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ {
+ tree width = NULL_TREE, attributes, first_attribute, decl;
+ cp_declarator *declarator = NULL;
+ int ctor_dtor_or_conv_p;
+
+ /* Check for a (possibly unnamed) bitfield declaration. */
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_COLON)
+ goto eat_colon;
+
+ if (token->type == CPP_NAME
+ && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
+ == CPP_COLON))
+ {
+ /* Get the name of the bitfield. */
+ declarator = make_id_declarator (NULL_TREE,
+ cp_parser_identifier (parser));
+
+ eat_colon:
+ cp_lexer_consume_token (parser->lexer); /* Eat ':'. */
+ /* Get the width of the bitfield. */
+ width
+ = cp_parser_constant_expression (parser,
+ /*allow_non_constant=*/false,
+ NULL);
+ }
+ else
+ {
+ /* Parse the declarator. */
+ declarator
+ = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ &ctor_dtor_or_conv_p,
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
+ }
+
+ /* Look for attributes that apply to the ivar. */
+ attributes = cp_parser_attributes_opt (parser);
+ /* Remember which attributes are prefix attributes and
+ which are not. */
+ first_attribute = attributes;
+ /* Combine the attributes. */
+ attributes = chainon (prefix_attributes, attributes);
+
+ if (width)
+ {
+ /* Create the bitfield declaration. */
+ decl = grokbitfield (declarator, &declspecs, width);
+ cplus_decl_attributes (&decl, attributes, /*flags=*/0);
+ }
+ else
+ decl = grokfield (declarator, &declspecs, NULL_TREE,
+ NULL_TREE, attributes);
+
+ /* Add the instance variable. */
+ objc_add_instance_variable (decl);
+
+ /* Reset PREFIX_ATTRIBUTES. */
+ while (attributes && TREE_CHAIN (attributes) != first_attribute)
+ attributes = TREE_CHAIN (attributes);
+ if (attributes)
+ TREE_CHAIN (attributes) = NULL_TREE;
+
+ token = cp_lexer_peek_token (parser->lexer);
+
+ if (token->type == CPP_COMMA)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat ','. */
+ continue;
+ }
+ break;
+ }
+
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '}'. */
+ /* For historical reasons, we accept an optional semicolon. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
+}
+
+/* Parse an Objective-C protocol declaration. */
+
+static void
+cp_parser_objc_protocol_declaration (cp_parser* parser)
+{
+ tree proto, protorefs;
+ cp_token *tok;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@protocol'. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+ {
+ error ("identifier expected after %<@protocol%>");
+ goto finish;
+ }
+
+ /* See if we have a forward declaration or a definition. */
+ tok = cp_lexer_peek_nth_token (parser->lexer, 2);
+
+ /* Try a forward declaration first. */
+ if (tok->type == CPP_COMMA || tok->type == CPP_SEMICOLON)
+ {
+ objc_declare_protocols (cp_parser_objc_identifier_list (parser));
+ finish:
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ }
+
+ /* Ok, we got a full-fledged definition (or at least should). */
+ else
+ {
+ proto = cp_parser_identifier (parser);
+ protorefs = cp_parser_objc_protocol_refs_opt (parser);
+ objc_start_protocol (proto, protorefs);
+ cp_parser_objc_method_prototype_list (parser);
+ }
+}
+
+/* Parse an Objective-C superclass or category. */
+
+static void
+cp_parser_objc_superclass_or_category (cp_parser *parser, tree *super,
+ tree *categ)
+{
+ cp_token *next = cp_lexer_peek_token (parser->lexer);
+
+ *super = *categ = NULL_TREE;
+ if (next->type == CPP_COLON)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat ':'. */
+ *super = cp_parser_identifier (parser);
+ }
+ else if (next->type == CPP_OPEN_PAREN)
+ {
+ cp_lexer_consume_token (parser->lexer); /* Eat '('. */
+ *categ = cp_parser_identifier (parser);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ }
+}
+
+/* Parse an Objective-C class interface. */
+
+static void
+cp_parser_objc_class_interface (cp_parser* parser)
+{
+ tree name, super, categ, protos;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@interface'. */
+ name = cp_parser_identifier (parser);
+ cp_parser_objc_superclass_or_category (parser, &super, &categ);
+ protos = cp_parser_objc_protocol_refs_opt (parser);
+
+ /* We have either a class or a category on our hands. */
+ if (categ)
+ objc_start_category_interface (name, categ, protos);
+ else
+ {
+ objc_start_class_interface (name, super, protos);
+ /* Handle instance variable declarations, if any. */
+ cp_parser_objc_class_ivars (parser);
+ objc_continue_interface ();
+ }
+
+ cp_parser_objc_method_prototype_list (parser);
+}
+
+/* Parse an Objective-C class implementation. */
+
+static void
+cp_parser_objc_class_implementation (cp_parser* parser)
+{
+ tree name, super, categ;
+
+ cp_lexer_consume_token (parser->lexer); /* Eat '@implementation'. */
+ name = cp_parser_identifier (parser);
+ cp_parser_objc_superclass_or_category (parser, &super, &categ);
+
+ /* We have either a class or a category on our hands. */
+ if (categ)
+ objc_start_category_implementation (name, categ);
+ else
+ {
+ objc_start_class_implementation (name, super);
+ /* Handle instance variable declarations, if any. */
+ cp_parser_objc_class_ivars (parser);
+ objc_continue_implementation ();
+ }
+
+ cp_parser_objc_method_definition_list (parser);
+}
+
+/* Consume the @end token and finish off the implementation. */
+
+static void
+cp_parser_objc_end_implementation (cp_parser* parser)
+{
+ cp_lexer_consume_token (parser->lexer); /* Eat '@end'. */
+ objc_finish_implementation ();
+}
+
+/* Parse an Objective-C declaration. */
+
+static void
+cp_parser_objc_declaration (cp_parser* parser)
+{
+ /* Try to figure out what kind of declaration is present. */
+ cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+
+ switch (kwd->keyword)
+ {
+ case RID_AT_ALIAS:
+ cp_parser_objc_alias_declaration (parser);
+ break;
+ case RID_AT_CLASS:
+ cp_parser_objc_class_declaration (parser);
+ break;
+ case RID_AT_PROTOCOL:
+ cp_parser_objc_protocol_declaration (parser);
+ break;
+ case RID_AT_INTERFACE:
+ cp_parser_objc_class_interface (parser);
+ break;
+ case RID_AT_IMPLEMENTATION:
+ cp_parser_objc_class_implementation (parser);
+ break;
+ case RID_AT_END:
+ cp_parser_objc_end_implementation (parser);
+ break;
+ default:
+ error ("misplaced %<@%D%> Objective-C++ construct", kwd->value);
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ }
+}
+
+/* Parse an Objective-C try-catch-finally statement.
+
+ objc-try-catch-finally-stmt:
+ @try compound-statement objc-catch-clause-seq [opt]
+ objc-finally-clause [opt]
+
+ objc-catch-clause-seq:
+ objc-catch-clause objc-catch-clause-seq [opt]
+
+ objc-catch-clause:
+ @catch ( exception-declaration ) compound-statement
+
+ objc-finally-clause
+ @finally compound-statement
+
+ Returns NULL_TREE. */
+
+static tree
+cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
+ location_t location;
+ tree stmt;
+
+ cp_parser_require_keyword (parser, RID_AT_TRY, "`@try'");
+ location = cp_lexer_peek_token (parser->lexer)->location;
+ /* NB: The @try block needs to be wrapped in its own STATEMENT_LIST
+ node, lest it get absorbed into the surrounding block. */
+ stmt = push_stmt_list ();
+ cp_parser_compound_statement (parser, NULL, false);
+ objc_begin_try_stmt (location, pop_stmt_list (stmt));
+
+ while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH))
+ {
+ cp_parameter_declarator *parmdecl;
+ tree parm;
+
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
+ parm = grokdeclarator (parmdecl->declarator,
+ &parmdecl->decl_specifiers,
+ PARM, /*initialized=*/0,
+ /*attrlist=*/NULL);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ objc_begin_catch_clause (parm);
+ cp_parser_compound_statement (parser, NULL, false);
+ objc_finish_catch_clause ();
+ }
+
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_FINALLY))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ location = cp_lexer_peek_token (parser->lexer)->location;
+ /* NB: The @finally block needs to be wrapped in its own STATEMENT_LIST
+ node, lest it get absorbed into the surrounding block. */
+ stmt = push_stmt_list ();
+ cp_parser_compound_statement (parser, NULL, false);
+ objc_build_finally_clause (location, pop_stmt_list (stmt));
+ }
+
+ return objc_finish_try_stmt ();
+}
+
+/* Parse an Objective-C synchronized statement.
+
+ objc-synchronized-stmt:
+ @synchronized ( expression ) compound-statement
+
+ Returns NULL_TREE. */
+
+static tree
+cp_parser_objc_synchronized_statement (cp_parser *parser) {
+ location_t location;
+ tree lock, stmt;
+
+ cp_parser_require_keyword (parser, RID_AT_SYNCHRONIZED, "`@synchronized'");
+
+ location = cp_lexer_peek_token (parser->lexer)->location;
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ lock = cp_parser_expression (parser, false);
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ /* NB: The @synchronized block needs to be wrapped in its own STATEMENT_LIST
+ node, lest it get absorbed into the surrounding block. */
+ stmt = push_stmt_list ();
+ cp_parser_compound_statement (parser, NULL, false);
+
+ return objc_build_synchronized (location, lock, pop_stmt_list (stmt));
+}
+
+/* Parse an Objective-C throw statement.
+
+ objc-throw-stmt:
+ @throw assignment-expression [opt] ;
+
+ Returns a constructed '@throw' statement. */
+
+static tree
+cp_parser_objc_throw_statement (cp_parser *parser) {
+ tree expr = NULL_TREE;
+
+ cp_parser_require_keyword (parser, RID_AT_THROW, "`@throw'");
+
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ expr = cp_parser_assignment_expression (parser, false);
+
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ return objc_build_throw_stmt (expr);
+}
+
+/* Parse an Objective-C statement. */
+
+static tree
+cp_parser_objc_statement (cp_parser * parser) {
+ /* Try to figure out what kind of declaration is present. */
+ cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+
+ switch (kwd->keyword)
+ {
+ case RID_AT_TRY:
+ return cp_parser_objc_try_catch_finally_statement (parser);
+ case RID_AT_SYNCHRONIZED:
+ return cp_parser_objc_synchronized_statement (parser);
+ case RID_AT_THROW:
+ return cp_parser_objc_throw_statement (parser);
+ default:
+ error ("misplaced %<@%D%> Objective-C++ construct", kwd->value);
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ }
+
+ return error_mark_node;
+}
\f
/* The parser. */