token->keyword = RID_MAX;
}
}
- /* Handle Objective-C++ keywords. */
else if (token->type == CPP_AT_NAME)
{
+ /* This only happens in Objective-C++; it must be a keyword. */
token->type = CPP_KEYWORD;
switch (C_RID_CODE (token->u.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;
+ /* Replace 'class' with '@class', 'private' with '@private',
+ etc. This prevents confusion with the C++ keyword
+ 'class', and makes the tokens consistent with other
+ Objective-C 'AT' keywords. For example '@class' is
+ reported as RID_AT_CLASS which is consistent with
+ '@synchronized', which is reported as
+ RID_AT_SYNCHRONIZED.
+ */
+ 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->u.value);
+ 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->u.value);
}
}
else if (token->type == CPP_PRAGMA)
(cp_parser *);
static void cp_parser_for_init_statement
(cp_parser *);
+static tree cp_parser_c_for
+ (cp_parser *);
+static tree cp_parser_range_for
+ (cp_parser *);
static tree cp_parser_jump_statement
(cp_parser *);
static void cp_parser_declaration_statement
static tree cp_parser_objc_protocol_refs_opt
(cp_parser *);
static void cp_parser_objc_declaration
- (cp_parser *);
+ (cp_parser *, tree);
static tree cp_parser_objc_statement
(cp_parser *);
+static bool cp_parser_objc_valid_prefix_attributes
+ (cp_parser* parser, tree *attrib);
/* Utility Routines */
koenig_p = true;
if (!any_type_dependent_arguments_p (args))
postfix_expression
- = perform_koenig_lookup (postfix_expression, args);
+ = perform_koenig_lookup (postfix_expression, args,
+ /*include_std=*/false);
}
else
postfix_expression
koenig_p = true;
if (!any_type_dependent_arguments_p (args))
postfix_expression
- = perform_koenig_lookup (postfix_expression, args);
+ = perform_koenig_lookup (postfix_expression, args,
+ /*include_std=*/false);
}
}
}
return cp_parser_expression (parser, /*cast_p=*/false, NULL);
}
+/* Parses a traditional for-statement until the closing ')', not included. */
+
+static tree
+cp_parser_c_for (cp_parser *parser)
+{
+ /* Normal for loop */
+ tree stmt;
+ tree condition = NULL_TREE;
+ tree expression = NULL_TREE;
+
+ /* Begin the for-statement. */
+ stmt = begin_for_stmt ();
+
+ /* Parse the initialization. */
+ cp_parser_for_init_statement (parser);
+ finish_for_init_stmt (stmt);
+
+ /* If there's a condition, process it. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ condition = cp_parser_condition (parser);
+ finish_for_cond (condition, stmt);
+ /* Look for the `;'. */
+ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+
+ /* If there's an expression, process it. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+ expression = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+ finish_for_expr (expression, stmt);
+
+ return stmt;
+}
+
+/* Tries to parse a range-based for-statement:
+
+ range-based-for:
+ type-specifier-seq declarator : expression
+
+ If succesful, assigns to *DECL the DECLARATOR and to *EXPR the
+ expression. Note that the *DECL is returned unfinished, so
+ later you should call cp_finish_decl().
+
+ Returns TRUE iff a range-based for is parsed. */
+
+static tree
+cp_parser_range_for (cp_parser *parser)
+{
+ tree stmt, range_decl, range_expr;
+ cp_decl_specifier_seq type_specifiers;
+ cp_declarator *declarator;
+ const char *saved_message;
+ tree attributes, pushed_scope;
+
+ cp_parser_parse_tentatively (parser);
+ /* New types are not allowed in the type-specifier-seq for a
+ range-based for loop. */
+ saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in range-based for loops");
+ /* Parse the type-specifier-seq. */
+ cp_parser_type_specifier_seq (parser, /*is_declaration==*/true,
+ /*is_trailing_return=*/false,
+ &type_specifiers);
+ /* Restore the saved message. */
+ parser->type_definition_forbidden_message = saved_message;
+ /* If all is well, we might be looking at a declaration. */
+ if (cp_parser_error_occurred (parser))
+ {
+ cp_parser_abort_tentative_parse (parser);
+ return NULL_TREE;
+ }
+ /* Parse the declarator. */
+ declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ /*ctor_dtor_or_conv_p=*/NULL,
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
+ /* Parse the attributes. */
+ attributes = cp_parser_attributes_opt (parser);
+ /* The next token should be `:'. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+ cp_parser_simulate_error (parser);
+
+ /* Check if it is a range-based for */
+ if (!cp_parser_parse_definitely (parser))
+ return NULL_TREE;
+
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ bool expr_non_constant_p;
+ range_expr = cp_parser_braced_list (parser, &expr_non_constant_p);
+ }
+ else
+ range_expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+
+ /* If in template, STMT is converted to a normal for-statements
+ at instantiation. If not, it is done just ahead. */
+ if (processing_template_decl)
+ stmt = begin_range_for_stmt ();
+ else
+ stmt = begin_for_stmt ();
+
+ /* Create the declaration. It must be after begin{,_range}_for_stmt(). */
+ range_decl = start_decl (declarator, &type_specifiers,
+ /*initialized_p=*/SD_INITIALIZED,
+ attributes, /*prefix_attributes=*/NULL_TREE,
+ &pushed_scope);
+ /* No scope allowed here */
+ pop_scope (pushed_scope);
+
+ if (TREE_CODE (stmt) == RANGE_FOR_STMT)
+ finish_range_for_decl (stmt, range_decl, range_expr);
+ else
+ /* Convert the range-based for loop into a normal for-statement. */
+ stmt = cp_convert_range_for (stmt, range_decl, range_expr);
+
+ return stmt;
+}
+
+/* Converts a range-based for-statement into a normal
+ for-statement, as per the definition.
+
+ for (RANGE_DECL : RANGE_EXPR)
+ BLOCK
+
+ should be equivalent to:
+
+ {
+ auto &&__range = RANGE_EXPR;
+ for (auto __begin = BEGIN_EXPR, end = END_EXPR;
+ __begin != __end;
+ ++__begin)
+ {
+ RANGE_DECL = *__begin;
+ BLOCK
+ }
+ }
+
+ If RANGE_EXPR is an array:
+ BEGIN_EXPR = __range
+ END_EXPR = __range + ARRAY_SIZE(__range)
+ Else:
+ BEGIN_EXPR = begin(__range)
+ END_EXPR = end(__range);
+
+ When calling begin()/end() we must use argument dependent
+ lookup, but always considering 'std' as an associated namespace. */
+
+tree
+cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
+{
+ tree range_type, range_temp;
+ tree begin, end;
+ tree iter_type, begin_expr, end_expr;
+ tree condition, expression;
+
+ /* Find out the type deduced by the declaration
+ * `auto &&__range = range_expr' */
+ range_type = cp_build_reference_type (make_auto (), true);
+ range_type = do_auto_deduction (range_type, range_expr,
+ type_uses_auto (range_type));
+
+ /* Create the __range variable */
+ range_temp = build_decl (input_location, VAR_DECL,
+ get_identifier ("__for_range"), range_type);
+ TREE_USED (range_temp) = 1;
+ DECL_ARTIFICIAL (range_temp) = 1;
+ pushdecl (range_temp);
+ finish_expr_stmt (cp_build_modify_expr (range_temp, INIT_EXPR, range_expr,
+ tf_warning_or_error));
+ range_temp = convert_from_reference (range_temp);
+
+ if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
+ {
+ /* If RANGE_TEMP is an array we will use pointer arithmetic */
+ iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp)));
+ begin_expr = range_temp;
+ end_expr
+ = build_binary_op (input_location, PLUS_EXPR,
+ range_temp,
+ array_type_nelts_top (TREE_TYPE (range_temp)), 0);
+ }
+ else
+ {
+ /* If it is not an array, we must call begin(__range)/end__range() */
+ VEC(tree,gc) *vec;
+
+ begin_expr = get_identifier ("begin");
+ vec = make_tree_vector ();
+ VEC_safe_push (tree, gc, vec, range_temp);
+ begin_expr = perform_koenig_lookup (begin_expr, vec,
+ /*include_std=*/true);
+ begin_expr = finish_call_expr (begin_expr, &vec, false, true,
+ tf_warning_or_error);
+ release_tree_vector (vec);
+
+ end_expr = get_identifier ("end");
+ vec = make_tree_vector ();
+ VEC_safe_push (tree, gc, vec, range_temp);
+ end_expr = perform_koenig_lookup (end_expr, vec,
+ /*include_std=*/true);
+ end_expr = finish_call_expr (end_expr, &vec, false, true,
+ tf_warning_or_error);
+ release_tree_vector (vec);
+
+ /* The unqualified type of the __begin and __end temporaries should
+ * be the same as required by the multiple auto declaration */
+ iter_type = cv_unqualified (TREE_TYPE (begin_expr));
+ if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr))))
+ error ("inconsistent begin/end types in range-based for: %qT and %qT",
+ TREE_TYPE (begin_expr), TREE_TYPE (end_expr));
+ }
+
+ /* The new for initialization statement */
+ begin = build_decl (input_location, VAR_DECL,
+ get_identifier ("__for_begin"), iter_type);
+ TREE_USED (begin) = 1;
+ DECL_ARTIFICIAL (begin) = 1;
+ pushdecl (begin);
+ finish_expr_stmt (cp_build_modify_expr (begin, INIT_EXPR, begin_expr,
+ tf_warning_or_error));
+ end = build_decl (input_location, VAR_DECL,
+ get_identifier ("__for_end"), iter_type);
+ TREE_USED (end) = 1;
+ DECL_ARTIFICIAL (end) = 1;
+ pushdecl (end);
+
+ finish_expr_stmt (cp_build_modify_expr (end, INIT_EXPR, end_expr,
+ tf_warning_or_error));
+
+ finish_for_init_stmt (statement);
+
+/* The new for condition */
+ condition = build_x_binary_op (NE_EXPR,
+ begin, ERROR_MARK,
+ end, ERROR_MARK,
+ NULL, tf_warning_or_error);
+ finish_for_cond (condition, statement);
+
+ /* The new increment expression */
+ expression = finish_unary_op_expr (PREINCREMENT_EXPR, begin);
+ finish_for_expr (expression, statement);
+
+ /* The declaration is initialized with *__begin inside the loop body */
+ cp_finish_decl (range_decl,
+ build_x_indirect_ref (begin, RO_NULL, tf_warning_or_error),
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+
+ return statement;
+}
+
+
/* Parse an iteration-statement.
iteration-statement:
for ( for-init-statement condition [opt] ; expression [opt] )
statement
- Returns the new WHILE_STMT, DO_STMT, or FOR_STMT. */
+ Returns the new WHILE_STMT, DO_STMT, FOR_STMT or RANGE_FOR_STMT. */
static tree
cp_parser_iteration_statement (cp_parser* parser)
case RID_FOR:
{
- tree condition = NULL_TREE;
- tree expression = NULL_TREE;
-
- /* Begin the for-statement. */
- statement = begin_for_stmt ();
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
- /* Parse the initialization. */
- cp_parser_for_init_statement (parser);
- finish_for_init_stmt (statement);
-
- /* If there's a condition, process it. */
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- condition = cp_parser_condition (parser);
- finish_for_cond (condition, statement);
- /* Look for the `;'. */
- cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
- /* If there's an expression, process it. */
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
- expression = cp_parser_expression (parser, /*cast_p=*/false, NULL);
- finish_for_expr (expression, statement);
+ if (cxx_dialect == cxx0x)
+ statement = cp_parser_range_for (parser);
+ else
+ statement = NULL_TREE;
+ if (statement == NULL_TREE)
+ statement = cp_parser_c_for (parser);
+
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
cp_token token2;
int saved_pedantic;
void *p;
+ tree attributes = NULL_TREE;
/* Check for the `__extension__' keyword. */
if (cp_parser_extension_opt (parser, &saved_pedantic))
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);
+ cp_parser_objc_declaration (parser, NULL_TREE);
+ else if (c_dialect_objc ()
+ && token1.keyword == RID_ATTRIBUTE
+ && cp_parser_objc_valid_prefix_attributes (parser, &attributes))
+ cp_parser_objc_declaration (parser, attributes);
/* We must have either a block declaration or a function
definition. */
else
{
tree identifier;
tree value;
+ location_t loc;
+
+ /* Save the input location because we are interested in the location
+ of the identifier and not the location of the explicit value. */
+ loc = cp_lexer_peek_token (parser->lexer)->location;
/* Look for the identifier. */
identifier = cp_parser_identifier (parser);
value = error_mark_node;
/* Create the enumerator. */
- build_enumerator (identifier, value, type);
+ build_enumerator (identifier, value, type, loc);
}
/* Parse a namespace-name.
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE))
{
+ maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES);
is_inline = true;
cp_lexer_consume_token (parser->lexer);
}
/* Parse an Objective-C params list. */
static tree
-cp_parser_objc_method_keyword_params (cp_parser* parser)
+cp_parser_objc_method_keyword_params (cp_parser* parser, tree* attributes)
{
tree params = NULL_TREE;
bool maybe_unary_selector_p = true;
while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
{
tree selector = NULL_TREE, type_name, identifier;
+ tree parm_attr = NULL_TREE;
+
+ if (token->keyword == RID_ATTRIBUTE)
+ break;
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;
+ {
+ params = selector; /* Might be followed by attributes. */
+ break;
+ }
maybe_unary_selector_p = false;
cp_parser_require (parser, CPP_COLON, RT_COLON);
type_name = cp_parser_objc_typename (parser);
+ /* New ObjC allows attributes on parameters too. */
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
+ parm_attr = cp_parser_attributes_opt (parser);
identifier = cp_parser_identifier (parser);
params
= chainon (params,
objc_build_keyword_decl (selector,
type_name,
- identifier));
+ identifier,
+ parm_attr));
token = cp_lexer_peek_token (parser->lexer);
}
+ if (params == NULL_TREE)
+ {
+ cp_parser_error (parser, "objective-c++ method declaration is expected");
+ return error_mark_node;
+ }
+
+ /* We allow tail attributes for the method. */
+ if (token->keyword == RID_ATTRIBUTE)
+ {
+ *attributes = cp_parser_attributes_opt (parser);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+ || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ return params;
+ cp_parser_error (parser,
+ "method attributes must be specified at the end");
+ return error_mark_node;
+ }
+
return params;
}
/* Parse the non-keyword Objective-C params. */
static tree
-cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp)
+cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp,
+ tree* attributes)
{
tree params = make_node (TREE_LIST);
cp_token *token = cp_lexer_peek_token (parser->lexer);
break;
}
+ /* TODO: parse attributes for tail parameters. */
parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
parm = grokdeclarator (parmdecl->declarator,
&parmdecl->decl_specifiers,
token = cp_lexer_peek_token (parser->lexer);
}
+ /* We allow tail attributes for the method. */
+ if (token->keyword == RID_ATTRIBUTE)
+ {
+ if (*attributes == NULL_TREE)
+ {
+ *attributes = cp_parser_attributes_opt (parser);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+ || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ return params;
+ }
+ else
+ /* We have an error, but parse the attributes, so that we can
+ carry on. */
+ *attributes = cp_parser_attributes_opt (parser);
+
+ cp_parser_error (parser,
+ "method attributes must be specified at the end");
+ return error_mark_node;
+ }
+
return params;
}
/* Parse a method signature. */
static tree
-cp_parser_objc_method_signature (cp_parser* parser)
+cp_parser_objc_method_signature (cp_parser* parser, tree* attributes)
{
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);
+ *attributes = NULL_TREE;
+ kwdparms = cp_parser_objc_method_keyword_params (parser, attributes);
+ if (kwdparms == error_mark_node)
+ return error_mark_node;
+ optparms = cp_parser_objc_method_tail_params_opt (parser, &ellipsis, attributes);
+ if (optparms == error_mark_node)
+ return error_mark_node;
return objc_build_method_signature (rettype, kwdparms, optparms, ellipsis);
}
-/* Pars an Objective-C method prototype list. */
+static bool
+cp_parser_objc_method_maybe_bad_prefix_attributes (cp_parser* parser)
+{
+ tree tattr;
+ cp_lexer_save_tokens (parser->lexer);
+ tattr = cp_parser_attributes_opt (parser);
+ gcc_assert (tattr) ;
+
+ /* If the attributes are followed by a method introducer, this is not allowed.
+ Dump the attributes and flag the situation. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_PLUS)
+ || cp_lexer_next_token_is (parser->lexer, CPP_MINUS))
+ return true;
+
+ /* Otherwise, the attributes introduce some interstitial code, possibly so
+ rewind to allow that check. */
+ cp_lexer_rollback_tokens (parser->lexer);
+ return false;
+}
+
+/* Parse 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)
+ while (token->keyword != RID_AT_END && token->type != CPP_EOF)
{
if (token->type == CPP_PLUS || token->type == CPP_MINUS)
{
- objc_add_method_declaration
- (cp_parser_objc_method_signature (parser));
+ tree attributes, sig;
+ sig = cp_parser_objc_method_signature (parser, &attributes);
+ if (sig == error_mark_node)
+ {
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ continue;
+ }
+ objc_add_method_declaration (sig, attributes);
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
+ else if (token->keyword == RID_ATTRIBUTE
+ && cp_parser_objc_method_maybe_bad_prefix_attributes(parser))
+ warning_at (cp_lexer_peek_token (parser->lexer)->location,
+ OPT_Wattributes,
+ "prefix attributes are ignored for methods");
else
/* Allow for interspersed non-ObjC++ code. */
cp_parser_objc_interstitial_code (parser);
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
- while (token->keyword != RID_AT_END)
+ while (token->keyword != RID_AT_END && token->type != CPP_EOF)
{
tree meth;
if (token->type == CPP_PLUS || token->type == CPP_MINUS)
{
+ cp_token *ptk;
+ tree sig, attribute;
push_deferring_access_checks (dk_deferred);
- objc_start_method_definition
- (cp_parser_objc_method_signature (parser));
+ sig = cp_parser_objc_method_signature (parser, &attribute);
+ if (sig == error_mark_node)
+ {
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ continue;
+ }
+ objc_start_method_definition (sig, attribute);
/* 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,
+ ptk = cp_lexer_peek_token (parser->lexer);
+ if (!(ptk->type == CPP_PLUS || ptk->type == CPP_MINUS
+ || ptk->type == CPP_EOF || ptk->keyword == RID_AT_END))
+ {
+ 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);
+ pop_deferring_access_checks ();
+ objc_finish_method_definition (meth);
+ }
}
+ else if (token->keyword == RID_ATTRIBUTE
+ && cp_parser_objc_method_maybe_bad_prefix_attributes(parser))
+ warning_at (token->location, OPT_Wattributes,
+ "prefix attributes are ignored for methods");
else
/* Allow for interspersed non-ObjC++ code. */
cp_parser_objc_interstitial_code (parser);
/* Parse an Objective-C protocol declaration. */
static void
-cp_parser_objc_protocol_declaration (cp_parser* parser)
+cp_parser_objc_protocol_declaration (cp_parser* parser, tree attributes)
{
tree proto, protorefs;
cp_token *tok;
{
proto = cp_parser_identifier (parser);
protorefs = cp_parser_objc_protocol_refs_opt (parser);
- objc_start_protocol (proto, protorefs);
+ objc_start_protocol (proto, protorefs, attributes);
cp_parser_objc_method_prototype_list (parser);
}
}
/* Parse an Objective-C class interface. */
static void
-cp_parser_objc_class_interface (cp_parser* parser)
+cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
{
tree name, super, categ, protos;
/* We have either a class or a category on our hands. */
if (categ)
- objc_start_category_interface (name, categ, protos);
+ objc_start_category_interface (name, categ, protos, attributes);
else
{
- objc_start_class_interface (name, super, protos);
+ objc_start_class_interface (name, super, protos, attributes);
/* Handle instance variable declarations, if any. */
cp_parser_objc_class_ivars (parser);
objc_continue_interface ();
/* Parse an Objective-C declaration. */
static void
-cp_parser_objc_declaration (cp_parser* parser)
+cp_parser_objc_declaration (cp_parser* parser, tree attributes)
{
/* Try to figure out what kind of declaration is present. */
cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+ if (attributes)
+ switch (kwd->keyword)
+ {
+ case RID_AT_ALIAS:
+ case RID_AT_CLASS:
+ case RID_AT_END:
+ error_at (kwd->location, "attributes may not be specified before"
+ " the %<@%D%> Objective-C++ keyword",
+ kwd->u.value);
+ attributes = NULL;
+ break;
+ case RID_AT_IMPLEMENTATION:
+ warning_at (kwd->location, OPT_Wattributes,
+ "prefix attributes are ignored before %<@%D%>",
+ kwd->u.value);
+ attributes = NULL;
+ default:
+ break;
+ }
+
switch (kwd->keyword)
{
case RID_AT_ALIAS:
cp_parser_objc_class_declaration (parser);
break;
case RID_AT_PROTOCOL:
- cp_parser_objc_protocol_declaration (parser);
+ cp_parser_objc_protocol_declaration (parser, attributes);
break;
case RID_AT_INTERFACE:
- cp_parser_objc_class_interface (parser);
+ cp_parser_objc_class_interface (parser, attributes);
break;
case RID_AT_IMPLEMENTATION:
cp_parser_objc_class_implementation (parser);
return error_mark_node;
}
+
+/* If we are compiling ObjC++ and we see an __attribute__ we neeed to
+ look ahead to see if an objc keyword follows the attributes. This
+ is to detect the use of prefix attributes on ObjC @interface and
+ @protocol. */
+
+static bool
+cp_parser_objc_valid_prefix_attributes (cp_parser* parser, tree *attrib)
+{
+ cp_lexer_save_tokens (parser->lexer);
+ *attrib = cp_parser_attributes_opt (parser);
+ gcc_assert (*attrib);
+ if (OBJC_IS_AT_KEYWORD (cp_lexer_peek_token (parser->lexer)->keyword))
+ {
+ cp_lexer_commit_tokens (parser->lexer);
+ return true;
+ }
+ cp_lexer_rollback_tokens (parser->lexer);
+ return false;
+}
\f
/* OpenMP 2.5 parsing routines. */