/* Parser for C and Objective-C.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011,
+ 2012 Free Software Foundation, Inc.
Parser actions based on the old Bison parser; structure somewhat
influenced by and fragments based on the C++ parser.
#include "c-tree.h"
#include "flags.h"
#include "output.h"
-#include "toplev.h"
#include "ggc.h"
#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
#include "vec.h"
#include "target.h"
#include "cgraph.h"
/* True if we are in a context where the Objective-C "PQ" keywords
are considered keywords. */
BOOL_BITFIELD objc_pq_context : 1;
+ /* True if we are parsing a (potential) Objective-C foreach
+ statement. This is set to true after we parsed 'for (' and while
+ we wait for 'in' or ';' to decide if it's a standard C for loop or an
+ Objective-C foreach loop. */
+ BOOL_BITFIELD objc_could_be_foreach_context : 1;
/* The following flag is needed to contextualize Objective-C lexical
analysis. In some cases (e.g., 'int NSObject;'), it is
undesirable to bind an identifier to an Objective-C class, even
if a class with that name exists. */
BOOL_BITFIELD objc_need_raw_identifier : 1;
+ /* Nonzero if we're processing a __transaction statement. The value
+ is 1 | TM_STMT_ATTR_*. */
+ unsigned int in_transaction : 4;
+ /* True if we are in a context where the Objective-C "Property attribute"
+ keywords are valid. */
+ BOOL_BITFIELD objc_property_attr_context : 1;
} c_parser;
/* We found an Objective-C "pq" keyword (in, out,
inout, bycopy, byref, oneway). They need special
care because the interpretation depends on the
- context.
- */
+ context. */
if (parser->objc_pq_context)
{
token->type = CPP_KEYWORD;
token->keyword = rid_code;
break;
}
+ else if (parser->objc_could_be_foreach_context
+ && rid_code == RID_IN)
+ {
+ /* We are in Objective-C, inside a (potential)
+ foreach context (which means after having
+ parsed 'for (', but before having parsed ';'),
+ and we found 'in'. We consider it the keyword
+ which terminates the declaration at the
+ beginning of a foreach-statement. Note that
+ this means you can't use 'in' for anything else
+ in that context; in particular, in Objective-C
+ you can't use 'in' as the name of the running
+ variable in a C for loop. We could potentially
+ try to add code here to disambiguate, but it
+ seems a reasonable limitation. */
+ token->type = CPP_KEYWORD;
+ token->keyword = rid_code;
+ break;
+ }
/* Else, "pq" keywords outside of the "pq" context are
not keywords, and we fall through to the code for
- normal tokens.
+ normal tokens. */
+ }
+ else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code))
+ {
+ /* We found an Objective-C "property attribute"
+ keyword (getter, setter, readonly, etc). These are
+ only valid in the property context. */
+ if (parser->objc_property_attr_context)
+ {
+ token->type = CPP_KEYWORD;
+ token->keyword = rid_code;
+ break;
+ }
+ /* Else they are not special keywords.
*/
}
else if (c_dialect_objc ()
protected, public, try, catch, throw) without a
preceding '@' sign. Do nothing and fall through to
the code for normal tokens (in C++ we would still
- consider the CXX ones keywords, but not in C).
- */
+ consider the CXX ones keywords, but not in C). */
;
}
else
variables and typedefs, and hence are shadowed by local
declarations. */
if (objc_interface_decl
- && (global_bindings_p ()
- || (!objc_force_identifier && !decl)))
+ && (!objc_force_identifier || global_bindings_p ()))
{
token->value = objc_interface_decl;
token->id_kind = C_ID_CLASSNAME;
case CPP_AT_NAME:
/* This only happens in Objective-C; it must be a keyword. */
token->type = CPP_KEYWORD;
- token->keyword = C_RID_CODE (token->value);
+ switch (C_RID_CODE (token->value))
+ {
+ /* 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->value);
+ }
break;
case CPP_COLON:
case CPP_COMMA:
return c_parser_peek_token (parser)->keyword == keyword;
}
+/* Return a pointer to the next-but-one token from PARSER, reading it
+ in if necessary. The next token is already read in. */
+
+static c_token *
+c_parser_peek_2nd_token (c_parser *parser)
+{
+ if (parser->tokens_avail >= 2)
+ return &parser->tokens[1];
+ gcc_assert (parser->tokens_avail == 1);
+ gcc_assert (parser->tokens[0].type != CPP_EOF);
+ gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
+ c_lex_one_token (parser, &parser->tokens[1]);
+ parser->tokens_avail = 2;
+ return &parser->tokens[1];
+}
+
/* Return true if TOKEN can start a type name,
false otherwise. */
static bool
}
}
+enum c_lookahead_kind {
+ /* Always treat unknown identifiers as typenames. */
+ cla_prefer_type,
+
+ /* Could be parsing a nonabstract declarator. Only treat an identifier
+ as a typename if followed by another identifier or a star. */
+ cla_nonabstract_decl,
+
+ /* Never treat identifiers as typenames. */
+ cla_prefer_id
+};
+
/* Return true if the next token from PARSER can start a type name,
+ false otherwise. LA specifies how to do lookahead in order to
+ detect unknown type names. If unsure, pick CLA_PREFER_ID. */
+
+static inline bool
+c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la)
+{
+ c_token *token = c_parser_peek_token (parser);
+ if (c_token_starts_typename (token))
+ return true;
+
+ /* Try a bit harder to detect an unknown typename. */
+ if (la != cla_prefer_id
+ && token->type == CPP_NAME
+ && token->id_kind == C_ID_ID
+
+ /* Do not try too hard when we could have "object in array". */
+ && !parser->objc_could_be_foreach_context
+
+ && (la == cla_prefer_type
+ || c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+
+ /* Only unknown identifiers. */
+ && !lookup_name (token->value))
+ return true;
+
+ return false;
+}
+
+/* Return true if TOKEN is a type qualifier, false otherwise. */
+static bool
+c_token_is_qualifier (c_token *token)
+{
+ switch (token->type)
+ {
+ case CPP_NAME:
+ switch (token->id_kind)
+ {
+ case C_ID_ADDRSPACE:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_LESS:
+ return false;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return true if the next token from PARSER is a type qualifier,
false otherwise. */
static inline bool
-c_parser_next_token_starts_typename (c_parser *parser)
+c_parser_next_token_is_qualifier (c_parser *parser)
{
c_token *token = c_parser_peek_token (parser);
- return c_token_starts_typename (token);
+ return c_token_is_qualifier (token);
}
/* Return true if TOKEN can start declaration specifiers, false
case RID_REGISTER:
case RID_TYPEDEF:
case RID_INLINE:
+ case RID_NORETURN:
case RID_AUTO:
case RID_THREAD:
case RID_UNSIGNED:
case RID_FRACT:
case RID_ACCUM:
case RID_SAT:
+ case RID_ALIGNAS:
return true;
default:
return false;
c_parser_next_token_starts_declspecs (c_parser *parser)
{
c_token *token = c_parser_peek_token (parser);
+
+ /* In Objective-C, a classname normally starts a declspecs unless it
+ is immediately followed by a dot. In that case, it is the
+ Objective-C 2.0 "dot-syntax" for class objects, ie, calls the
+ setter/getter on the class. c_token_starts_declspecs() can't
+ differentiate between the two cases because it only checks the
+ current token, so we have a special check here. */
+ if (c_dialect_objc ()
+ && token->type == CPP_NAME
+ && token->id_kind == C_ID_CLASSNAME
+ && c_parser_peek_2nd_token (parser)->type == CPP_DOT)
+ return false;
+
return c_token_starts_declspecs (token);
}
-/* Return true if the next token from PARSER can start declaration
+/* Return true if the next tokens from PARSER can start declaration
specifiers or a static assertion, false otherwise. */
static inline bool
-c_parser_next_token_starts_declaration (c_parser *parser)
+c_parser_next_tokens_start_declaration (c_parser *parser)
{
c_token *token = c_parser_peek_token (parser);
- return c_token_starts_declaration (token);
-}
-/* Return a pointer to the next-but-one token from PARSER, reading it
- in if necessary. The next token is already read in. */
+ /* Same as above. */
+ if (c_dialect_objc ()
+ && token->type == CPP_NAME
+ && token->id_kind == C_ID_CLASSNAME
+ && c_parser_peek_2nd_token (parser)->type == CPP_DOT)
+ return false;
-static c_token *
-c_parser_peek_2nd_token (c_parser *parser)
-{
- if (parser->tokens_avail >= 2)
- return &parser->tokens[1];
- gcc_assert (parser->tokens_avail == 1);
- gcc_assert (parser->tokens[0].type != CPP_EOF);
- gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
- c_lex_one_token (parser, &parser->tokens[1]);
- parser->tokens_avail = 2;
- return &parser->tokens[1];
+ /* Labels do not start declarations. */
+ if (token->type == CPP_NAME
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ return false;
+
+ if (c_token_starts_declaration (token))
+ return true;
+
+ if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl))
+ return true;
+
+ return false;
}
/* Consume the next token from PARSER. */
| (warn_traditional << 2)
| (flag_iso << 3)
| (warn_long_long << 4)
- | (warn_cxx_compat << 5));
+ | (warn_cxx_compat << 5)
+ | (warn_overlength_strings << 6));
cpp_opts->cpp_pedantic = pedantic = 0;
warn_pointer_arith = 0;
cpp_opts->cpp_warn_traditional = warn_traditional = 0;
flag_iso = 0;
cpp_opts->cpp_warn_long_long = warn_long_long = 0;
warn_cxx_compat = 0;
+ warn_overlength_strings = 0;
return ret;
}
flag_iso = (flags >> 3) & 1;
cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1;
warn_cxx_compat = (flags >> 5) & 1;
+ warn_overlength_strings = (flags >> 6) & 1;
}
/* Possibly kinds of declarator to parse. */
C_DTR_PARM
} c_dtr_syn;
+/* The binary operation precedence levels, where 0 is a dummy lowest level
+ used for the bottom of the stack. */
+enum c_parser_prec {
+ PREC_NONE,
+ PREC_LOGOR,
+ PREC_LOGAND,
+ PREC_BITOR,
+ PREC_BITXOR,
+ PREC_BITAND,
+ PREC_EQ,
+ PREC_REL,
+ PREC_SHIFT,
+ PREC_ADD,
+ PREC_MULT,
+ NUM_PRECS
+};
+
static void c_parser_external_declaration (c_parser *);
static void c_parser_asm_definition (c_parser *);
static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
- bool, bool);
+ bool, bool, tree *);
static void c_parser_static_assert_declaration_no_semi (c_parser *);
static void c_parser_static_assert_declaration (c_parser *);
static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
- bool);
+ bool, enum c_lookahead_kind);
static struct c_typespec c_parser_enum_specifier (c_parser *);
static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
static tree c_parser_struct_declaration (c_parser *);
static struct c_typespec c_parser_typeof_specifier (c_parser *);
+static tree c_parser_alignas_specifier (c_parser *);
static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn,
bool *);
static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,
bool,
struct c_declarator *);
static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree);
-static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree);
+static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree,
+ tree);
static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
static tree c_parser_simple_asm_expr (c_parser *);
static tree c_parser_attributes (c_parser *);
static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
static struct c_expr c_parser_conditional_expression (c_parser *,
struct c_expr *);
-static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
+ enum c_parser_prec);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
static struct c_expr c_parser_sizeof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
location_t loc,
struct c_expr);
+static tree c_parser_transaction (c_parser *, enum rid);
+static struct c_expr c_parser_transaction_expression (c_parser *, enum rid);
+static tree c_parser_transaction_cancel (c_parser *);
static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *);
static VEC(tree,gc) *c_parser_expr_list (c_parser *, bool, bool,
static void c_parser_omp_barrier (c_parser *);
static void c_parser_omp_flush (c_parser *);
static void c_parser_omp_taskwait (c_parser *);
+static void c_parser_omp_taskyield (c_parser *);
enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
static bool c_parser_pragma (c_parser *, enum pragma_context);
static void c_parser_objc_class_declaration (c_parser *);
static void c_parser_objc_alias_declaration (c_parser *);
static void c_parser_objc_protocol_definition (c_parser *, tree);
-static enum tree_code c_parser_objc_method_type (c_parser *);
+static bool c_parser_objc_method_type (c_parser *);
static void c_parser_objc_method_definition (c_parser *);
static void c_parser_objc_methodprotolist (c_parser *);
static void c_parser_objc_methodproto (c_parser *);
-static tree c_parser_objc_method_decl (c_parser *, tree *);
+static tree c_parser_objc_method_decl (c_parser *, bool, tree *, tree *);
static tree c_parser_objc_type_name (c_parser *);
static tree c_parser_objc_protocol_refs (c_parser *);
-static void c_parser_objc_try_catch_statement (c_parser *);
+static void c_parser_objc_try_catch_finally_statement (c_parser *);
static void c_parser_objc_synchronized_statement (c_parser *);
static tree c_parser_objc_selector (c_parser *);
static tree c_parser_objc_selector_arg (c_parser *);
static tree c_parser_objc_receiver (c_parser *);
static tree c_parser_objc_message_args (c_parser *);
static tree c_parser_objc_keywordexpr (c_parser *);
-static bool c_parser_objc_diagnose_bad_element_prefix
+static void c_parser_objc_at_property_declaration (c_parser *);
+static void c_parser_objc_at_synthesize_declaration (c_parser *);
+static void c_parser_objc_at_dynamic_declaration (c_parser *);
+static bool c_parser_objc_diagnose_bad_element_prefix
(c_parser *, struct c_declspecs *);
/* Parse a translation unit (C90 6.7, C99 6.9).
gcc_assert (c_dialect_objc ());
c_parser_objc_class_definition (parser, NULL_TREE);
break;
- case RID_CLASS:
+ case RID_AT_CLASS:
gcc_assert (c_dialect_objc ());
c_parser_objc_class_declaration (parser);
break;
gcc_assert (c_dialect_objc ());
c_parser_objc_protocol_definition (parser, NULL_TREE);
break;
+ case RID_AT_PROPERTY:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_at_property_declaration (parser);
+ break;
+ case RID_AT_SYNTHESIZE:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_at_synthesize_declaration (parser);
+ break;
+ case RID_AT_DYNAMIC:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_at_dynamic_declaration (parser);
+ break;
case RID_AT_END:
gcc_assert (c_dialect_objc ());
c_parser_consume_token (parser);
an @interface or @protocol with prefix attributes). We can
only tell which after parsing the declaration specifiers, if
any, and the first declarator. */
- c_parser_declaration_or_fndef (parser, true, true, true, false, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL);
break;
}
}
(old-style parameter declarations) they are diagnosed. If
START_ATTR_OK is true, the declaration specifiers may start with
attributes; otherwise they may not.
+ OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed
+ declaration when parsing an Objective-C foreach statement.
declaration:
declaration-specifiers init-declarator-list[opt] ;
specifiers, but only at top level (elsewhere they conflict with
other syntax).
+ In Objective-C, declarations of the looping variable in a foreach
+ statement are exceptionally terminated by 'in' (for example, 'for
+ (NSObject *object in array) { ... }').
+
OpenMP:
declaration:
static void
c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
bool static_assert_ok, bool empty_ok,
- bool nested, bool start_attr_ok)
+ bool nested, bool start_attr_ok,
+ tree *objc_foreach_object_declaration)
{
struct c_declspecs *specs;
tree prefix_attrs;
return;
}
specs = build_null_declspecs ();
- c_parser_declspecs (parser, specs, true, true, start_attr_ok);
+
+ /* Try to detect an unknown type name when we have "A B" or "A *B". */
+ if (c_parser_peek_token (parser)->type == CPP_NAME
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID
+ && (c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+ && (!nested || !lookup_name (c_parser_peek_token (parser)->value)))
+ {
+ error_at (here, "unknown type name %qE",
+ c_parser_peek_token (parser)->value);
+
+ /* Parse declspecs normally to get a correct pointer type, but avoid
+ a further "fails to be a type name" error. Refuse nested functions
+ since it is not how the user likely wants us to recover. */
+ c_parser_peek_token (parser)->type = CPP_KEYWORD;
+ c_parser_peek_token (parser)->keyword = RID_VOID;
+ c_parser_peek_token (parser)->value = error_mark_node;
+ fndef_ok = !nested;
+ }
+
+ c_parser_declspecs (parser, specs, true, true, start_attr_ok, cla_nonabstract_decl);
if (parser->error)
{
c_parser_skip_to_end_of_block_or_statement (parser);
c_parser_consume_token (parser);
return;
}
+
+ /* Provide better error recovery. Note that a type name here is usually
+ better diagnosed as a redeclaration. */
+ if (empty_ok
+ && specs->typespec_kind == ctsk_tagdef
+ && c_parser_next_token_starts_declspecs (parser)
+ && !c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+ parser->error = false;
+ shadow_tag_warned (specs, 1);
+ return;
+ }
else if (c_dialect_objc ())
{
/* Prefix attributes are an error on method decls. */
return;
}
break;
+ case RID_AT_ALIAS:
+ case RID_AT_CLASS:
+ case RID_AT_END:
+ case RID_AT_PROPERTY:
+ if (specs->attrs)
+ {
+ c_parser_error (parser, "unexpected attribute");
+ specs->attrs = NULL;
+ }
+ break;
default:
break;
}
{
struct c_declarator *declarator;
bool dummy = false;
+ timevar_id_t tv;
tree fnbody;
/* Declaring either one or more declarators (in which case we
should diagnose if there were no declaration specifiers) or a
function definition (in which case the diagnostic for
implicit int suffices). */
- declarator = c_parser_declarator (parser, specs->type_seen_p,
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
C_DTR_NORMAL, &dummy);
if (declarator == NULL)
{
|| c_parser_next_token_is (parser, CPP_COMMA)
|| c_parser_next_token_is (parser, CPP_SEMICOLON)
|| c_parser_next_token_is_keyword (parser, RID_ASM)
- || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)
+ || c_parser_next_token_is_keyword (parser, RID_IN))
{
tree asm_name = NULL_TREE;
tree postfix_attrs = NULL_TREE;
all_prefix_attrs));
if (d)
finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
- NULL_TREE, asm_name);
+ NULL_TREE, asm_name);
+
+ if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ if (d)
+ *objc_foreach_object_declaration = d;
+ else
+ *objc_foreach_object_declaration = error_mark_node;
+ }
}
if (c_parser_next_token_is (parser, CPP_COMMA))
{
c_parser_consume_token (parser);
return;
}
+ else if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ /* This can only happen in Objective-C: we found the
+ 'in' that terminates the declaration inside an
+ Objective-C foreach statement. Do not consume the
+ token, so that the caller can use it to determine
+ that this indeed is a foreach context. */
+ return;
+ }
else
{
c_parser_error (parser, "expected %<,%> or %<;%>");
c_pop_function_context ();
break;
}
+
+ if (DECL_DECLARED_INLINE_P (current_function_decl))
+ tv = TV_PARSE_INLINE;
+ else
+ tv = TV_PARSE_FUNC;
+ timevar_push (tv);
+
/* Parse old-style parameter declarations. ??? Attributes are
not allowed to start declaration specifiers here because of a
syntax conflict between a function declaration with attribute
while (c_parser_next_token_is_not (parser, CPP_EOF)
&& c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
c_parser_declaration_or_fndef (parser, false, false, false,
- true, false);
+ true, false, NULL);
store_parm_decls ();
DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
= c_parser_peek_token (parser)->location;
add_stmt (fnbody);
finish_function ();
}
+
+ timevar_pop (tv);
break;
}
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
-/* Parse a static assertion (C1X N1425 6.7.10).
+/* Parse a static assertion (C11 6.7.10).
static_assert-declaration:
static_assert-declaration-no-semi ;
c_parser_skip_to_end_of_block_or_statement (parser);
}
-/* Parse a static assertion (C1X N1425 6.7.10), without the trailing
+/* Parse a static assertion (C11 6.7.10), without the trailing
semicolon.
static_assert-declaration-no-semi:
gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT));
assert_loc = c_parser_peek_token (parser)->location;
- if (!flag_isoc1x)
+ if (!flag_isoc11)
{
if (flag_isoc99)
pedwarn (assert_loc, OPT_pedantic,
type-specifier declaration-specifiers[opt]
type-qualifier declaration-specifiers[opt]
function-specifier declaration-specifiers[opt]
+ alignment-specifier declaration-specifiers[opt]
Function specifiers (inline) are from C99, and are currently
- handled as storage class specifiers, as is __thread.
+ handled as storage class specifiers, as is __thread. Alignment
+ specifiers are from C11.
C90 6.5.1, C99 6.7.1:
storage-class-specifier:
C99 6.7.4:
function-specifier:
inline
+ _Noreturn
+
+ (_Noreturn is new in C11.)
C90 6.5.2, C99 6.7.2:
type-specifier:
static void
c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
- bool scspec_ok, bool typespec_ok, bool start_attr_ok)
+ bool scspec_ok, bool typespec_ok, bool start_attr_ok,
+ enum c_lookahead_kind la)
{
bool attrs_ok = start_attr_ok;
- bool seen_type = specs->type_seen_p;
+ bool seen_type = specs->typespec_kind != ctsk_none;
+
+ if (!typespec_ok)
+ gcc_assert (la == cla_prefer_id);
+
while (c_parser_next_token_is (parser, CPP_NAME)
|| c_parser_next_token_is (parser, CPP_KEYWORD)
|| (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
{
struct c_typespec t;
tree attrs;
+ tree align;
location_t loc = c_parser_peek_token (parser)->location;
+
+ /* If we cannot accept a type, exit if the next token must start
+ one. Also, if we already have seen a tagged definition,
+ a typename would be an error anyway and likely the user
+ has simply forgotten a semicolon, so we exit. */
+ if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
+ && c_parser_next_tokens_start_typename (parser, la)
+ && !c_parser_next_token_is_qualifier (parser))
+ break;
+
if (c_parser_next_token_is (parser, CPP_NAME))
{
tree value = c_parser_peek_token (parser)->value;
continue;
}
- /* This finishes the specifiers unless a type name is OK, it
- is declared as a type name and a type name hasn't yet
- been seen. */
- if (!typespec_ok || seen_type
- || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
+ gcc_assert (!c_parser_next_token_is_qualifier (parser));
+
+ /* If we cannot accept a type, and the next token must start one,
+ exit. Do the same if we already have seen a tagged definition,
+ since it would be an error anyway and likely the user has simply
+ forgotten a semicolon. */
+ if (seen_type || !c_parser_next_tokens_start_typename (parser, la))
break;
+
+ /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or
+ a C_ID_CLASSNAME. */
c_parser_consume_token (parser);
seen_type = true;
attrs_ok = true;
- if (kind == C_ID_TYPENAME
- && (!c_dialect_objc ()
- || c_parser_next_token_is_not (parser, CPP_LESS)))
+ if (kind == C_ID_ID)
+ {
+ error ("unknown type name %qE", value);
+ t.kind = ctsk_typedef;
+ t.spec = error_mark_node;
+ }
+ else if (kind == C_ID_TYPENAME
+ && (!c_dialect_objc ()
+ || c_parser_next_token_is_not (parser, CPP_LESS)))
{
t.kind = ctsk_typedef;
/* For a typedef name, record the meaning, not the name.
In case of 'foo foo, bar;'. */
t.spec = lookup_name (value);
- t.expr = NULL_TREE;
- t.expr_const_operands = true;
}
else
{
if (c_parser_next_token_is (parser, CPP_LESS))
proto = c_parser_objc_protocol_refs (parser);
t.spec = objc_get_protocol_qualified_type (value, proto);
- t.expr = NULL_TREE;
- t.expr_const_operands = true;
}
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
declspecs_add_type (loc, specs, t);
continue;
}
case RID_REGISTER:
case RID_TYPEDEF:
case RID_INLINE:
+ case RID_NORETURN:
case RID_AUTO:
case RID_THREAD:
if (!scspec_ok)
goto out;
attrs_ok = true;
- /* TODO: Distinguish between function specifiers (inline)
+ /* TODO: Distinguish between function specifiers (inline, noreturn)
and storage class specifiers, either here or in
declspecs_add_scspec. */
declspecs_add_scspec (specs, c_parser_peek_token (parser)->value);
attrs = c_parser_attributes (parser);
declspecs_add_attrs (specs, attrs);
break;
+ case RID_ALIGNAS:
+ align = c_parser_alignas_specifier (parser);
+ declspecs_add_alignas (specs, align);
+ break;
default:
goto out;
}
{
/* Parse an enum definition. */
struct c_enum_contents the_enum;
- tree type = start_enum (enum_loc, &the_enum, ident);
+ tree type;
tree postfix_attrs;
/* We chain the enumerators in reverse order, then put them in
forward order at the end. */
- tree values = NULL_TREE;
+ tree values;
+ timevar_push (TV_PARSE_ENUM);
+ type = start_enum (enum_loc, &the_enum, ident);
+ values = NULL_TREE;
c_parser_consume_token (parser);
while (true)
{
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ timevar_pop (TV_PARSE_ENUM);
return ret;
}
else if (!ident)
semicolon separated fields than comma separated fields, and
so we'll be minimizing the number of node traversals required
by chainon. */
- tree contents = NULL_TREE;
+ tree contents;
+ timevar_push (TV_PARSE_STRUCT);
+ contents = NULL_TREE;
c_parser_consume_token (parser);
/* Handle the Objective-C @defs construct,
e.g. foo(sizeof(struct{ @defs(ClassName) }));. */
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
pedwarn (c_parser_peek_token (parser)->location, 0,
"no semicolon at end of struct or union");
- else
+ else if (parser->error
+ || !c_parser_next_token_starts_declspecs (parser))
{
c_parser_error (parser, "expected %<;%>");
c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
break;
}
+
+ /* If we come here, we have already emitted an error
+ for an expected `;', identifier or `(', and we also
+ recovered already. Go on with the next field. */
}
}
postfix_attrs = c_parser_attributes (parser);
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ timevar_pop (TV_PARSE_STRUCT);
return ret;
}
else if (!ident)
}
specs = build_null_declspecs ();
decl_loc = c_parser_peek_token (parser)->location;
- c_parser_declspecs (parser, specs, false, true, true);
+ c_parser_declspecs (parser, specs, false, true, true, cla_nonabstract_decl);
if (parser->error)
return NULL_TREE;
if (!specs->declspecs_seen_p)
return NULL_TREE;
}
finish_declspecs (specs);
- if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+ || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
tree ret;
- if (!specs->type_seen_p)
+ if (specs->typespec_kind == ctsk_none)
{
pedwarn (decl_loc, OPT_pedantic,
"ISO C forbids member declarations with no members");
}
return ret;
}
+
+ /* Provide better error recovery. Note that a type name here is valid,
+ and will be treated as a field name. */
+ if (specs->typespec_kind == ctsk_tagdef
+ && TREE_CODE (specs->type) != ENUMERAL_TYPE
+ && c_parser_next_token_starts_declspecs (parser)
+ && !c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+ parser->error = false;
+ return NULL_TREE;
+ }
+
pending_xref_error ();
prefix_attrs = specs->attrs;
all_prefix_attrs = prefix_attrs;
if (c_parser_next_token_is (parser, CPP_COLON))
declarator = build_id_declarator (NULL_TREE);
else
- declarator = c_parser_declarator (parser, specs->type_seen_p,
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
C_DTR_NORMAL, &dummy);
if (declarator == NULL)
{
in_typeof--;
return ret;
}
- if (c_parser_next_token_starts_typename (parser))
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
{
struct c_type_name *type = c_parser_type_name (parser);
c_inhibit_evaluation_warnings--;
return ret;
}
+/* Parse an alignment-specifier.
+
+ C11 6.7.5:
+
+ alignment-specifier:
+ _Alignas ( type-name )
+ _Alignas ( constant-expression )
+*/
+
+static tree
+c_parser_alignas_specifier (c_parser * parser)
+{
+ tree ret = error_mark_node;
+ location_t loc = c_parser_peek_token (parser)->location;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS));
+ c_parser_consume_token (parser);
+ if (!flag_isoc11)
+ {
+ if (flag_isoc99)
+ pedwarn (loc, OPT_pedantic,
+ "ISO C99 does not support %<_Alignas%>");
+ else
+ pedwarn (loc, OPT_pedantic,
+ "ISO C90 does not support %<_Alignas%>");
+ }
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return ret;
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
+ {
+ struct c_type_name *type = c_parser_type_name (parser);
+ if (type != NULL)
+ ret = c_alignof (loc, groktypename (type, NULL, NULL));
+ }
+ else
+ ret = c_parser_expr_no_commas (parser, NULL).value;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return ret;
+}
+
/* Parse a declarator, possibly an abstract declarator (C90 6.5.4,
6.5.5, C99 6.7.5, 6.7.6). If TYPE_SEEN_P then a typedef name may
be redeclared; otherwise it may not. KIND indicates which kind of
struct c_declspecs *quals_attrs = build_null_declspecs ();
struct c_declarator *inner;
c_parser_consume_token (parser);
- c_parser_declspecs (parser, quals_attrs, false, false, true);
+ c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
if (inner == NULL)
return NULL;
bool star_seen;
tree dimen;
c_parser_consume_token (parser);
- c_parser_declspecs (parser, quals_attrs, false, false, true);
+ c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
if (static_seen)
c_parser_consume_token (parser);
if (static_seen && !quals_attrs->declspecs_seen_p)
- c_parser_declspecs (parser, quals_attrs, false, false, true);
+ c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
if (!quals_attrs->declspecs_seen_p)
quals_attrs = NULL;
/* If "static" is present, there must be an array dimension.
if (id_list_ok
&& !attrs
&& c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID
+
+ /* Look ahead to detect typos in type names. */
+ && c_parser_peek_2nd_token (parser)->type != CPP_NAME
+ && c_parser_peek_2nd_token (parser)->type != CPP_MULT
+ && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+ && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE)
{
tree list = NULL_TREE, *nextp = &list;
while (c_parser_next_token_is (parser, CPP_NAME)
}
else
{
- struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs);
+ struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs,
+ NULL);
pop_scope ();
return ret;
}
/* Parse a parameter list (possibly empty), including the closing
parenthesis but not the opening one. ATTRS are the attributes at
- the start of the list. */
+ the start of the list. EXPR is NULL or an expression that needs to
+ be evaluated for the side effects of array size expressions in the
+ parameters. */
static struct c_arg_info *
-c_parser_parms_list_declarator (c_parser *parser, tree attrs)
+c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
{
bool bad_parm = false;
+
/* ??? Following the old parser, forward parameter declarations may
use abstract declarators, and if no real parameter declarations
follow the forward declarations then this is not diagnosed. Also
if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
struct c_arg_info *ret = build_arg_info ();
- /* Suppress -Wold-style-definition for this case. */
- ret->types = error_mark_node;
- error_at (c_parser_peek_token (parser)->location,
- "ISO C requires a named argument before %<...%>");
+
+ if (flag_allow_parameterless_variadic_functions)
+ {
+ /* F (...) is allowed. */
+ ret->types = NULL_TREE;
+ }
+ else
+ {
+ /* Suppress -Wold-style-definition for this case. */
+ ret->types = error_mark_node;
+ error_at (c_parser_peek_token (parser)->location,
+ "ISO C requires a named argument before %<...%>");
+ }
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
if (parm == NULL)
bad_parm = true;
else
- push_parm_decl (parm);
+ push_parm_decl (parm, &expr);
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
tree new_attrs;
c_parser_consume_token (parser);
mark_forward_parm_decls ();
new_attrs = c_parser_attributes (parser);
- return c_parser_parms_list_declarator (parser, new_attrs);
+ return c_parser_parms_list_declarator (parser, new_attrs, expr);
}
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
c_parser_consume_token (parser);
if (bad_parm)
- {
- get_pending_sizes ();
- return NULL;
- }
+ return NULL;
else
- return get_parm_info (false);
+ return get_parm_info (false, expr);
}
if (!c_parser_require (parser, CPP_COMMA,
"expected %<;%>, %<,%> or %<)%>"))
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- get_pending_sizes ();
return NULL;
}
if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
c_parser_consume_token (parser);
if (bad_parm)
- {
- get_pending_sizes ();
- return NULL;
- }
+ return NULL;
else
- return get_parm_info (true);
+ return get_parm_info (true, expr);
}
else
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
- get_pending_sizes ();
return NULL;
}
}
if (parser->error)
return NULL;
c_parser_set_source_position_from_token (token);
- if (token->type == CPP_NAME
- && c_parser_peek_2nd_token (parser)->type != CPP_COMMA
- && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
{
error ("unknown type name %qE", token->value);
parser->error = true;
declspecs_add_attrs (specs, attrs);
attrs = NULL_TREE;
}
- c_parser_declspecs (parser, specs, true, true, true);
+ c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl);
finish_declspecs (specs);
pending_xref_error ();
prefix_attrs = specs->attrs;
specs->attrs = NULL_TREE;
- declarator = c_parser_declarator (parser, specs->type_seen_p,
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
C_DTR_PARM, &dummy);
if (declarator == NULL)
{
c_parser_asm_string_literal (c_parser *parser)
{
tree str;
+ int save_flag = warn_overlength_strings;
+ warn_overlength_strings = 0;
if (c_parser_next_token_is (parser, CPP_STRING))
{
str = c_parser_peek_token (parser)->value;
c_parser_error (parser, "expected string literal");
str = NULL_TREE;
}
+ warn_overlength_strings = save_flag;
return str;
}
return str;
}
+static tree
+c_parser_attribute_any_word (c_parser *parser)
+{
+ tree attr_name = NULL_TREE;
+
+ if (c_parser_next_token_is (parser, CPP_KEYWORD))
+ {
+ /* ??? See comment above about what keywords are accepted here. */
+ bool ok;
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_STATIC:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_INT128:
+ case RID_CONST:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_TYPEDEF:
+ case RID_SHORT:
+ case RID_INLINE:
+ case RID_NORETURN:
+ case RID_VOLATILE:
+ case RID_SIGNED:
+ case RID_AUTO:
+ case RID_RESTRICT:
+ case RID_COMPLEX:
+ case RID_THREAD:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_CANCEL:
+ ok = true;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ if (!ok)
+ return NULL_TREE;
+
+ /* Accept __attribute__((__const)) as __attribute__((const)) etc. */
+ attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword];
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME))
+ attr_name = c_parser_peek_token (parser)->value;
+
+ return attr_name;
+}
+
/* Parse (possibly empty) attributes. This is a GNU extension.
attributes:
c_parser_consume_token (parser);
continue;
}
- if (c_parser_next_token_is (parser, CPP_KEYWORD))
- {
- /* ??? See comment above about what keywords are
- accepted here. */
- bool ok;
- switch (c_parser_peek_token (parser)->keyword)
- {
- case RID_STATIC:
- case RID_UNSIGNED:
- case RID_LONG:
- case RID_INT128:
- case RID_CONST:
- case RID_EXTERN:
- case RID_REGISTER:
- case RID_TYPEDEF:
- case RID_SHORT:
- case RID_INLINE:
- case RID_VOLATILE:
- case RID_SIGNED:
- case RID_AUTO:
- case RID_RESTRICT:
- case RID_COMPLEX:
- case RID_THREAD:
- case RID_INT:
- case RID_CHAR:
- case RID_FLOAT:
- case RID_DOUBLE:
- case RID_VOID:
- case RID_DFLOAT32:
- case RID_DFLOAT64:
- case RID_DFLOAT128:
- case RID_BOOL:
- case RID_FRACT:
- case RID_ACCUM:
- case RID_SAT:
- ok = true;
- break;
- default:
- ok = false;
- break;
- }
- if (!ok)
- break;
- /* Accept __attribute__((__const)) as __attribute__((const))
- etc. */
- attr_name
- = ridpointers[(int) c_parser_peek_token (parser)->keyword];
- }
- else
- attr_name = c_parser_peek_token (parser)->value;
+
+ attr_name = c_parser_attribute_any_word (parser);
+ if (attr_name == NULL)
+ break;
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
{
/* Parse the attribute contents. If they start with an
identifier which is followed by a comma or close
parenthesis, then the arguments start with that
- identifier; otherwise they are an expression list. */
+ identifier; otherwise they are an expression list.
+ In objective-c the identifier may be a classname. */
if (c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_token (parser)->id_kind == C_ID_ID
+ && (c_parser_peek_token (parser)->id_kind == C_ID_ID
+ || (c_dialect_objc ()
+ && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
&& ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
|| (c_parser_peek_2nd_token (parser)->type
== CPP_CLOSE_PAREN)))
struct c_declarator *declarator;
struct c_type_name *ret;
bool dummy = false;
- c_parser_declspecs (parser, specs, false, true, true);
+ c_parser_declspecs (parser, specs, false, true, true, cla_prefer_type);
if (!specs->declspecs_seen_p)
{
c_parser_error (parser, "expected specifier-qualifier-list");
return NULL;
}
- pending_xref_error ();
- finish_declspecs (specs);
- declarator = c_parser_declarator (parser, specs->type_seen_p,
+ if (specs->type != error_mark_node)
+ {
+ pending_xref_error ();
+ finish_declspecs (specs);
+ }
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
C_DTR_ABSTRACT, &dummy);
if (declarator == NULL)
return NULL;
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
mexpr.value
- = objc_build_message_expr (build_tree_list (rec, args));
+ = objc_build_message_expr (rec, args);
mexpr.original_code = ERROR_MARK;
mexpr.original_type = NULL;
/* Now parse and process the remainder of the
c_parser_label (parser);
}
else if (!last_label
- && c_parser_next_token_starts_declaration (parser))
+ && c_parser_next_tokens_start_declaration (parser))
{
last_label = false;
mark_valid_location_for_stdc_pragma (false);
- c_parser_declaration_or_fndef (parser, true, true, true, true, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
if (last_stmt)
pedwarn_c90 (loc,
(pedantic && !flag_isoc99)
last_label = false;
mark_valid_location_for_stdc_pragma (false);
c_parser_declaration_or_fndef (parser, true, true, true, true,
- true);
+ true, NULL);
/* Following the old parser, __extension__ does not
disable this diagnostic. */
restore_extension_diagnostics (ext);
}
if (label)
{
- if (c_parser_next_token_starts_declaration (parser)
- && !(c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ if (c_parser_next_tokens_start_declaration (parser))
{
error_at (c_parser_peek_token (parser)->location,
"a label can only be part of a statement and "
c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
/*static_assert_ok*/ true,
/*nested*/ true, /*empty_ok*/ false,
- /*start_attr_ok*/ true);
+ /*start_attr_ok*/ true, NULL);
}
}
}
atomic-directive expression-statement
ordered-construct:
- ordered-directive structured-block */
+ ordered-directive structured-block
+
+ Transactional Memory:
+
+ statement:
+ transaction-statement
+ transaction-cancel-statement
+*/
static void
c_parser_statement (c_parser *parser)
}
else if (c_parser_next_token_is (parser, CPP_MULT))
{
+ tree val;
+
c_parser_consume_token (parser);
- stmt = c_finish_goto_ptr (loc,
- c_parser_expression (parser).value);
+ val = c_parser_expression (parser).value;
+ mark_exp_read (val);
+ stmt = c_finish_goto_ptr (loc, val);
}
else
c_parser_error (parser, "expected identifier or %<*%>");
case RID_ASM:
stmt = c_parser_asm_statement (parser);
break;
- case RID_THROW:
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_RELAXED:
+ stmt = c_parser_transaction (parser,
+ c_parser_peek_token (parser)->keyword);
+ break;
+ case RID_TRANSACTION_CANCEL:
+ stmt = c_parser_transaction_cancel (parser);
+ goto expect_semicolon;
+ case RID_AT_THROW:
gcc_assert (c_dialect_objc ());
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
goto expect_semicolon;
}
break;
- case RID_TRY:
+ case RID_AT_TRY:
gcc_assert (c_dialect_objc ());
- c_parser_objc_try_catch_statement (parser);
+ c_parser_objc_try_catch_finally_statement (parser);
break;
case RID_AT_SYNCHRONIZED:
gcc_assert (c_dialect_objc ());
Note in particular that the nested function does not include a
trailing ';', whereas the "declaration" production includes one.
Also, can we reject bad declarations earlier and cheaper than
- check_for_loop_decls? */
+ check_for_loop_decls?
+
+ In Objective-C, there are two additional variants:
+
+ foreach-statement:
+ for ( expression in expresssion ) statement
+ for ( declaration in expression ) statement
+
+ This is inconsistent with C, because the second variant is allowed
+ even if c99 is not enabled.
+
+ The rest of the comment documents these Objective-C foreach-statement.
+
+ Here is the canonical example of the first variant:
+ for (object in array) { do something with object }
+ we call the first expression ("object") the "object_expression" and
+ the second expression ("array") the "collection_expression".
+ object_expression must be an lvalue of type "id" (a generic Objective-C
+ object) because the loop works by assigning to object_expression the
+ various objects from the collection_expression. collection_expression
+ must evaluate to something of type "id" which responds to the method
+ countByEnumeratingWithState:objects:count:.
+
+ The canonical example of the second variant is:
+ for (id object in array) { do something with object }
+ which is completely equivalent to
+ {
+ id object;
+ for (object in array) { do something with object }
+ }
+ Note that initizializing 'object' in some way (eg, "for ((object =
+ xxx) in array) { do something with object }") is possibly
+ technically valid, but completely pointless as 'object' will be
+ assigned to something else as soon as the loop starts. We should
+ most likely reject it (TODO).
+
+ The beginning of the Objective-C foreach-statement looks exactly
+ like the beginning of the for-statement, and we can tell it is a
+ foreach-statement only because the initial declaration or
+ expression is terminated by 'in' instead of ';'.
+*/
static void
c_parser_for_statement (c_parser *parser)
{
tree block, cond, incr, save_break, save_cont, body;
+ /* The following are only used when parsing an ObjC foreach statement. */
+ tree object_expression;
+ /* Silence the bogus uninitialized warning. */
+ tree collection_expression = NULL;
location_t loc = c_parser_peek_token (parser)->location;
location_t for_loc = c_parser_peek_token (parser)->location;
+ bool is_foreach_statement = false;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
c_parser_consume_token (parser);
- block = c_begin_compound_stmt (flag_isoc99);
+ /* Open a compound statement in Objective-C as well, just in case this is
+ as foreach expression. */
+ block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ());
+ cond = error_mark_node;
+ incr = error_mark_node;
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
/* Parse the initialization declaration or expression. */
+ object_expression = error_mark_node;
+ parser->objc_could_be_foreach_context = c_dialect_objc ();
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
+ parser->objc_could_be_foreach_context = false;
c_parser_consume_token (parser);
c_finish_expr_stmt (loc, NULL_TREE);
}
- else if (c_parser_next_token_starts_declaration (parser))
+ else if (c_parser_next_tokens_start_declaration (parser))
{
- c_parser_declaration_or_fndef (parser, true, true, true, true, true);
- check_for_loop_decls (for_loc);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+ &object_expression);
+ parser->objc_could_be_foreach_context = false;
+
+ if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ c_parser_consume_token (parser);
+ is_foreach_statement = true;
+ if (check_for_loop_decls (for_loc, true) == NULL_TREE)
+ c_parser_error (parser, "multiple iterating variables in fast enumeration");
+ }
+ else
+ check_for_loop_decls (for_loc, flag_isoc99);
}
else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
{
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
c_parser_declaration_or_fndef (parser, true, true, true, true,
- true);
+ true, &object_expression);
+ parser->objc_could_be_foreach_context = false;
+
restore_extension_diagnostics (ext);
- check_for_loop_decls (for_loc);
+ if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ c_parser_consume_token (parser);
+ is_foreach_statement = true;
+ if (check_for_loop_decls (for_loc, true) == NULL_TREE)
+ c_parser_error (parser, "multiple iterating variables in fast enumeration");
+ }
+ else
+ check_for_loop_decls (for_loc, flag_isoc99);
}
else
goto init_expr;
else
{
init_expr:
- c_finish_expr_stmt (loc, c_parser_expression (parser).value);
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ {
+ tree init_expression;
+ init_expression = c_parser_expression (parser).value;
+ parser->objc_could_be_foreach_context = false;
+ if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ c_parser_consume_token (parser);
+ is_foreach_statement = true;
+ if (! lvalue_p (init_expression))
+ c_parser_error (parser, "invalid iterating variable in fast enumeration");
+ object_expression = c_fully_fold (init_expression, false, NULL);
+ }
+ else
+ {
+ c_finish_expr_stmt (loc, init_expression);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ }
}
- /* Parse the loop condition. */
- if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ /* Parse the loop condition. In the case of a foreach
+ statement, there is no loop condition. */
+ gcc_assert (!parser->objc_could_be_foreach_context);
+ if (!is_foreach_statement)
{
- c_parser_consume_token (parser);
- cond = NULL_TREE;
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ cond = NULL_TREE;
+ }
+ else
+ {
+ cond = c_parser_condition (parser);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
}
- else
+ /* Parse the increment expression (the third expression in a
+ for-statement). In the case of a foreach-statement, this is
+ the expression that follows the 'in'. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
- cond = c_parser_condition (parser);
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ if (is_foreach_statement)
+ {
+ c_parser_error (parser, "missing collection in fast enumeration");
+ collection_expression = error_mark_node;
+ }
+ else
+ incr = c_process_expr_stmt (loc, NULL_TREE);
}
- /* Parse the increment expression. */
- if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- incr = c_process_expr_stmt (loc, NULL_TREE);
else
- incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+ {
+ if (is_foreach_statement)
+ collection_expression = c_fully_fold (c_parser_expression (parser).value,
+ false, NULL);
+ else
+ incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+ }
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
- else
- {
- cond = error_mark_node;
- incr = error_mark_node;
- }
save_break = c_break_label;
c_break_label = NULL_TREE;
save_cont = c_cont_label;
c_cont_label = NULL_TREE;
body = c_parser_c99_block_statement (parser);
- c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
- add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+ if (is_foreach_statement)
+ objc_finish_foreach_loop (loc, object_expression, collection_expression, body, c_break_label, c_cont_label);
+ else
+ c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99 || c_dialect_objc ()));
c_break_label = save_break;
c_cont_label = save_cont;
}
gcc_assert (!after || c_dialect_objc ());
- cond = c_parser_binary_expression (parser, after);
+ cond = c_parser_binary_expression (parser, after, PREC_NONE);
if (c_parser_next_token_is_not (parser, CPP_QUERY))
return cond;
/* Parse a binary expression; that is, a logical-OR-expression (C90
6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is
an Objective-C message expression which is the primary-expression
- starting the expression as an initializer.
+ starting the expression as an initializer. PREC is the starting
+ precedence, usually PREC_NONE.
multiplicative-expression:
cast-expression
*/
static struct c_expr
-c_parser_binary_expression (c_parser *parser, struct c_expr *after)
+c_parser_binary_expression (c_parser *parser, struct c_expr *after,
+ enum c_parser_prec prec)
{
/* A binary expression is parsed using operator-precedence parsing,
with the operands being cast expressions. All the binary
expressions, we also need to adjust c_inhibit_evaluation_warnings
as appropriate when the operators are pushed and popped. */
- /* The precedence levels, where 0 is a dummy lowest level used for
- the bottom of the stack. */
- enum prec {
- PREC_NONE,
- PREC_LOGOR,
- PREC_LOGAND,
- PREC_BITOR,
- PREC_BITXOR,
- PREC_BITAND,
- PREC_EQ,
- PREC_REL,
- PREC_SHIFT,
- PREC_ADD,
- PREC_MULT,
- NUM_PRECS
- };
struct {
/* The expression at this stack level. */
struct c_expr expr;
/* The precedence of the operator on its left, PREC_NONE at the
bottom of the stack. */
- enum prec prec;
+ enum c_parser_prec prec;
/* The operation on its left. */
enum tree_code op;
/* The source location of this operation. */
gcc_assert (!after || c_dialect_objc ());
stack[0].loc = c_parser_peek_token (parser)->location;
stack[0].expr = c_parser_cast_expression (parser, after);
- stack[0].prec = PREC_NONE;
+ stack[0].prec = prec;
sp = 0;
while (true)
{
- enum prec oprec;
+ enum c_parser_prec oprec;
enum tree_code ocode;
if (parser->error)
goto out;
goto out;
}
binary_loc = c_parser_peek_token (parser)->location;
- c_parser_consume_token (parser);
while (oprec <= stack[sp].prec)
- POP;
+ {
+ if (sp == 0)
+ goto out;
+ POP;
+ }
+ c_parser_consume_token (parser);
switch (ocode)
{
case TRUTH_ANDIF_EXPR:
/* If the expression begins with a parenthesized type name, it may
be either a cast or a compound literal; we need to see whether
the next character is '{' to tell the difference. If not, it is
- an unary expression. */
+ an unary expression. Full detection of unknown typenames here
+ would require a 3-token lookahead. */
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_typename (c_parser_peek_2nd_token (parser)))
{
__alignof__ ( type-name )
&& identifier
+ (C11 permits _Alignof with type names only.)
+
unary-operator: one of
__extension__ __real__ __imag__
+ Transactional Memory:
+
+ unary-expression:
+ transaction-expression
+
In addition, the GNU syntax treats ++ and -- as unary operators, so
they may be applied to cast expressions with errors for non-lvalues
given later. */
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (exp_loc, op);
return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_RELAXED:
+ return c_parser_transaction_expression (parser,
+ c_parser_peek_token (parser)->keyword);
default:
return c_parser_postfix_expression (parser);
}
{
struct c_expr expr;
location_t loc = c_parser_peek_token (parser)->location;
+ tree alignof_spelling = c_parser_peek_token (parser)->value;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
+ /* A diagnostic is not required for the use of this identifier in
+ the implementation namespace; only diagnose it for the C11
+ spelling because of existing code using the other spellings. */
+ if (!flag_isoc11
+ && strcmp (IDENTIFIER_POINTER (alignof_spelling), "_Alignof") == 0)
+ {
+ if (flag_isoc99)
+ pedwarn (loc, OPT_pedantic, "ISO C99 does not support %qE",
+ alignof_spelling);
+ else
+ pedwarn (loc, OPT_pedantic, "ISO C90 does not support %qE",
+ alignof_spelling);
+ }
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
in_alignof++;
mark_exp_read (expr.value);
c_inhibit_evaluation_warnings--;
in_alignof--;
+ pedwarn (loc, OPT_pedantic, "ISO C does not allow %<%E (expression)%>",
+ alignof_spelling);
ret.value = c_alignof_expr (loc, expr.value);
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
}
}
+/* Helper function to read arguments of builtins which are interfaces
+ for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and
+ others. The name of the builtin is passed using BNAME parameter.
+ Function returns true if there were no errors while parsing and
+ stores the arguments in CEXPR_LIST. */
+static bool
+c_parser_get_builtin_args (c_parser *parser, const char *bname,
+ VEC(c_expr_t,gc) **ret_cexpr_list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ VEC (c_expr_t,gc) *cexpr_list;
+ c_expr_t expr;
+
+ *ret_cexpr_list = NULL;
+ if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+ {
+ error_at (loc, "cannot take address of %qs", bname);
+ return false;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ return true;
+ }
+
+ expr = c_parser_expr_no_commas (parser, NULL);
+ cexpr_list = VEC_alloc (c_expr_t, gc, 1);
+ C_EXPR_APPEND (cexpr_list, expr);
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ expr = c_parser_expr_no_commas (parser, NULL);
+ C_EXPR_APPEND (cexpr_list, expr);
+ }
+
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ return false;
+
+ *ret_cexpr_list = cexpr_list;
+ return true;
+}
+
+
/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).
postfix-expression:
assignment-expression ,
assignment-expression )
__builtin_types_compatible_p ( type-name , type-name )
+ __builtin_complex ( assignment-expression , assignment-expression )
+ __builtin_shuffle ( assignment-expression , assignment-expression )
+ __builtin_shuffle ( assignment-expression ,
+ assignment-expression ,
+ assignment-expression, )
offsetof-member-designator:
identifier
@protocol ( identifier )
@encode ( type-name )
objc-string-literal
+ Classname . identifier
*/
static struct c_expr
c_parser_postfix_expression (c_parser *parser)
{
- struct c_expr expr, e1, e2, e3;
+ struct c_expr expr, e1;
struct c_type_name *t1, *t2;
location_t loc = c_parser_peek_token (parser)->location;;
expr.original_code = ERROR_MARK;
c_parser_consume_token (parser);
break;
case CPP_NAME:
- if (c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ switch (c_parser_peek_token (parser)->id_kind)
{
+ case C_ID_ID:
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ expr.value = build_external_ref (loc, id,
+ (c_parser_peek_token (parser)->type
+ == CPP_OPEN_PAREN),
+ &expr.original_type);
+ break;
+ }
+ case C_ID_CLASSNAME:
+ {
+ /* Here we parse the Objective-C 2.0 Class.name dot
+ syntax. */
+ tree class_name = c_parser_peek_token (parser)->value;
+ tree component;
+ c_parser_consume_token (parser);
+ gcc_assert (c_dialect_objc ());
+ if (!c_parser_require (parser, CPP_DOT, "expected %<.%>"))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.value = error_mark_node;
+ break;
+ }
+ component = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ expr.value = objc_build_class_component_ref (class_name,
+ component);
+ break;
+ }
+ default:
c_parser_error (parser, "expected expression");
expr.value = error_mark_node;
break;
}
- {
- tree id = c_parser_peek_token (parser)->value;
- c_parser_consume_token (parser);
- expr.value = build_external_ref (loc, id,
- (c_parser_peek_token (parser)->type
- == CPP_OPEN_PAREN),
- &expr.original_type);
- }
break;
case CPP_OPEN_PAREN:
/* A parenthesized expression, statement expression or compound
c_parser_consume_token (parser);
brace_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
- if (cur_stmt_list == NULL)
+ if (!building_stmt_list_p ())
{
error_at (loc, "braced-group within expression allowed "
"only inside a function");
}
t1 = c_parser_type_name (parser);
if (t1 == NULL)
- {
- expr.value = error_mark_node;
- break;
- }
+ parser->error = true;
if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ gcc_assert (parser->error);
+ if (parser->error)
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
expr.value = error_mark_node;
break;
}
+
{
tree type = groktypename (t1, NULL, NULL);
tree offsetof_ref;
c_parser_error (parser, "expected identifier");
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
- expr.value = fold_offsetof (offsetof_ref, NULL_TREE);
+ expr.value = fold_offsetof (offsetof_ref);
}
break;
case RID_CHOOSE_EXPR:
- c_parser_consume_token (parser);
- if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
- {
- expr.value = error_mark_node;
- break;
- }
- loc = c_parser_peek_token (parser)->location;
- e1 = c_parser_expr_no_commas (parser, NULL);
- if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
- {
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- expr.value = error_mark_node;
- break;
- }
- e2 = c_parser_expr_no_commas (parser, NULL);
- if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
- {
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- expr.value = error_mark_node;
- break;
- }
- e3 = c_parser_expr_no_commas (parser, NULL);
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
- "expected %<)%>");
{
+ VEC (c_expr_t, gc) *cexpr_list;
+ c_expr_t *e1_p, *e2_p, *e3_p;
tree c;
- c = e1.value;
- mark_exp_read (e2.value);
- mark_exp_read (e3.value);
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_choose_expr",
+ &cexpr_list))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+
+ if (VEC_length (c_expr_t, cexpr_list) != 3)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_choose_expr%>");
+ expr.value = error_mark_node;
+ break;
+ }
+
+ e1_p = VEC_index (c_expr_t, cexpr_list, 0);
+ e2_p = VEC_index (c_expr_t, cexpr_list, 1);
+ e3_p = VEC_index (c_expr_t, cexpr_list, 2);
+
+ c = e1_p->value;
+ mark_exp_read (e2_p->value);
+ mark_exp_read (e3_p->value);
if (TREE_CODE (c) != INTEGER_CST
|| !INTEGRAL_TYPE_P (TREE_TYPE (c)))
error_at (loc,
"first argument to %<__builtin_choose_expr%> not"
" a constant");
constant_expression_warning (c);
- expr = integer_zerop (c) ? e3 : e2;
+ expr = integer_zerop (c) ? *e3_p : *e2_p;
+ break;
}
- break;
case RID_TYPES_COMPATIBLE_P:
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
"expected %<)%>");
{
tree e1, e2;
+ e1 = groktypename (t1, NULL, NULL);
+ e2 = groktypename (t2, NULL, NULL);
+ if (e1 == error_mark_node || e2 == error_mark_node)
+ {
+ expr.value = error_mark_node;
+ break;
+ }
- e1 = TYPE_MAIN_VARIANT (groktypename (t1, NULL, NULL));
- e2 = TYPE_MAIN_VARIANT (groktypename (t2, NULL, NULL));
+ e1 = TYPE_MAIN_VARIANT (e1);
+ e2 = TYPE_MAIN_VARIANT (e2);
expr.value
= comptypes (e1, e2) ? integer_one_node : integer_zero_node;
}
break;
+ case RID_BUILTIN_COMPLEX:
+ {
+ VEC(c_expr_t, gc) *cexpr_list;
+ c_expr_t *e1_p, *e2_p;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_complex",
+ &cexpr_list))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+
+ if (VEC_length (c_expr_t, cexpr_list) != 2)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_complex%>");
+ expr.value = error_mark_node;
+ break;
+ }
+
+ e1_p = VEC_index (c_expr_t, cexpr_list, 0);
+ e2_p = VEC_index (c_expr_t, cexpr_list, 1);
+
+ mark_exp_read (e1_p->value);
+ if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR)
+ e1_p->value = convert (TREE_TYPE (e1_p->value),
+ TREE_OPERAND (e1_p->value, 0));
+ mark_exp_read (e2_p->value);
+ if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR)
+ e2_p->value = convert (TREE_TYPE (e2_p->value),
+ TREE_OPERAND (e2_p->value, 0));
+ if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1_p->value))
+ || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1_p->value))
+ || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2_p->value))
+ || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2_p->value)))
+ {
+ error_at (loc, "%<__builtin_complex%> operand "
+ "not of real binary floating-point type");
+ expr.value = error_mark_node;
+ break;
+ }
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (e1_p->value))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (e2_p->value)))
+ {
+ error_at (loc,
+ "%<__builtin_complex%> operands of different types");
+ expr.value = error_mark_node;
+ break;
+ }
+ if (!flag_isoc99)
+ pedwarn (loc, OPT_pedantic,
+ "ISO C90 does not support complex types");
+ expr.value = build2 (COMPLEX_EXPR,
+ build_complex_type
+ (TYPE_MAIN_VARIANT
+ (TREE_TYPE (e1_p->value))),
+ e1_p->value, e2_p->value);
+ break;
+ }
+ case RID_BUILTIN_SHUFFLE:
+ {
+ VEC(c_expr_t,gc) *cexpr_list;
+ unsigned int i;
+ c_expr_t *p;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_shuffle",
+ &cexpr_list))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+
+ FOR_EACH_VEC_ELT (c_expr_t, cexpr_list, i, p)
+ mark_exp_read (p->value);
+
+ if (VEC_length (c_expr_t, cexpr_list) == 2)
+ expr.value =
+ c_build_vec_perm_expr
+ (loc, VEC_index (c_expr_t, cexpr_list, 0)->value,
+ NULL_TREE, VEC_index (c_expr_t, cexpr_list, 1)->value);
+
+ else if (VEC_length (c_expr_t, cexpr_list) == 3)
+ expr.value =
+ c_build_vec_perm_expr
+ (loc, VEC_index (c_expr_t, cexpr_list, 0)->value,
+ VEC_index (c_expr_t, cexpr_list, 1)->value,
+ VEC_index (c_expr_t, cexpr_list, 2)->value);
+ else
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_shuffle%>");
+ expr.value = error_mark_node;
+ }
+ break;
+ }
case RID_AT_SELECTOR:
gcc_assert (c_dialect_objc ());
c_parser_consume_token (parser);
args = c_parser_objc_message_args (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
- expr.value = objc_build_message_expr (build_tree_list (receiver,
- args));
+ expr.value = objc_build_message_expr (receiver, args);
break;
}
/* Else fall through to report error. */
objc-class-instance-variables[opt]
@interface identifier ( identifier ) objc-protocol-refs[opt]
objc-methodprotolist @end
+ @interface identifier ( ) objc-protocol-refs[opt]
+ objc-methodprotolist @end
@implementation identifier ( identifier )
objc-superclass:
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
+ /* We have a category or class extension. */
tree id2;
tree proto = NULL_TREE;
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
- c_parser_error (parser, "expected identifier");
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- return;
+ if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ /* We have a class extension. */
+ id2 = NULL_TREE;
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier or %<)%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return;
+ }
+ }
+ else
+ {
+ id2 = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
}
- id2 = c_parser_peek_token (parser)->value;
- c_parser_consume_token (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
if (!iface_p)
{
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
- "extra semicolon in struct or union specified");
+ "extra semicolon");
c_parser_consume_token (parser);
continue;
}
break;
}
/* Parse any objc-visibility-spec. */
- if (c_parser_next_token_is_keyword (parser, RID_PRIVATE))
+ if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE))
+ {
+ c_parser_consume_token (parser);
+ objc_set_visibility (OBJC_IVAR_VIS_PRIVATE);
+ continue;
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED))
{
c_parser_consume_token (parser);
- objc_set_visibility (2);
+ objc_set_visibility (OBJC_IVAR_VIS_PROTECTED);
continue;
}
- else if (c_parser_next_token_is_keyword (parser, RID_PROTECTED))
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC))
{
c_parser_consume_token (parser);
- objc_set_visibility (0);
+ objc_set_visibility (OBJC_IVAR_VIS_PUBLIC);
continue;
}
- else if (c_parser_next_token_is_keyword (parser, RID_PUBLIC))
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE))
{
c_parser_consume_token (parser);
- objc_set_visibility (1);
+ objc_set_visibility (OBJC_IVAR_VIS_PACKAGE);
continue;
}
else if (c_parser_next_token_is (parser, CPP_PRAGMA))
/* Parse some comma-separated declarations. */
decls = c_parser_struct_declaration (parser);
- {
- /* Comma-separated instance variables are chained together in
- reverse order; add them one by one. */
- tree ivar = nreverse (decls);
- for (; ivar; ivar = DECL_CHAIN (ivar))
- objc_add_instance_variable (copy_node (ivar));
- }
+ if (decls == NULL)
+ {
+ /* There is a syntax error. We want to skip the offending
+ tokens up to the next ';' (included) or '}'
+ (excluded). */
+
+ /* First, skip manually a ')' or ']'. This is because they
+ reduce the nesting level, so c_parser_skip_until_found()
+ wouldn't be able to skip past them. */
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE)
+ c_parser_consume_token (parser);
+
+ /* Then, do the standard skipping. */
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+
+ /* We hopefully recovered. Start normal parsing again. */
+ parser->error = false;
+ continue;
+ }
+ else
+ {
+ /* Comma-separated instance variables are chained together
+ in reverse order; add them one by one. */
+ tree ivar = nreverse (decls);
+ for (; ivar; ivar = DECL_CHAIN (ivar))
+ objc_add_instance_variable (copy_node (ivar));
+ }
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
}
static void
c_parser_objc_class_declaration (c_parser *parser)
{
- tree list = NULL_TREE;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_CLASS));
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS));
c_parser_consume_token (parser);
/* Any identifiers, including those declared as type names, are OK
here. */
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
c_parser_error (parser, "expected identifier");
- break;
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ parser->error = false;
+ return;
}
id = c_parser_peek_token (parser)->value;
- list = chainon (list, build_tree_list (NULL_TREE, id));
+ objc_declare_class (id);
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
break;
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- objc_declare_class (list);
}
/* Parse an objc-alias-declaration.
if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
|| c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON)
{
- tree list = NULL_TREE;
/* Any identifiers, including those declared as type names, are
OK here. */
while (true)
break;
}
id = c_parser_peek_token (parser)->value;
- list = chainon (list, build_tree_list (NULL_TREE, id));
+ objc_declare_protocol (id, attributes);
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
break;
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- objc_declare_protocols (list);
}
else
{
objc-method-type:
+
-
-*/
-static enum tree_code
+ Return true if it is a class method (+) and false if it is
+ an instance method (-).
+*/
+static inline bool
c_parser_objc_method_type (c_parser *parser)
{
switch (c_parser_peek_token (parser)->type)
{
case CPP_PLUS:
c_parser_consume_token (parser);
- return PLUS_EXPR;
+ return true;
case CPP_MINUS:
c_parser_consume_token (parser);
- return MINUS_EXPR;
+ return false;
default:
gcc_unreachable ();
}
static void
c_parser_objc_method_definition (c_parser *parser)
{
- enum tree_code type = c_parser_objc_method_type (parser);
- tree decl, attributes = NULL_TREE;
- objc_set_method_type (type);
+ bool is_class_method = c_parser_objc_method_type (parser);
+ tree decl, attributes = NULL_TREE, expr = NULL_TREE;
parser->objc_pq_context = true;
- decl = c_parser_objc_method_decl (parser, &attributes);
+ decl = c_parser_objc_method_decl (parser, is_class_method, &attributes,
+ &expr);
if (decl == error_mark_node)
return; /* Bail here. */
}
parser->objc_pq_context = false;
- if (objc_start_method_definition (decl, attributes))
+ if (objc_start_method_definition (is_class_method, decl, attributes, expr))
{
add_stmt (c_parser_compound_statement (parser));
objc_finish_method_definition (current_function_decl);
else
{
/* This code is executed when we find a method definition
- outside of an @implementation context. Parse the method (to
- keep going) but do not emit any code.
+ outside of an @implementation context (or invalid for other
+ reasons). Parse the method (to keep going) but do not emit
+ any code.
*/
c_parser_compound_statement (parser);
}
objc-methodprotolist objc-methodproto
objc-methodprotolist declaration
objc-methodprotolist ;
+ @optional
+ @required
The declaration is a data definition, which may be missing
declaration specifiers under the same rules and diagnostics as
default:
if (c_parser_next_token_is_keyword (parser, RID_AT_END))
return;
- c_parser_declaration_or_fndef (parser, false, false, true,
- false, true);
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY))
+ c_parser_objc_at_property_declaration (parser);
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL))
+ {
+ objc_set_method_opt (true);
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_REQUIRED))
+ {
+ objc_set_method_opt (false);
+ c_parser_consume_token (parser);
+ }
+ else
+ c_parser_declaration_or_fndef (parser, false, false, true,
+ false, true, NULL);
break;
}
}
static void
c_parser_objc_methodproto (c_parser *parser)
{
- enum tree_code type = c_parser_objc_method_type (parser);
+ bool is_class_method = c_parser_objc_method_type (parser);
tree decl, attributes = NULL_TREE;
- objc_set_method_type (type);
+
/* Remember protocol qualifiers in prototypes. */
parser->objc_pq_context = true;
- decl = c_parser_objc_method_decl (parser, &attributes);
+ decl = c_parser_objc_method_decl (parser, is_class_method, &attributes,
+ NULL);
/* Forget protocol qualifiers now. */
parser->objc_pq_context = false;
}
if (decl != error_mark_node)
- objc_add_method_declaration (decl, attributes);
+ objc_add_method_declaration (is_class_method, decl, attributes);
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
*/
static tree
-c_parser_objc_method_decl (c_parser *parser, tree *attributes)
+c_parser_objc_method_decl (c_parser *parser, bool is_class_method,
+ tree *attributes, tree *expr)
{
tree type = NULL_TREE;
tree sel;
if (parm == NULL)
break;
parms = chainon (parms,
- build_tree_list (NULL_TREE, grokparm (parm)));
+ build_tree_list (NULL_TREE, grokparm (parm, expr)));
}
sel = list;
}
if (attr_err)
return error_mark_node;
- return objc_build_method_signature (type, sel, parms, ellipsis);
+ return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis);
}
/* Parse an objc-type-name.
|| token->keyword == RID_BYREF
|| token->keyword == RID_ONEWAY))
{
- quals = chainon (quals, build_tree_list (NULL_TREE, token->value));
+ quals = chainon (build_tree_list (NULL_TREE, token->value), quals);
c_parser_consume_token (parser);
}
else
break;
}
- if (c_parser_next_token_starts_typename (parser))
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
type_name = c_parser_type_name (parser);
if (type_name)
type = groktypename (type_name, NULL, NULL);
+
+ /* If the type is unknown, and error has already been produced and
+ we need to recover from the error. In that case, use NULL_TREE
+ for the type, as if no type had been specified; this will use the
+ default type ('id') which is good for error recovery. */
+ if (type == error_mark_node)
+ type = NULL_TREE;
+
return build_tree_list (quals, type);
}
return list;
}
-/* Parse an objc-try-catch-statement.
+/* Parse an objc-try-catch-finally-statement.
- objc-try-catch-statement:
+ objc-try-catch-finally-statement:
@try compound-statement objc-catch-list[opt]
@try compound-statement objc-catch-list[opt] @finally compound-statement
objc-catch-list:
- @catch ( parameter-declaration ) compound-statement
- objc-catch-list @catch ( parameter-declaration ) compound-statement
-*/
+ @catch ( objc-catch-parameter-declaration ) compound-statement
+ objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement
+
+ objc-catch-parameter-declaration:
+ parameter-declaration
+ '...'
+
+ where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS.
+
+ PS: This function is identical to cp_parser_objc_try_catch_finally_statement
+ for C++. Keep them in sync. */
static void
-c_parser_objc_try_catch_statement (c_parser *parser)
+c_parser_objc_try_catch_finally_statement (c_parser *parser)
{
- location_t loc;
+ location_t location;
tree stmt;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRY));
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY));
c_parser_consume_token (parser);
- loc = c_parser_peek_token (parser)->location;
+ location = c_parser_peek_token (parser)->location;
+ objc_maybe_warn_exceptions (location);
stmt = c_parser_compound_statement (parser);
- objc_begin_try_stmt (loc, stmt);
- while (c_parser_next_token_is_keyword (parser, RID_CATCH))
+ objc_begin_try_stmt (location, stmt);
+
+ while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH))
{
struct c_parm *parm;
+ tree parameter_declaration = error_mark_node;
+ bool seen_open_paren = false;
+
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
- break;
- parm = c_parser_parameter_declaration (parser, NULL_TREE);
- if (parm == NULL)
+ seen_open_paren = true;
+ if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- break;
+ /* We have "@catch (...)" (where the '...' are literally
+ what is in the code). Skip the '...'.
+ parameter_declaration is set to NULL_TREE, and
+ objc_being_catch_clauses() knows that that means
+ '...'. */
+ c_parser_consume_token (parser);
+ parameter_declaration = NULL_TREE;
}
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
- objc_begin_catch_clause (grokparm (parm));
+ else
+ {
+ /* We have "@catch (NSException *exception)" or something
+ like that. Parse the parameter declaration. */
+ parm = c_parser_parameter_declaration (parser, NULL_TREE);
+ if (parm == NULL)
+ parameter_declaration = error_mark_node;
+ else
+ parameter_declaration = grokparm (parm, NULL);
+ }
+ if (seen_open_paren)
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ else
+ {
+ /* If there was no open parenthesis, we are recovering from
+ an error, and we are trying to figure out what mistake
+ the user has made. */
+
+ /* If there is an immediate closing parenthesis, the user
+ probably forgot the opening one (ie, they typed "@catch
+ NSException *e)". Parse the closing parenthesis and keep
+ going. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+
+ /* If these is no immediate closing parenthesis, the user
+ probably doesn't know that parenthesis are required at
+ all (ie, they typed "@catch NSException *e"). So, just
+ forget about the closing parenthesis and keep going. */
+ }
+ objc_begin_catch_clause (parameter_declaration);
if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
c_parser_compound_statement_nostart (parser);
objc_finish_catch_clause ();
}
if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY))
{
- location_t finloc;
- tree finstmt;
c_parser_consume_token (parser);
- finloc = c_parser_peek_token (parser)->location;
- finstmt = c_parser_compound_statement (parser);
- objc_build_finally_clause (finloc, finstmt);
+ location = c_parser_peek_token (parser)->location;
+ stmt = c_parser_compound_statement (parser);
+ objc_build_finally_clause (location, stmt);
}
objc_finish_try_stmt ();
}
gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED));
c_parser_consume_token (parser);
loc = c_parser_peek_token (parser)->location;
+ objc_maybe_warn_exceptions (loc);
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
expr = c_parser_expression (parser).value;
c_parser_objc_diagnose_bad_element_prefix (c_parser *parser,
struct c_declspecs *specs)
{
- if (!specs->declspecs_seen_p || specs->type_seen_p || specs->non_sc_seen_p)
+ if (!specs->declspecs_seen_p || specs->non_sc_seen_p
+ || specs->typespec_kind != ctsk_none)
{
c_parser_error (parser,
"no type or storage class may be specified here,");
}
return false;
}
+
+/* Parse an Objective-C @property declaration. The syntax is:
+
+ objc-property-declaration:
+ '@property' objc-property-attributes[opt] struct-declaration ;
+
+ objc-property-attributes:
+ '(' objc-property-attribute-list ')'
+
+ objc-property-attribute-list:
+ objc-property-attribute
+ objc-property-attribute-list, objc-property-attribute
+
+ objc-property-attribute
+ 'getter' = identifier
+ 'setter' = identifier
+ 'readonly'
+ 'readwrite'
+ 'assign'
+ 'retain'
+ 'copy'
+ 'nonatomic'
+
+ For example:
+ @property NSString *name;
+ @property (readonly) id object;
+ @property (retain, nonatomic, getter=getTheName) id name;
+ @property int a, b, c;
+
+ PS: This function is identical to cp_parser_objc_at_propery_declaration
+ for C++. Keep them in sync. */
+static void
+c_parser_objc_at_property_declaration (c_parser *parser)
+{
+ /* The following variables hold the attributes of the properties as
+ parsed. They are 'false' or 'NULL_TREE' if the attribute was not
+ seen. When we see an attribute, we set them to 'true' (if they
+ are boolean properties) or to the identifier (if they have an
+ argument, ie, for getter and setter). Note that here we only
+ parse the list of attributes, check the syntax and accumulate the
+ attributes that we find. objc_add_property_declaration() will
+ then process the information. */
+ bool property_assign = false;
+ bool property_copy = false;
+ tree property_getter_ident = NULL_TREE;
+ bool property_nonatomic = false;
+ bool property_readonly = false;
+ bool property_readwrite = false;
+ bool property_retain = false;
+ tree property_setter_ident = NULL_TREE;
+
+ /* 'properties' is the list of properties that we read. Usually a
+ single one, but maybe more (eg, in "@property int a, b, c;" there
+ are three). */
+ tree properties;
+ location_t loc;
+
+ loc = c_parser_peek_token (parser)->location;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY));
+
+ c_parser_consume_token (parser); /* Eat '@property'. */
+
+ /* Parse the optional attribute list... */
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ /* Eat the '(' */
+ c_parser_consume_token (parser);
+
+ /* Property attribute keywords are valid now. */
+ parser->objc_property_attr_context = true;
+
+ while (true)
+ {
+ bool syntax_error = false;
+ c_token *token = c_parser_peek_token (parser);
+ enum rid keyword;
+
+ if (token->type != CPP_KEYWORD)
+ {
+ if (token->type == CPP_CLOSE_PAREN)
+ c_parser_error (parser, "expected identifier");
+ else
+ {
+ c_parser_consume_token (parser);
+ c_parser_error (parser, "unknown property attribute");
+ }
+ break;
+ }
+ keyword = token->keyword;
+ c_parser_consume_token (parser);
+ switch (keyword)
+ {
+ case RID_ASSIGN: property_assign = true; break;
+ case RID_COPY: property_copy = true; break;
+ case RID_NONATOMIC: property_nonatomic = true; break;
+ case RID_READONLY: property_readonly = true; break;
+ case RID_READWRITE: property_readwrite = true; break;
+ case RID_RETAIN: property_retain = true; break;
+
+ case RID_GETTER:
+ case RID_SETTER:
+ if (c_parser_next_token_is_not (parser, CPP_EQ))
+ {
+ if (keyword == RID_GETTER)
+ c_parser_error (parser,
+ "missing %<=%> (after %<getter%> attribute)");
+ else
+ c_parser_error (parser,
+ "missing %<=%> (after %<setter%> attribute)");
+ syntax_error = true;
+ break;
+ }
+ c_parser_consume_token (parser); /* eat the = */
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ syntax_error = true;
+ break;
+ }
+ if (keyword == RID_SETTER)
+ {
+ if (property_setter_ident != NULL_TREE)
+ c_parser_error (parser, "the %<setter%> attribute may only be specified once");
+ else
+ property_setter_ident = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_not (parser, CPP_COLON))
+ c_parser_error (parser, "setter name must terminate with %<:%>");
+ else
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ if (property_getter_ident != NULL_TREE)
+ c_parser_error (parser, "the %<getter%> attribute may only be specified once");
+ else
+ property_getter_ident = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ break;
+ default:
+ c_parser_error (parser, "unknown property attribute");
+ syntax_error = true;
+ break;
+ }
+
+ if (syntax_error)
+ break;
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ parser->objc_property_attr_context = false;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ /* ... and the property declaration(s). */
+ properties = c_parser_struct_declaration (parser);
+
+ if (properties == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ parser->error = false;
+ return;
+ }
+
+ if (properties == NULL_TREE)
+ c_parser_error (parser, "expected identifier");
+ else
+ {
+ /* Comma-separated properties are chained together in
+ reverse order; add them one by one. */
+ properties = nreverse (properties);
+
+ for (; properties; properties = TREE_CHAIN (properties))
+ objc_add_property_declaration (loc, copy_node (properties),
+ property_readonly, property_readwrite,
+ property_assign, property_retain,
+ property_copy, property_nonatomic,
+ property_getter_ident, property_setter_ident);
+ }
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ parser->error = false;
+}
+
+/* Parse an Objective-C @synthesize declaration. The syntax is:
+
+ objc-synthesize-declaration:
+ @synthesize objc-synthesize-identifier-list ;
+
+ objc-synthesize-identifier-list:
+ objc-synthesize-identifier
+ objc-synthesize-identifier-list, objc-synthesize-identifier
+
+ objc-synthesize-identifier
+ identifier
+ identifier = identifier
+
+ For example:
+ @synthesize MyProperty;
+ @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty;
+
+ PS: This function is identical to cp_parser_objc_at_synthesize_declaration
+ for C++. Keep them in sync.
+*/
+static void
+c_parser_objc_at_synthesize_declaration (c_parser *parser)
+{
+ tree list = NULL_TREE;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE));
+ loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_token (parser);
+ while (true)
+ {
+ tree property, ivar;
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ /* Once we find the semicolon, we can resume normal parsing.
+ We have to reset parser->error manually because
+ c_parser_skip_until_found() won't reset it for us if the
+ next token is precisely a semicolon. */
+ parser->error = false;
+ return;
+ }
+ property = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_EQ))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ parser->error = false;
+ return;
+ }
+ ivar = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else
+ ivar = NULL_TREE;
+ list = chainon (list, build_tree_list (ivar, property));
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ objc_add_synthesize_declaration (loc, list);
+}
+
+/* Parse an Objective-C @dynamic declaration. The syntax is:
+
+ objc-dynamic-declaration:
+ @dynamic identifier-list ;
+
+ For example:
+ @dynamic MyProperty;
+ @dynamic MyProperty, AnotherProperty;
+
+ PS: This function is identical to cp_parser_objc_at_dynamic_declaration
+ for C++. Keep them in sync.
+*/
+static void
+c_parser_objc_at_dynamic_declaration (c_parser *parser)
+{
+ tree list = NULL_TREE;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC));
+ loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_token (parser);
+ while (true)
+ {
+ tree property;
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ parser->error = false;
+ return;
+ }
+ property = c_parser_peek_token (parser)->value;
+ list = chainon (list, build_tree_list (NULL_TREE, property));
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ objc_add_dynamic_declaration (loc, list);
+}
+
\f
/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore
should be considered, statements. ALLOW_STMT is true if we're within
c_parser_omp_taskwait (parser);
return false;
+ case PRAGMA_OMP_TASKYIELD:
+ if (context != pragma_compound)
+ {
+ if (context == pragma_stmt)
+ c_parser_error (parser, "%<#pragma omp taskyield%> may only be "
+ "used in compound statements");
+ goto bad_stmt;
+ }
+ c_parser_omp_taskyield (parser);
+ return false;
+
case PRAGMA_OMP_THREADPRIVATE:
c_parser_omp_threadprivate (parser);
return false;
result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
break;
case 'f':
- if (!strcmp ("firstprivate", p))
+ if (!strcmp ("final", p))
+ result = PRAGMA_OMP_CLAUSE_FINAL;
+ else if (!strcmp ("firstprivate", p))
result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
break;
case 'l':
if (!strcmp ("lastprivate", p))
result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
break;
+ case 'm':
+ if (!strcmp ("mergeable", p))
+ result = PRAGMA_OMP_CLAUSE_MERGEABLE;
+ break;
case 'n':
if (!strcmp ("nowait", p))
result = PRAGMA_OMP_CLAUSE_NOWAIT;
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list);
}
+/* OpenMP 3.1:
+ final ( expression ) */
+
+static tree
+c_parser_omp_clause_final (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree t = c_parser_paren_condition (parser);
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final");
+
+ c = build_omp_clause (loc, OMP_CLAUSE_FINAL);
+ OMP_CLAUSE_FINAL_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+ else
+ c_parser_error (parser, "expected %<(%>");
+
+ return list;
+}
+
/* OpenMP 2.5:
if ( expression ) */
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list);
}
+/* OpenMP 3.1:
+ mergeable */
+
+static tree
+c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+
+ /* FIXME: Should we allow duplicates? */
+ check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable");
+
+ c = build_omp_clause (c_parser_peek_token (parser)->location,
+ OMP_CLAUSE_MERGEABLE);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
/* OpenMP 2.5:
nowait */
{
location_t expr_loc = c_parser_peek_token (parser)->location;
tree c, t = c_parser_expression (parser).value;
+ mark_exp_read (t);
t = c_fully_fold (t, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
reduction ( reduction-operator : variable-list )
reduction-operator:
- One of: + * - & ^ | && || */
+ One of: + * - & ^ | && ||
+
+ OpenMP 3.1:
+
+ reduction-operator:
+ One of: + * - & ^ | && || max min */
static tree
c_parser_omp_clause_reduction (c_parser *parser, tree list)
case CPP_OR_OR:
code = TRUTH_ORIF_EXPR;
break;
+ case CPP_NAME:
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "min") == 0)
+ {
+ code = MIN_EXPR;
+ break;
+ }
+ if (strcmp (p, "max") == 0)
+ {
+ code = MAX_EXPR;
+ break;
+ }
+ }
+ /* FALLTHRU */
default:
c_parser_error (parser,
"expected %<+%>, %<*%>, %<-%>, %<&%>, "
- "%<^%>, %<|%>, %<&&%>, or %<||%>");
+ "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or %<max%>");
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
return list;
}
here = c_parser_peek_token (parser)->location;
t = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (t);
t = c_fully_fold (t, false, NULL);
if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
clauses = c_parser_omp_clause_firstprivate (parser, clauses);
c_name = "firstprivate";
break;
+ case PRAGMA_OMP_CLAUSE_FINAL:
+ clauses = c_parser_omp_clause_final (parser, clauses);
+ c_name = "final";
+ break;
case PRAGMA_OMP_CLAUSE_IF:
clauses = c_parser_omp_clause_if (parser, clauses);
c_name = "if";
clauses = c_parser_omp_clause_lastprivate (parser, clauses);
c_name = "lastprivate";
break;
+ case PRAGMA_OMP_CLAUSE_MERGEABLE:
+ clauses = c_parser_omp_clause_mergeable (parser, clauses);
+ c_name = "mergeable";
+ break;
case PRAGMA_OMP_CLAUSE_NOWAIT:
clauses = c_parser_omp_clause_nowait (parser, clauses);
c_name = "nowait";
where x is an lvalue expression with scalar type.
+ OpenMP 3.1:
+ # pragma omp atomic new-line
+ update-stmt
+
+ # pragma omp atomic read new-line
+ read-stmt
+
+ # pragma omp atomic write new-line
+ write-stmt
+
+ # pragma omp atomic update new-line
+ update-stmt
+
+ # pragma omp atomic capture new-line
+ capture-stmt
+
+ # pragma omp atomic capture new-line
+ capture-block
+
+ read-stmt:
+ v = x
+ write-stmt:
+ x = expr
+ update-stmt:
+ expression-stmt | x = x binop expr
+ capture-stmt:
+ v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; }
+
+ where x and v are lvalue expressions with scalar type.
+
LOC is the location of the #pragma token. */
static void
c_parser_omp_atomic (location_t loc, c_parser *parser)
{
- tree lhs, rhs;
- tree stmt;
- enum tree_code code;
+ tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
+ tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
+ tree stmt, orig_lhs;
+ enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
struct c_expr rhs_expr;
+ bool structured_block = false;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (p, "read"))
+ code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ code = OMP_ATOMIC;
+ else if (!strcmp (p, "capture"))
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ else
+ p = NULL;
+ if (p)
+ c_parser_consume_token (parser);
+ }
c_parser_skip_to_pragma_eol (parser);
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ case NOP_EXPR: /* atomic write */
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ if (code == NOP_EXPR)
+ lhs = c_parser_expression (parser).value;
+ else
+ lhs = c_parser_unary_expression (parser).value;
+ lhs = c_fully_fold (lhs, false, NULL);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (code == NOP_EXPR)
+ {
+ /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
+ opcode. */
+ code = OMP_ATOMIC;
+ rhs = lhs;
+ lhs = v;
+ v = NULL_TREE;
+ }
+ goto done;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_consume_token (parser);
+ structured_block = true;
+ }
+ else
+ {
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* For structured_block case we don't know yet whether
+ old or new x should be captured. */
+restart:
lhs = c_parser_unary_expression (parser).value;
lhs = c_fully_fold (lhs, false, NULL);
+ orig_lhs = lhs;
switch (TREE_CODE (lhs))
{
case ERROR_MARK:
saw_error:
c_parser_skip_to_end_of_block_or_statement (parser);
+ if (structured_block)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ else if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ }
+ }
return;
- case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREINCREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
- code = PLUS_EXPR;
+ opcode = PLUS_EXPR;
rhs = integer_one_node;
break;
- case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREDECREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
- code = MINUS_EXPR;
+ opcode = MINUS_EXPR;
rhs = integer_one_node;
break;
/* This is pre or post increment. */
rhs = TREE_OPERAND (lhs, 1);
lhs = TREE_OPERAND (lhs, 0);
- code = NOP_EXPR;
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
break;
}
if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
/* This is pre or post decrement. */
rhs = TREE_OPERAND (lhs, 1);
lhs = TREE_OPERAND (lhs, 0);
- code = NOP_EXPR;
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
break;
}
}
switch (c_parser_peek_token (parser)->type)
{
case CPP_MULT_EQ:
- code = MULT_EXPR;
+ opcode = MULT_EXPR;
break;
case CPP_DIV_EQ:
- code = TRUNC_DIV_EXPR;
+ opcode = TRUNC_DIV_EXPR;
break;
case CPP_PLUS_EQ:
- code = PLUS_EXPR;
+ opcode = PLUS_EXPR;
break;
case CPP_MINUS_EQ:
- code = MINUS_EXPR;
+ opcode = MINUS_EXPR;
break;
case CPP_LSHIFT_EQ:
- code = LSHIFT_EXPR;
+ opcode = LSHIFT_EXPR;
break;
case CPP_RSHIFT_EQ:
- code = RSHIFT_EXPR;
+ opcode = RSHIFT_EXPR;
break;
case CPP_AND_EQ:
- code = BIT_AND_EXPR;
+ opcode = BIT_AND_EXPR;
break;
case CPP_OR_EQ:
- code = BIT_IOR_EXPR;
+ opcode = BIT_IOR_EXPR;
break;
case CPP_XOR_EQ:
- code = BIT_XOR_EXPR;
+ opcode = BIT_XOR_EXPR;
break;
+ case CPP_EQ:
+ if (structured_block || code == OMP_ATOMIC)
+ {
+ location_t aloc = c_parser_peek_token (parser)->location;
+ location_t rhs_loc;
+ enum c_parser_prec oprec = PREC_NONE;
+
+ c_parser_consume_token (parser);
+ rhs1 = c_parser_unary_expression (parser).value;
+ rhs1 = c_fully_fold (rhs1, false, NULL);
+ if (rhs1 == error_mark_node)
+ goto saw_error;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_SEMICOLON:
+ if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ v = lhs;
+ lhs = NULL_TREE;
+ lhs1 = rhs1;
+ rhs1 = NULL_TREE;
+ c_parser_consume_token (parser);
+ goto restart;
+ }
+ c_parser_error (parser,
+ "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ case CPP_MULT:
+ opcode = MULT_EXPR;
+ oprec = PREC_MULT;
+ break;
+ case CPP_DIV:
+ opcode = TRUNC_DIV_EXPR;
+ oprec = PREC_MULT;
+ break;
+ case CPP_PLUS:
+ opcode = PLUS_EXPR;
+ oprec = PREC_ADD;
+ break;
+ case CPP_MINUS:
+ opcode = MINUS_EXPR;
+ oprec = PREC_ADD;
+ break;
+ case CPP_LSHIFT:
+ opcode = LSHIFT_EXPR;
+ oprec = PREC_SHIFT;
+ break;
+ case CPP_RSHIFT:
+ opcode = RSHIFT_EXPR;
+ oprec = PREC_SHIFT;
+ break;
+ case CPP_AND:
+ opcode = BIT_AND_EXPR;
+ oprec = PREC_BITAND;
+ break;
+ case CPP_OR:
+ opcode = BIT_IOR_EXPR;
+ oprec = PREC_BITOR;
+ break;
+ case CPP_XOR:
+ opcode = BIT_XOR_EXPR;
+ oprec = PREC_BITXOR;
+ break;
+ default:
+ c_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ loc = aloc;
+ c_parser_consume_token (parser);
+ rhs_loc = c_parser_peek_token (parser)->location;
+ if (commutative_tree_code (opcode))
+ oprec = (enum c_parser_prec) (oprec - 1);
+ rhs_expr = c_parser_binary_expression (parser, NULL, oprec);
+ rhs_expr = default_function_array_read_conversion (rhs_loc,
+ rhs_expr);
+ rhs = rhs_expr.value;
+ rhs = c_fully_fold (rhs, false, NULL);
+ goto stmt_done;
+ }
+ /* FALLTHROUGH */
default:
c_parser_error (parser,
"invalid operator for %<#pragma omp atomic%>");
goto saw_error;
}
+ /* Arrange to pass the location of the assignment operator to
+ c_finish_omp_atomic. */
+ loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
{
location_t rhs_loc = c_parser_peek_token (parser)->location;
rhs = c_fully_fold (rhs, false, NULL);
break;
}
- stmt = c_finish_omp_atomic (loc, code, lhs, rhs);
+stmt_done:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ lhs1 = c_parser_unary_expression (parser).value;
+ lhs1 = c_fully_fold (lhs1, false, NULL);
+ if (lhs1 == error_mark_node)
+ goto saw_error;
+ }
+ if (structured_block)
+ {
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ }
+done:
+ stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1);
if (stmt != error_mark_node)
add_stmt (stmt);
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+ if (!structured_block)
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
goto pop_scopes;
/* Parse the initialization declaration or expression. */
- if (c_parser_next_token_starts_declaration (parser))
+ if (c_parser_next_tokens_start_declaration (parser))
{
if (i > 0)
VEC_safe_push (tree, gc, for_block, c_begin_compound_stmt (true));
- c_parser_declaration_or_fndef (parser, true, true, true, true, true);
- decl = check_for_loop_decls (for_loc);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+ decl = check_for_loop_decls (for_loc, flag_isoc99);
if (decl == NULL)
goto error_init;
if (DECL_INITIAL (decl) == error_mark_node)
if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
{
location_t cond_loc = c_parser_peek_token (parser)->location;
- struct c_expr cond_expr = c_parser_binary_expression (parser, NULL);
+ struct c_expr cond_expr = c_parser_binary_expression (parser, NULL,
+ PREC_NONE);
cond = cond_expr.value;
cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
| (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
| (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_SHARED))
+ | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (1u << PRAGMA_OMP_CLAUSE_FINAL) \
+ | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE))
static tree
c_parser_omp_task (location_t loc, c_parser *parser)
c_finish_omp_taskwait (loc);
}
+/* OpenMP 3.1:
+ # pragma omp taskyield new-line
+*/
+
+static void
+c_parser_omp_taskyield (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_taskyield (loc);
+}
+
/* Main entry point to parsing most OpenMP pragmas. */
static void
c_parser_skip_to_pragma_eol (parser);
}
+/* Parse a transaction attribute (GCC Extension).
+
+ transaction-attribute:
+ attributes
+ [ [ any-word ] ]
+
+ The transactional memory language description is written for C++,
+ and uses the C++0x attribute syntax. For compatibility, allow the
+ bracket style for transactions in C as well. */
+
+static tree
+c_parser_transaction_attributes (c_parser *parser)
+{
+ tree attr_name, attr = NULL;
+
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ return c_parser_attributes (parser);
+
+ if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ return NULL_TREE;
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>"))
+ goto error1;
+
+ attr_name = c_parser_attribute_any_word (parser);
+ if (attr_name)
+ {
+ c_parser_consume_token (parser);
+ attr = build_tree_list (attr_name, NULL_TREE);
+ }
+ else
+ c_parser_error (parser, "expected identifier");
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+ error1:
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+ return attr;
+}
+
+/* Parse a __transaction_atomic or __transaction_relaxed statement
+ (GCC Extension).
+
+ transaction-statement:
+ __transaction_atomic transaction-attribute[opt] compound-statement
+ __transaction_relaxed compound-statement
+
+ Note that the only valid attribute is: "outer".
+*/
+
+static tree
+c_parser_transaction (c_parser *parser, enum rid keyword)
+{
+ unsigned int old_in = parser->in_transaction;
+ unsigned int this_in = 1, new_in;
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree stmt, attrs;
+
+ gcc_assert ((keyword == RID_TRANSACTION_ATOMIC
+ || keyword == RID_TRANSACTION_RELAXED)
+ && c_parser_next_token_is_keyword (parser, keyword));
+ c_parser_consume_token (parser);
+
+ if (keyword == RID_TRANSACTION_RELAXED)
+ this_in |= TM_STMT_ATTR_RELAXED;
+ else
+ {
+ attrs = c_parser_transaction_attributes (parser);
+ if (attrs)
+ this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
+ }
+
+ /* Keep track if we're in the lexical scope of an outer transaction. */
+ new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
+
+ parser->in_transaction = new_in;
+ stmt = c_parser_compound_statement (parser);
+ parser->in_transaction = old_in;
+
+ if (flag_tm)
+ stmt = c_finish_transaction (loc, stmt, this_in);
+ else
+ error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ?
+ "%<__transaction_atomic%> without transactional memory support enabled"
+ : "%<__transaction_relaxed %> "
+ "without transactional memory support enabled"));
+
+ return stmt;
+}
+
+/* Parse a __transaction_atomic or __transaction_relaxed expression
+ (GCC Extension).
+
+ transaction-expression:
+ __transaction_atomic ( expression )
+ __transaction_relaxed ( expression )
+*/
+
+static struct c_expr
+c_parser_transaction_expression (c_parser *parser, enum rid keyword)
+{
+ struct c_expr ret;
+ unsigned int old_in = parser->in_transaction;
+ unsigned int this_in = 1;
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree attrs;
+
+ gcc_assert ((keyword == RID_TRANSACTION_ATOMIC
+ || keyword == RID_TRANSACTION_RELAXED)
+ && c_parser_next_token_is_keyword (parser, keyword));
+ c_parser_consume_token (parser);
+
+ if (keyword == RID_TRANSACTION_RELAXED)
+ this_in |= TM_STMT_ATTR_RELAXED;
+ else
+ {
+ attrs = c_parser_transaction_attributes (parser);
+ if (attrs)
+ this_in |= parse_tm_stmt_attr (attrs, 0);
+ }
+
+ parser->in_transaction = this_in;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ tree expr = c_parser_expression (parser).value;
+ ret.original_type = TREE_TYPE (expr);
+ ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr);
+ if (this_in & TM_STMT_ATTR_RELAXED)
+ TRANSACTION_EXPR_RELAXED (ret.value) = 1;
+ SET_EXPR_LOCATION (ret.value, loc);
+ ret.original_code = TRANSACTION_EXPR;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error;
+ }
+ }
+ else
+ {
+ error:
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ }
+ parser->in_transaction = old_in;
+
+ if (!flag_tm)
+ error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ?
+ "%<__transaction_atomic%> without transactional memory support enabled"
+ : "%<__transaction_relaxed %> "
+ "without transactional memory support enabled"));
+
+ return ret;
+}
+
+/* Parse a __transaction_cancel statement (GCC Extension).
+
+ transaction-cancel-statement:
+ __transaction_cancel transaction-attribute[opt] ;
+
+ Note that the only valid attribute is "outer".
+*/
+
+static tree
+c_parser_transaction_cancel(c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree attrs;
+ bool is_outer = false;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL));
+ c_parser_consume_token (parser);
+
+ attrs = c_parser_transaction_attributes (parser);
+ if (attrs)
+ is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0);
+
+ if (!flag_tm)
+ {
+ error_at (loc, "%<__transaction_cancel%> without "
+ "transactional memory support enabled");
+ goto ret_error;
+ }
+ else if (parser->in_transaction & TM_STMT_ATTR_RELAXED)
+ {
+ error_at (loc, "%<__transaction_cancel%> within a "
+ "%<__transaction_relaxed%>");
+ goto ret_error;
+ }
+ else if (is_outer)
+ {
+ if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0
+ && !is_tm_may_cancel_outer (current_function_decl))
+ {
+ error_at (loc, "outer %<__transaction_cancel%> not "
+ "within outer %<__transaction_atomic%>");
+ error_at (loc, " or a %<transaction_may_cancel_outer%> function");
+ goto ret_error;
+ }
+ }
+ else if (parser->in_transaction == 0)
+ {
+ error_at (loc, "%<__transaction_cancel%> not within "
+ "%<__transaction_atomic%>");
+ goto ret_error;
+ }
+
+ return add_stmt (build_tm_abort_call (loc, is_outer));
+
+ ret_error:
+ return build1 (NOP_EXPR, void_type_node, error_mark_node);
+}
\f
/* Parse a single source file. */