/* 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
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Parser actions based on the old Bison parser; structure somewhat
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
+#include "tm.h" /* For rtl.h: needs enum reg_class. */
#include "tree.h"
-#include "rtl.h"
#include "langhooks.h"
#include "input.h"
#include "cpplib.h"
#include "timevar.h"
-#include "c-pragma.h"
+#include "c-family/c-pragma.h"
#include "c-tree.h"
#include "flags.h"
#include "output.h"
-#include "toplev.h"
#include "ggc.h"
-#include "c-common.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
#include "vec.h"
#include "target.h"
#include "cgraph.h"
tree id;
int mask = 0;
+ /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in
+ the c_token structure. */
+ gcc_assert (RID_MAX <= 255);
+
mask |= D_CXXONLY;
if (!flag_isoc99)
mask |= D_C99;
if (!c_dialect_objc ())
mask |= D_OBJC | D_CXX_OBJC;
- ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX);
+ ridpointers = ggc_alloc_cleared_vec_tree ((int) RID_MAX);
for (i = 0; i < num_c_common_reswords; i++)
{
/* If a keyword is disabled, do not enter it into the table
C_ID_TYPENAME,
/* An identifier declared as an Objective-C class name. */
C_ID_CLASSNAME,
+ /* An address space identifier. */
+ C_ID_ADDRSPACE,
/* Not an identifier. */
C_ID_NONE
} c_id_kind;
/* If this token is a CPP_PRAGMA, this indicates the pragma that
was seen. Otherwise it is PRAGMA_NONE. */
ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
- /* The value associated with this token, if any. */
- tree value;
/* The location at which this token was found. */
location_t location;
+ /* The value associated with this token, if any. */
+ tree value;
} c_token;
/* A parser structure recording information about the state and
BOOL_BITFIELD in_if_block : 1;
/* True if we want to lex an untranslated string. */
BOOL_BITFIELD lex_untranslated_string : 1;
+
/* Objective-C specific parser/lexer information. */
+
+ /* 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;
+ /* 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;
static GTY (()) c_parser *the_parser;
-
/* Read in and lex a single token, storing it in *TOKEN. */
static void
"identifier %qE conflicts with C++ keyword",
token->value);
}
- else if (c_dialect_objc ())
+ else if (rid_code >= RID_FIRST_ADDR_SPACE
+ && rid_code <= RID_LAST_ADDR_SPACE)
+ {
+ token->id_kind = C_ID_ADDRSPACE;
+ token->keyword = rid_code;
+ break;
+ }
+ else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code))
{
- if (!objc_is_reserved_word (token->value)
- && (!OBJC_IS_PQ_KEYWORD (rid_code)
- || parser->objc_pq_context))
+ /* We found an Objective-C "pq" keyword (in, out,
+ inout, bycopy, byref, oneway). They need special
+ care because the interpretation depends on the
+ 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)
{
- /* Return the canonical spelling for this keyword. */
- token->value = ridpointers[(int) rid_code];
+ /* 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. */
+ }
+ 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 ()
+ && (OBJC_IS_AT_KEYWORD (rid_code)
+ || OBJC_IS_CXX_KEYWORD (rid_code)))
+ {
+ /* We found one of the Objective-C "@" keywords (defs,
+ selector, synchronized, etc) or one of the
+ Objective-C "cxx" keywords (class, private,
+ 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). */
+ ;
}
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
{
case C_ID_ID:
return false;
+ case C_ID_ADDRSPACE:
+ return true;
case C_ID_TYPENAME:
return true;
case C_ID_CLASSNAME:
{
case RID_UNSIGNED:
case RID_LONG:
+ case RID_INT128:
case RID_SHORT:
case RID_SIGNED:
case RID_COMPLEX:
}
}
+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 C_ID_ID:
return false;
+ case C_ID_ADDRSPACE:
+ return true;
case C_ID_TYPENAME:
return true;
case C_ID_CLASSNAME:
case RID_THREAD:
case RID_UNSIGNED:
case RID_LONG:
+ case RID_INT128:
case RID_SHORT:
case RID_SIGNED:
case RID_COMPLEX:
}
}
+
+/* Return true if TOKEN can start declaration specifiers or a static
+ assertion, false otherwise. */
+static bool
+c_token_starts_declaration (c_token *token)
+{
+ if (c_token_starts_declspecs (token)
+ || token->keyword == RID_STATIC_ASSERT)
+ return true;
+ else
+ return false;
+}
+
/* Return true if the next token from PARSER can start declaration
specifiers, false otherwise. */
static inline bool
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 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)
+/* Return true if the next tokens from PARSER can start declaration
+ specifiers or a static assertion, false otherwise. */
+static inline bool
+c_parser_next_tokens_start_declaration (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];
+ c_token *token = c_parser_peek_token (parser);
+
+ /* 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;
+
+ /* 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));
- cpp_opts->pedantic = pedantic = 0;
+ | (warn_cxx_compat << 5)
+ | (warn_overlength_strings << 6));
+ cpp_opts->cpp_pedantic = pedantic = 0;
warn_pointer_arith = 0;
- cpp_opts->warn_traditional = warn_traditional = 0;
+ cpp_opts->cpp_warn_traditional = warn_traditional = 0;
flag_iso = 0;
- cpp_opts->warn_long_long = warn_long_long = 0;
+ cpp_opts->cpp_warn_long_long = warn_long_long = 0;
warn_cxx_compat = 0;
+ warn_overlength_strings = 0;
return ret;
}
static inline void
restore_extension_diagnostics (int flags)
{
- cpp_opts->pedantic = pedantic = flags & 1;
+ cpp_opts->cpp_pedantic = pedantic = flags & 1;
warn_pointer_arith = (flags >> 1) & 1;
- cpp_opts->warn_traditional = warn_traditional = (flags >> 2) & 1;
+ cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1;
flag_iso = (flags >> 3) & 1;
- cpp_opts->warn_long_long = warn_long_long = (flags >> 4) & 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. */
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);
+static void c_parser_declaration_or_fndef (c_parser *, 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_type_name *c_parser_type_name (c_parser *);
static struct c_expr c_parser_initializer (c_parser *);
static struct c_expr c_parser_braced_init (c_parser *, tree, bool);
-static void c_parser_initelt (c_parser *);
-static void c_parser_initval (c_parser *, struct c_expr *);
+static void c_parser_initelt (c_parser *, struct obstack *);
+static void c_parser_initval (c_parser *, struct c_expr *,
+ struct obstack *);
static tree c_parser_compound_statement (c_parser *);
static void c_parser_compound_statement_nostart (c_parser *);
static void c_parser_label (c_parser *);
static void c_parser_for_statement (c_parser *);
static tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *, bool);
+static tree c_parser_asm_goto_operands (c_parser *);
static tree c_parser_asm_clobbers (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_type_name *,
location_t);
static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
+ location_t loc,
struct c_expr);
static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *);
/* These Objective-C parser functions are only ever called when
compiling Objective-C. */
-static void c_parser_objc_class_definition (c_parser *);
+static void c_parser_objc_class_definition (c_parser *, tree);
static void c_parser_objc_class_instance_variables (c_parser *);
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 *);
-static enum tree_code c_parser_objc_method_type (c_parser *);
+static void c_parser_objc_protocol_definition (c_parser *, tree);
+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 *);
+static tree c_parser_objc_method_decl (c_parser *, bool, 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 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).
{
if (c_parser_next_token_is (parser, CPP_EOF))
{
- pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+ pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"ISO C forbids an empty translation unit");
}
else
case RID_AT_INTERFACE:
case RID_AT_IMPLEMENTATION:
gcc_assert (c_dialect_objc ());
- c_parser_objc_class_definition (parser);
+ 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;
break;
case RID_AT_PROTOCOL:
gcc_assert (c_dialect_objc ());
- c_parser_objc_protocol_definition (parser);
+ 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 ());
}
break;
case CPP_SEMICOLON:
- pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+ pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"ISO C does not allow extra %<;%> outside of a function");
c_parser_consume_token (parser);
break;
as a declaration or function definition. */
default:
decl_or_fndef:
- /* A declaration or a function definition. We can only tell
- which after parsing the declaration specifiers, if any, and
- the first declarator. */
- c_parser_declaration_or_fndef (parser, true, true, false, true);
+ /* A declaration or a function definition (or, in Objective-C,
+ 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, NULL);
break;
}
}
-
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1). If FNDEF_OK is true, a function definition is
accepted; otherwise (old-style parameter declarations) only other
- declarations are accepted. If NESTED is true, we are inside a
- function or parsing old-style parameter declarations; any functions
- encountered are nested functions and declaration specifiers are
- required; otherwise we are at top level and functions are normal
- functions and declaration specifiers may be optional. If EMPTY_OK
- is true, empty declarations are OK (subject to all other
- constraints); otherwise (old-style parameter declarations) they are
- diagnosed. If START_ATTR_OK is true, the declaration specifiers
- may start with attributes; otherwise they may not.
+ declarations are accepted. If STATIC_ASSERT_OK is true, a static
+ assertion is accepted; otherwise (old-style parameter declarations)
+ it is not. If NESTED is true, we are inside a function or parsing
+ old-style parameter declarations; any functions encountered are
+ nested functions and declaration specifiers are required; otherwise
+ we are at top level and functions are normal functions and
+ declaration specifiers may be optional. If EMPTY_OK is true, empty
+ declarations are OK (subject to all other constraints); otherwise
+ (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] ;
+ static_assert-declaration
function-definition:
declaration-specifiers[opt] declarator declaration-list[opt]
declaration-specifiers declarator declaration-list[opt]
compound-statement
+ Objective-C:
+ attributes objc-class-definition
+ attributes objc-category-definition
+ attributes objc-protocol-definition
+
The simple-asm-expr and attributes are GNU extensions.
This function does not handle __extension__; that is handled in its
C we also allow but diagnose declarations without declaration
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:
threadprivate-directive */
static void
-c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok,
- bool nested, bool start_attr_ok)
+c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
+ bool static_assert_ok, bool empty_ok,
+ bool nested, bool start_attr_ok,
+ tree *objc_foreach_object_declaration)
{
struct c_declspecs *specs;
tree prefix_attrs;
bool diagnosed_no_specs = false;
location_t here = c_parser_peek_token (parser)->location;
+ if (static_assert_ok
+ && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
+ {
+ c_parser_static_assert_declaration (parser);
+ 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. */
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS:
+ case CPP_MINUS:
+ if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
+ return;
+ if (specs->attrs)
+ {
+ warning_at (c_parser_peek_token (parser)->location,
+ OPT_Wattributes,
+ "prefix attributes are ignored for methods");
+ specs->attrs = NULL_TREE;
+ }
+ if (fndef_ok)
+ c_parser_objc_method_definition (parser);
+ else
+ c_parser_objc_methodproto (parser);
+ return;
+ break;
+ default:
+ break;
+ }
+ /* This is where we parse 'attributes @interface ...',
+ 'attributes @implementation ...', 'attributes @protocol ...'
+ (where attributes could be, for example, __attribute__
+ ((deprecated)).
+ */
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_AT_INTERFACE:
+ {
+ if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
+ return;
+ c_parser_objc_class_definition (parser, specs->attrs);
+ return;
+ }
+ break;
+ case RID_AT_IMPLEMENTATION:
+ {
+ if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
+ return;
+ if (specs->attrs)
+ {
+ warning_at (c_parser_peek_token (parser)->location,
+ OPT_Wattributes,
+ "prefix attributes are ignored for implementations");
+ specs->attrs = NULL_TREE;
+ }
+ c_parser_objc_class_definition (parser, NULL_TREE);
+ return;
+ }
+ break;
+ case RID_AT_PROTOCOL:
+ {
+ if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
+ return;
+ c_parser_objc_protocol_definition (parser, specs->attrs);
+ 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;
+ }
+ }
+
pending_xref_error ();
prefix_attrs = specs->attrs;
all_prefix_attrs = prefix_attrs;
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;
{
tree d;
struct c_expr init;
+ location_t init_loc;
c_parser_consume_token (parser);
/* The declaration of the variable is in effect while
its initializer is parsed. */
if (!d)
d = error_mark_node;
start_init (d, asm_name, global_bindings_p ());
+ init_loc = c_parser_peek_token (parser)->location;
init = c_parser_initializer (parser);
finish_init ();
if (d != error_mark_node)
{
maybe_warn_string_init (TREE_TYPE (d), init);
- finish_decl (d, init.value, init.original_type, asm_name);
+ finish_decl (d, init_loc, init.value,
+ init.original_type, asm_name);
}
}
else
chainon (postfix_attrs,
all_prefix_attrs));
if (d)
- finish_decl (d, NULL_TREE, NULL_TREE, asm_name);
+ finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
+ 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 %<;%>");
function definitions either. */
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, true, false);
+ c_parser_declaration_or_fndef (parser, false, false, false,
+ true, false, NULL);
store_parm_decls ();
DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
= c_parser_peek_token (parser)->location;
if (nested)
{
tree decl = current_function_decl;
+ /* Mark nested functions as needing static-chain initially.
+ lower_nested_functions will recompute it but the
+ DECL_STATIC_CHAIN flag is also used before that happens,
+ by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */
+ DECL_STATIC_CHAIN (decl) = 1;
add_stmt (fnbody);
finish_function ();
c_pop_function_context ();
- add_stmt (build_stmt (DECL_EXPR, decl));
+ add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
}
else
{
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
+/* Parse a static assertion (C1X N1425 6.7.10).
+
+ static_assert-declaration:
+ static_assert-declaration-no-semi ;
+*/
+
+static void
+c_parser_static_assert_declaration (c_parser *parser)
+{
+ c_parser_static_assert_declaration_no_semi (parser);
+ if (parser->error
+ || !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ c_parser_skip_to_end_of_block_or_statement (parser);
+}
+
+/* Parse a static assertion (C1X N1425 6.7.10), without the trailing
+ semicolon.
+
+ static_assert-declaration-no-semi:
+ _Static_assert ( constant-expression , string-literal )
+*/
+
+static void
+c_parser_static_assert_declaration_no_semi (c_parser *parser)
+{
+ location_t assert_loc, value_loc;
+ tree value;
+ tree string;
+
+ 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_isoc99)
+ pedwarn (assert_loc, OPT_pedantic,
+ "ISO C99 does not support %<_Static_assert%>");
+ else
+ pedwarn (assert_loc, OPT_pedantic,
+ "ISO C90 does not support %<_Static_assert%>");
+ }
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return;
+ value_loc = c_parser_peek_token (parser)->location;
+ value = c_parser_expr_no_commas (parser, NULL).value;
+ parser->lex_untranslated_string = true;
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ parser->lex_untranslated_string = false;
+ return;
+ }
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_STRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ case CPP_WSTRING:
+ case CPP_UTF8STRING:
+ string = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ parser->lex_untranslated_string = false;
+ break;
+ default:
+ c_parser_error (parser, "expected string literal");
+ parser->lex_untranslated_string = false;
+ return;
+ }
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (value)))
+ {
+ error_at (value_loc, "expression in static assertion is not an integer");
+ return;
+ }
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ value = c_fully_fold (value, false, NULL);
+ if (TREE_CODE (value) == INTEGER_CST)
+ pedwarn (value_loc, OPT_pedantic, "expression in static assertion "
+ "is not an integer constant expression");
+ }
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ error_at (value_loc, "expression in static assertion is not constant");
+ return;
+ }
+ constant_expression_warning (value);
+ if (integer_zerop (value))
+ error_at (assert_loc, "static assertion failed: %E", string);
+}
+
/* Parse some declaration specifiers (possibly none) (C90 6.5, C99
6.7), adding them to SPECS (which may already include some).
Storage class specifiers are accepted iff SCSPEC_OK; type
const
restrict
volatile
+ address-space-qualifier
(restrict is new in C99.)
declaration-specifiers:
attributes declaration-specifiers[opt]
+ type-qualifier:
+ address-space
+
+ address-space:
+ identifier recognized by the target
+
storage-class-specifier:
__thread
type-specifier:
typeof-specifier
+ __int128
_Decimal32
_Decimal64
_Decimal128
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;
+ 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;
c_id_kind kind = c_parser_peek_token (parser)->id_kind;
- /* 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))
+
+ if (kind == C_ID_ADDRSPACE)
+ {
+ addr_space_t as
+ = c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE;
+ declspecs_add_addrspace (specs, as);
+ c_parser_consume_token (parser);
+ attrs_ok = true;
+ continue;
+ }
+
+ 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;
}
- declspecs_add_type (specs, t);
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
+ declspecs_add_type (loc, specs, t);
continue;
}
if (c_parser_next_token_is (parser, CPP_LESS))
t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
t.expr = NULL_TREE;
t.expr_const_operands = true;
- declspecs_add_type (specs, t);
+ declspecs_add_type (loc, specs, t);
continue;
}
gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD));
break;
case RID_UNSIGNED:
case RID_LONG:
+ case RID_INT128:
case RID_SHORT:
case RID_SIGNED:
case RID_COMPLEX:
t.spec = c_parser_peek_token (parser)->value;
t.expr = NULL_TREE;
t.expr_const_operands = true;
- declspecs_add_type (specs, t);
+ declspecs_add_type (loc, specs, t);
c_parser_consume_token (parser);
break;
case RID_ENUM:
attrs_ok = true;
seen_type = true;
t = c_parser_enum_specifier (parser);
- declspecs_add_type (specs, t);
+ declspecs_add_type (loc, specs, t);
break;
case RID_STRUCT:
case RID_UNION:
seen_type = true;
t = c_parser_struct_or_union_specifier (parser);
invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
- declspecs_add_type (specs, t);
+ declspecs_add_type (loc, specs, t);
break;
case RID_TYPEOF:
/* ??? The old parser rejected typeof after other type
attrs_ok = true;
seen_type = true;
t = c_parser_typeof_specifier (parser);
- declspecs_add_type (specs, t);
+ declspecs_add_type (loc, specs, t);
break;
case RID_CONST:
case RID_VOLATILE:
enum_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
attrs = c_parser_attributes (parser);
+ enum_loc = c_parser_peek_token (parser)->location;
/* Set the location in case we create a decl now. */
c_parser_set_source_position_from_token (c_parser_peek_token (parser));
if (c_parser_next_token_is (parser, CPP_NAME))
{
/* Parse an enum definition. */
struct c_enum_contents the_enum;
- tree type = start_enum (&the_enum, ident, enum_loc);
+ tree type = start_enum (enum_loc, &the_enum, ident);
tree postfix_attrs;
/* We chain the enumerators in reverse order, then put them in
forward order at the end. */
bool seen_comma;
c_token *token;
location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */
- location_t value_loc;
+ location_t decl_loc, value_loc;
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
c_parser_error (parser, "expected identifier");
enum_id = token->value;
/* Set the location in case we create a decl now. */
c_parser_set_source_position_from_token (token);
- value_loc = token->location;
+ decl_loc = value_loc = token->location;
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_EQ))
{
}
else
enum_value = NULL_TREE;
- enum_decl = build_enumerator (&the_enum, enum_id, enum_value,
- value_loc);
+ enum_decl = build_enumerator (decl_loc, value_loc,
+ &the_enum, enum_id, enum_value);
TREE_CHAIN (enum_decl) = values;
values = enum_decl;
seen_comma = false;
ret.expr_const_operands = true;
return ret;
}
- ret = parser_xref_tag (ENUMERAL_TYPE, ident, ident_loc);
+ ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident);
/* In ISO C, enumerated types can be referred to only if already
defined. */
if (pedantic && !COMPLETE_TYPE_P (ret.spec))
{
gcc_assert (ident);
- pedwarn (ident_loc, OPT_pedantic,
+ pedwarn (enum_loc, OPT_pedantic,
"ISO C forbids forward references to %<enum%> types");
}
return ret;
struct_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
attrs = c_parser_attributes (parser);
+
/* Set the location in case we create a decl now. */
c_parser_set_source_position_from_token (c_parser_peek_token (parser));
+
if (c_parser_next_token_is (parser, CPP_NAME))
{
ident = c_parser_peek_token (parser)->value;
{
/* Parse a struct or union definition. Start the scope of the
tag before parsing components. */
- bool in_struct;
- VEC(tree,heap) *struct_types;
- tree type = start_struct (code, ident, &in_struct, &struct_types,
- struct_loc);
+ struct c_struct_parse_info *struct_info;
+ tree type = start_struct (struct_loc, code, ident, &struct_info);
tree postfix_attrs;
/* We chain the components in reverse order, then put them in
forward order at the end. Each struct-declaration may
/* Parse any stray semicolon. */
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
- pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+ pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"extra semicolon in struct or union specified");
c_parser_consume_token (parser);
continue;
else
{
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- pedwarn (c_parser_peek_token (parser)->location, 0,
+ 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.spec = finish_struct (type, nreverse (contents),
- chainon (attrs, postfix_attrs),
- in_struct, struct_types);
+ ret.spec = finish_struct (struct_loc, type, nreverse (contents),
+ chainon (attrs, postfix_attrs), struct_info);
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
ret.expr_const_operands = true;
return ret;
}
- ret = parser_xref_tag (code, ident, ident_loc);
+ ret = parser_xref_tag (ident_loc, code, ident);
return ret;
}
struct-declaration:
specifier-qualifier-list struct-declarator-list
+ static_assert-declaration-no-semi
specifier-qualifier-list:
type-specifier specifier-qualifier-list[opt]
restore_extension_diagnostics (ext);
return decl;
}
+ if (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
+ {
+ c_parser_static_assert_declaration_no_semi (parser);
+ return NULL_TREE;
+ }
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,
+ pedwarn (decl_loc, OPT_pedantic,
"ISO C forbids member declarations with no members");
shadow_tag_warned (specs, pedantic);
ret = NULL_TREE;
}
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)
{
declarator, specs, width, &all_prefix_attrs);
decl_attributes (&d, chainon (postfix_attrs,
all_prefix_attrs), 0);
- TREE_CHAIN (d) = decls;
+ DECL_CHAIN (d) = decls;
decls = d;
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
all_prefix_attrs = chainon (c_parser_attributes (parser),
ret.expr_const_operands = true;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
c_parser_consume_token (parser);
- skip_evaluation++;
+ c_inhibit_evaluation_warnings++;
in_typeof++;
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
- skip_evaluation--;
+ c_inhibit_evaluation_warnings--;
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);
- skip_evaluation--;
+ c_inhibit_evaluation_warnings--;
in_typeof--;
if (type != NULL)
{
bool was_vm;
location_t here = c_parser_peek_token (parser)->location;
struct c_expr expr = c_parser_expression (parser);
- skip_evaluation--;
+ c_inhibit_evaluation_warnings--;
in_typeof--;
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
error_at (here, "%<typeof%> applied to a bit-field");
+ mark_exp_read (expr.value);
ret.spec = TREE_TYPE (expr.value);
was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
/* This is returned with the type so that when the type is
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;
if (kind != C_DTR_ABSTRACT
&& c_parser_next_token_is (parser, CPP_NAME)
&& ((type_seen_p
- && c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME)
+ && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
+ || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
|| c_parser_peek_token (parser)->id_kind == C_ID_ID))
{
struct c_declarator *inner
/* Parse a sequence of array declarators and parameter lists. */
if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
{
+ location_t brace_loc = c_parser_peek_token (parser)->location;
struct c_declarator *declarator;
struct c_declspecs *quals_attrs = build_null_declspecs ();
bool static_seen;
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.
"expected %<]%>");
return NULL;
}
- declarator = build_array_declarator (dimen, quals_attrs, static_seen,
- star_seen);
+ if (dimen)
+ mark_exp_read (dimen);
+ declarator = build_array_declarator (brace_loc, dimen, quals_attrs,
+ static_seen, star_seen);
if (declarator == NULL)
return NULL;
inner = set_array_declarator_inner (declarator, inner);
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)
}
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
- struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
- ret->parms = 0;
- ret->tags = 0;
+ struct c_arg_info *ret = build_arg_info ();
ret->types = list;
- ret->others = 0;
- ret->pending_sizes = 0;
- ret->had_vla_unspec = 0;
c_parser_consume_token (parser);
pop_scope ();
return ret;
static struct c_arg_info *
c_parser_parms_list_declarator (c_parser *parser, tree attrs)
{
- bool good_parm = false;
+ 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
declarations. */
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
- struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
- ret->parms = 0;
- ret->tags = 0;
- ret->types = 0;
- ret->others = 0;
- ret->pending_sizes = 0;
- ret->had_vla_unspec = 0;
+ struct c_arg_info *ret = build_arg_info ();
c_parser_consume_token (parser);
return ret;
}
if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
- struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
- ret->parms = 0;
- ret->tags = 0;
- ret->others = 0;
- ret->pending_sizes = 0;
- ret->had_vla_unspec = 0;
+ 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,
/* Parse a parameter. */
struct c_parm *parm = c_parser_parameter_declaration (parser, attrs);
attrs = NULL_TREE;
- if (parm != NULL)
- {
- good_parm = true;
- push_parm_decl (parm);
- }
+ if (parm == NULL)
+ bad_parm = true;
+ else
+ push_parm_decl (parm);
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
tree new_attrs;
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
c_parser_consume_token (parser);
- if (good_parm)
- return get_parm_info (false);
- else
+ if (bad_parm)
{
- struct c_arg_info *ret
- = XOBNEW (&parser_obstack, struct c_arg_info);
- ret->parms = 0;
- ret->tags = 0;
- ret->types = 0;
- ret->others = 0;
- ret->pending_sizes = 0;
- ret->had_vla_unspec = 0;
- return ret;
+ get_pending_sizes ();
+ return NULL;
}
+ else
+ return get_parm_info (false);
}
if (!c_parser_require (parser, CPP_COMMA,
"expected %<;%>, %<,%> or %<)%>"))
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
c_parser_consume_token (parser);
- if (good_parm)
- return get_parm_info (true);
- else
+ if (bad_parm)
{
- struct c_arg_info *ret
- = XOBNEW (&parser_obstack, struct c_arg_info);
- ret->parms = 0;
- ret->tags = 0;
- ret->types = 0;
- ret->others = 0;
- ret->pending_sizes = 0;
- ret->had_vla_unspec = 0;
- return ret;
+ get_pending_sizes ();
+ return NULL;
}
+ else
+ return get_parm_info (true);
}
else
{
bool dummy = false;
if (!c_parser_next_token_starts_declspecs (parser))
{
+ c_token *token = c_parser_peek_token (parser);
+ if (parser->error)
+ return NULL;
+ c_parser_set_source_position_from_token (token);
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
+ {
+ error ("unknown type name %qE", token->value);
+ parser->error = true;
+ }
/* ??? In some Objective-C cases '...' isn't applicable so there
should be a different message. */
- c_parser_error (parser,
- "expected declaration specifiers or %<...%>");
+ else
+ c_parser_error (parser,
+ "expected declaration specifiers or %<...%>");
c_parser_skip_to_end_of_parameter (parser);
return NULL;
}
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;
}
case RID_STATIC:
case RID_UNSIGNED:
case RID_LONG:
+ case RID_INT128:
case RID_CONST:
case RID_EXTERN:
case RID_REGISTER:
/* 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;
else
{
struct c_expr ret;
+ location_t loc = c_parser_peek_token (parser)->location;
ret = c_parser_expr_no_commas (parser, NULL);
if (TREE_CODE (ret.value) != STRING_CST
&& TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR)
- ret = default_function_array_conversion (ret);
+ ret = default_function_array_read_conversion (loc, ret);
return ret;
}
}
static struct c_expr
c_parser_braced_init (c_parser *parser, tree type, bool nested_p)
{
+ struct c_expr ret;
+ struct obstack braced_init_obstack;
location_t brace_loc = c_parser_peek_token (parser)->location;
+ gcc_obstack_init (&braced_init_obstack);
gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
c_parser_consume_token (parser);
if (nested_p)
- push_init_level (0);
+ push_init_level (0, &braced_init_obstack);
else
really_start_incremental_init (type);
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
comma. */
while (true)
{
- c_parser_initelt (parser);
+ c_parser_initelt (parser, &braced_init_obstack);
if (parser->error)
break;
if (c_parser_next_token_is (parser, CPP_COMMA))
}
if (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
{
- struct c_expr ret;
ret.value = error_mark_node;
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>");
- pop_init_level (0);
+ pop_init_level (0, &braced_init_obstack);
+ obstack_free (&braced_init_obstack, NULL);
return ret;
}
c_parser_consume_token (parser);
- return pop_init_level (0);
+ ret = pop_init_level (0, &braced_init_obstack);
+ obstack_free (&braced_init_obstack, NULL);
+ return ret;
}
/* Parse a nested initializer, including designators. */
static void
-c_parser_initelt (c_parser *parser)
+c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack)
{
/* Parse any designator or designator list. A single array
designator may have the subsequent "=" omitted in GNU C, but a
&& c_parser_peek_2nd_token (parser)->type == CPP_COLON)
{
/* Old-style structure member designator. */
- set_init_label (c_parser_peek_token (parser)->value);
+ set_init_label (c_parser_peek_token (parser)->value,
+ braced_init_obstack);
/* Use the colon as the error location. */
- pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_pedantic,
+ pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_pedantic,
"obsolete use of designated initializer with %<:%>");
c_parser_consume_token (parser);
c_parser_consume_token (parser);
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
- set_init_label (c_parser_peek_token (parser)->value);
+ set_init_label (c_parser_peek_token (parser)->value,
+ braced_init_obstack);
c_parser_consume_token (parser);
}
else
init.original_type = NULL;
c_parser_error (parser, "expected identifier");
c_parser_skip_until_found (parser, CPP_COMMA, NULL);
- process_init_element (init, false);
+ process_init_element (init, false, braced_init_obstack);
return;
}
}
goto parse_message_args;
}
first = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (first);
if (c_parser_next_token_is (parser, CPP_ELLIPSIS)
|| c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
goto array_desig_after_first;
while (c_parser_next_token_is (parser, CPP_COMMA))
{
struct c_expr next;
+ location_t comma_loc, exp_loc;
+ comma_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
next = c_parser_expr_no_commas (parser, NULL);
- next = default_function_array_conversion (next);
- rec = build_compound_expr (rec, next.value);
+ next = default_function_array_read_conversion (exp_loc,
+ next);
+ rec = build_compound_expr (comma_loc, rec, next.value);
}
parse_message_args:
/* Now parse the objc-message-args. */
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
initializer, starting with this message
expression as a primary-expression. */
- c_parser_initval (parser, &mexpr);
+ c_parser_initval (parser, &mexpr, braced_init_obstack);
return;
}
c_parser_consume_token (parser);
first = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (first);
array_desig_after_first:
if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
ellipsis_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
second = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (second);
}
else
second = NULL_TREE;
if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
{
c_parser_consume_token (parser);
- set_init_index (first, second);
+ set_init_index (first, second, braced_init_obstack);
if (second)
- pedwarn (ellipsis_loc, OPT_pedantic,
+ pedwarn (ellipsis_loc, OPT_pedantic,
"ISO C forbids specifying range of elements to initialize");
}
else
if (c_parser_next_token_is (parser, CPP_EQ))
{
if (!flag_isoc99)
- pedwarn (des_loc, OPT_pedantic,
+ pedwarn (des_loc, OPT_pedantic,
"ISO C90 forbids specifying subobject to initialize");
c_parser_consume_token (parser);
}
else
{
if (des_seen == 1)
- pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+ pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"obsolete use of designated initializer without %<=%>");
else
{
init.original_type = NULL;
c_parser_error (parser, "expected %<=%>");
c_parser_skip_until_found (parser, CPP_COMMA, NULL);
- process_init_element (init, false);
+ process_init_element (init, false, braced_init_obstack);
return;
}
}
}
}
- c_parser_initval (parser, NULL);
+ c_parser_initval (parser, NULL, braced_init_obstack);
}
/* Parse a nested initializer; as c_parser_initializer but parses
initializer. */
static void
-c_parser_initval (c_parser *parser, struct c_expr *after)
+c_parser_initval (c_parser *parser, struct c_expr *after,
+ struct obstack * braced_init_obstack)
{
struct c_expr init;
gcc_assert (!after || c_dialect_objc ());
init = c_parser_braced_init (parser, NULL_TREE, true);
else
{
+ location_t loc = c_parser_peek_token (parser)->location;
init = c_parser_expr_no_commas (parser, after);
if (init.value != NULL_TREE
&& TREE_CODE (init.value) != STRING_CST
&& TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
- init = default_function_array_conversion (init);
+ init = default_function_array_read_conversion (loc, init);
}
- process_init_element (init, false);
+ process_init_element (init, false, braced_init_obstack);
}
/* Parse a compound statement (possibly a function body) (C90 6.6.2,
old parser in requiring something after label declarations.
Although they are erroneous if the labels declared aren't defined,
is it useful for the syntax to be this way?
-
+
OpenMP:
-
+
block-item:
openmp-directive
c_parser_compound_statement (c_parser *parser)
{
tree stmt;
+ location_t brace_loc;
+ brace_loc = c_parser_peek_token (parser)->location;
if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
{
/* Ensure a scope is entered and left anyway to avoid confusion
if we have just prepared to enter a function body. */
stmt = c_begin_compound_stmt (true);
- c_end_compound_stmt (stmt, true);
+ c_end_compound_stmt (brace_loc, stmt, true);
return error_mark_node;
}
stmt = c_begin_compound_stmt (true);
c_parser_compound_statement_nostart (parser);
- return c_end_compound_stmt (stmt, true);
+ return c_end_compound_stmt (brace_loc, stmt, true);
}
/* Parse a compound statement except for the opening brace. This is
mark_valid_location_for_stdc_pragma (true);
if (c_parser_next_token_is_keyword (parser, RID_LABEL))
{
- location_t err_loc = c_parser_peek_token (parser)->location;
/* Read zero or more forward-declarations for labels that nested
functions can jump to. */
mark_valid_location_for_stdc_pragma (false);
while (c_parser_next_token_is_keyword (parser, RID_LABEL))
{
+ label_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
/* Any identifiers, including those declared as type names,
are OK here. */
label
= declare_label (c_parser_peek_token (parser)->value);
C_DECLARED_LABEL_FLAG (label) = 1;
- add_stmt (build_stmt (DECL_EXPR, label));
+ add_stmt (build_stmt (label_loc, DECL_EXPR, label));
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
- pedwarn (err_loc, OPT_pedantic, "ISO C forbids label declarations");
+ pedwarn (label_loc, OPT_pedantic, "ISO C forbids label declarations");
}
/* We must now have at least one statement, label or declaration. */
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
c_parser_label (parser);
}
else if (!last_label
- && c_parser_next_token_starts_declspecs (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);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
if (last_stmt)
- pedwarn_c90 (loc,
+ pedwarn_c90 (loc,
(pedantic && !flag_isoc99)
? OPT_pedantic
: OPT_Wdeclaration_after_statement,
&& (c_parser_peek_2nd_token (parser)->keyword
== RID_EXTENSION))
c_parser_consume_token (parser);
- if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+ if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)))
{
int ext;
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
last_label = false;
mark_valid_location_for_stdc_pragma (false);
- c_parser_declaration_or_fndef (parser, true, true, true, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, true,
+ true, NULL);
/* Following the old parser, __extension__ does not
disable this diagnostic. */
restore_extension_diagnostics (ext);
}
else if (c_parser_next_token_is_keyword (parser, RID_ELSE))
{
- if (parser->in_if_block)
+ if (parser->in_if_block)
{
mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
error_at (loc, """expected %<}%> before %<else%>");
return;
}
- else
+ else
{
error_at (loc, "%<else%> without a previous %<if%>");
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COLON))
{
c_parser_consume_token (parser);
- label = do_case (exp1, NULL_TREE);
+ label = do_case (loc1, exp1, NULL_TREE);
}
else if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
c_parser_consume_token (parser);
exp2 = c_parser_expr_no_commas (parser, NULL).value;
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
- label = do_case (exp1, exp2);
+ label = do_case (loc1, exp1, exp2);
}
else
c_parser_error (parser, "expected %<:%> or %<...%>");
{
c_parser_consume_token (parser);
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
- label = do_case (NULL_TREE, NULL_TREE);
+ label = do_case (loc1, NULL_TREE, NULL_TREE);
}
else
{
if (tlab)
{
decl_attributes (&tlab, attrs, 0);
- label = add_stmt (build_stmt (LABEL_EXPR, tlab));
+ label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab));
}
}
if (label)
{
- SET_EXPR_LOCATION (label, loc1);
- if (c_parser_next_token_starts_declspecs (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 "
"a declaration is not a statement");
- c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
+ 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);
}
}
}
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
- stmt = c_finish_goto_label (c_parser_peek_token (parser)->value);
+ stmt = c_finish_goto_label (loc,
+ c_parser_peek_token (parser)->value);
c_parser_consume_token (parser);
}
else if (c_parser_next_token_is (parser, CPP_MULT))
{
+ tree val;
+
c_parser_consume_token (parser);
- stmt = c_finish_goto_ptr (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 %<*%>");
goto expect_semicolon;
case RID_CONTINUE:
c_parser_consume_token (parser);
- stmt = c_finish_bc_stmt (&c_cont_label, false);
+ stmt = c_finish_bc_stmt (loc, &c_cont_label, false);
goto expect_semicolon;
case RID_BREAK:
c_parser_consume_token (parser);
- stmt = c_finish_bc_stmt (&c_break_label, true);
+ stmt = c_finish_bc_stmt (loc, &c_break_label, true);
goto expect_semicolon;
case RID_RETURN:
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
- stmt = c_finish_return (NULL_TREE, NULL_TREE);
+ stmt = c_finish_return (loc, NULL_TREE, NULL_TREE);
c_parser_consume_token (parser);
}
else
{
struct c_expr expr = c_parser_expression_conv (parser);
- stmt = c_finish_return (expr.value, expr.original_type);
+ mark_exp_read (expr.value);
+ stmt = c_finish_return (loc, expr.value, expr.original_type);
goto expect_semicolon;
}
break;
case RID_ASM:
stmt = c_parser_asm_statement (parser);
break;
- case RID_THROW:
+ case RID_AT_THROW:
gcc_assert (c_dialect_objc ());
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
- stmt = objc_build_throw_stmt (NULL_TREE);
+ stmt = objc_build_throw_stmt (loc, NULL_TREE);
c_parser_consume_token (parser);
}
else
{
tree expr = c_parser_expression (parser).value;
expr = c_fully_fold (expr, false, NULL);
- stmt = objc_build_throw_stmt (expr);
+ stmt = objc_build_throw_stmt (loc, expr);
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 ());
break;
default:
expr_stmt:
- stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value);
+ stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value);
expect_semicolon:
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
break;
(recursively) all of the component statements should already have
line numbers assigned. ??? Can we discard no-op statements
earlier? */
- protected_set_expr_location (stmt, loc);
+ if (CAN_HAVE_LOCATION_P (stmt)
+ && EXPR_LOCATION (stmt) == UNKNOWN_LOCATION)
+ SET_EXPR_LOCATION (stmt, loc);
parser->in_if_block = in_if_block;
}
static tree
c_parser_condition (c_parser *parser)
{
- location_t loc;
+ location_t loc = c_parser_peek_token (parser)->location;
tree cond;
- loc = c_parser_peek_token (parser)->location;
cond = c_parser_expression_conv (parser).value;
cond = c_objc_common_truthvalue_conversion (loc, cond);
cond = c_fully_fold (cond, false, NULL);
c_parser_c99_block_statement (c_parser *parser)
{
tree block = c_begin_compound_stmt (flag_isoc99);
+ location_t loc = c_parser_peek_token (parser)->location;
c_parser_statement (parser);
- return c_end_compound_stmt (block, flag_isoc99);
+ return c_end_compound_stmt (loc, block, flag_isoc99);
}
/* Parse the body of an if statement. This is just parsing a
c_parser_if_body (c_parser *parser, bool *if_p)
{
tree block = c_begin_compound_stmt (flag_isoc99);
+ location_t body_loc = c_parser_peek_token (parser)->location;
while (c_parser_next_token_is_keyword (parser, RID_CASE)
|| c_parser_next_token_is_keyword (parser, RID_DEFAULT)
|| (c_parser_next_token_is (parser, CPP_NAME)
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
location_t loc = c_parser_peek_token (parser)->location;
- add_stmt (build_empty_stmt ());
+ add_stmt (build_empty_stmt (loc));
c_parser_consume_token (parser);
if (!c_parser_next_token_is_keyword (parser, RID_ELSE))
warning_at (loc, OPT_Wempty_body,
add_stmt (c_parser_compound_statement (parser));
else
c_parser_statement_after_labels (parser);
- return c_end_compound_stmt (block, flag_isoc99);
+ return c_end_compound_stmt (body_loc, block, flag_isoc99);
}
/* Parse the else body of an if statement. This is just parsing a
static tree
c_parser_else_body (c_parser *parser)
{
+ location_t else_loc = c_parser_peek_token (parser)->location;
tree block = c_begin_compound_stmt (flag_isoc99);
while (c_parser_next_token_is_keyword (parser, RID_CASE)
|| c_parser_next_token_is_keyword (parser, RID_DEFAULT)
c_parser_label (parser);
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
- warning_at (c_parser_peek_token (parser)->location,
+ location_t loc = c_parser_peek_token (parser)->location;
+ warning_at (loc,
OPT_Wempty_body,
"suggest braces around empty body in an %<else%> statement");
- add_stmt (build_empty_stmt ());
+ add_stmt (build_empty_stmt (loc));
c_parser_consume_token (parser);
}
- else
+ else
c_parser_statement_after_labels (parser);
- return c_end_compound_stmt (block, flag_isoc99);
+ return c_end_compound_stmt (else_loc, block, flag_isoc99);
}
/* Parse an if statement (C90 6.6.4, C99 6.8.4).
else
second_body = NULL_TREE;
c_finish_if_stmt (loc, cond, first_body, second_body, first_if);
- add_stmt (c_end_compound_stmt (block, flag_isoc99));
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
}
/* Parse a switch statement (C90 6.6.4, C99 6.8.4).
c_parser_switch_statement (c_parser *parser)
{
tree block, expr, body, save_break;
+ location_t switch_loc = c_parser_peek_token (parser)->location;
+ location_t switch_cond_loc;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
c_parser_consume_token (parser);
block = c_begin_compound_stmt (flag_isoc99);
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
+ switch_cond_loc = c_parser_peek_token (parser)->location;
expr = c_parser_expression (parser).value;
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
else
- expr = error_mark_node;
- c_start_case (expr);
+ {
+ switch_cond_loc = UNKNOWN_LOCATION;
+ expr = error_mark_node;
+ }
+ c_start_case (switch_loc, switch_cond_loc, expr);
save_break = c_break_label;
c_break_label = NULL_TREE;
body = c_parser_c99_block_statement (parser);
c_finish_case (body);
if (c_break_label)
- add_stmt (build1 (LABEL_EXPR, void_type_node, c_break_label));
+ {
+ location_t here = c_parser_peek_token (parser)->location;
+ tree t = build1 (LABEL_EXPR, void_type_node, c_break_label);
+ SET_EXPR_LOCATION (t, here);
+ add_stmt (t);
+ }
c_break_label = save_break;
- add_stmt (c_end_compound_stmt (block, flag_isoc99));
+ add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99));
}
/* Parse a while statement (C90 6.6.5, C99 6.8.5).
c_cont_label = NULL_TREE;
body = c_parser_c99_block_statement (parser);
c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
- add_stmt (c_end_compound_stmt (block, flag_isoc99));
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
c_break_label = save_break;
c_cont_label = save_cont;
}
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
- add_stmt (c_end_compound_stmt (block, flag_isoc99));
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
}
/* Parse a for statement (C90 6.6.5, C99 6.8.5).
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;
- location_t loc;
+ /* 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));
- loc = c_parser_peek_token (parser)->location;
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 (NULL_TREE);
+ c_finish_expr_stmt (loc, NULL_TREE);
}
- else if (c_parser_next_token_starts_declspecs (parser))
+ else if (c_parser_next_tokens_start_declaration (parser))
{
- c_parser_declaration_or_fndef (parser, true, true, true, true);
- check_for_loop_decls ();
+ 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))
{
&& (c_parser_peek_2nd_token (parser)->keyword
== RID_EXTENSION))
c_parser_consume_token (parser);
- if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+ if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)))
{
int ext;
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
- c_parser_declaration_or_fndef (parser, true, true, true, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, true,
+ true, &object_expression);
+ parser->objc_could_be_foreach_context = false;
+
restore_extension_diagnostics (ext);
- check_for_loop_decls ();
+ 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 (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 (NULL_TREE);
else
- incr = c_process_expr_stmt (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 (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;
}
asm-statement:
asm type-qualifier[opt] ( asm-argument ) ;
+ asm type-qualifier[opt] goto ( asm-goto-argument ) ;
asm-argument:
asm-string-literal
asm-string-literal : asm-operands[opt]
asm-string-literal : asm-operands[opt] : asm-operands[opt]
- asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers
+ asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers[opt]
+
+ asm-goto-argument:
+ asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \
+ : asm-goto-operands
Qualifiers other than volatile are accepted in the syntax but
warned for. */
static tree
c_parser_asm_statement (c_parser *parser)
{
- tree quals, str, outputs, inputs, clobbers, ret;
- bool simple;
+ tree quals, str, outputs, inputs, clobbers, labels, ret;
+ bool simple, is_goto;
+ location_t asm_loc = c_parser_peek_token (parser)->location;
+ int section, nsections;
+
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
c_parser_consume_token (parser);
if (c_parser_next_token_is_keyword (parser, RID_VOLATILE))
}
else
quals = NULL_TREE;
+
+ is_goto = false;
+ if (c_parser_next_token_is_keyword (parser, RID_GOTO))
+ {
+ c_parser_consume_token (parser);
+ is_goto = true;
+ }
+
/* ??? Follow the C++ parser rather than using the
lex_untranslated_string kludge. */
parser->lex_untranslated_string = true;
+ ret = NULL;
+
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
- {
- parser->lex_untranslated_string = false;
- return NULL_TREE;
- }
+ goto error;
+
str = c_parser_asm_string_literal (parser);
if (str == NULL_TREE)
- {
- parser->lex_untranslated_string = false;
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- return NULL_TREE;
- }
- if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- {
- simple = true;
- outputs = NULL_TREE;
- inputs = NULL_TREE;
- clobbers = NULL_TREE;
- goto done_asm;
- }
- if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
- {
- parser->lex_untranslated_string = false;
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- return NULL_TREE;
- }
- simple = false;
- /* Parse outputs. */
- if (c_parser_next_token_is (parser, CPP_COLON)
- || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- outputs = NULL_TREE;
- else
- outputs = c_parser_asm_operands (parser, false);
- if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- {
- inputs = NULL_TREE;
- clobbers = NULL_TREE;
- goto done_asm;
- }
- if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
- {
- parser->lex_untranslated_string = false;
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- return NULL_TREE;
- }
- /* Parse inputs. */
- if (c_parser_next_token_is (parser, CPP_COLON)
- || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- inputs = NULL_TREE;
- else
- inputs = c_parser_asm_operands (parser, true);
- if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- {
- clobbers = NULL_TREE;
- goto done_asm;
- }
- if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
- {
- parser->lex_untranslated_string = false;
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- return NULL_TREE;
+ goto error_close_paren;
+
+ simple = true;
+ outputs = NULL_TREE;
+ inputs = NULL_TREE;
+ clobbers = NULL_TREE;
+ labels = NULL_TREE;
+
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto)
+ goto done_asm;
+
+ /* Parse each colon-delimited section of operands. */
+ nsections = 3 + is_goto;
+ for (section = 0; section < nsections; ++section)
+ {
+ if (!c_parser_require (parser, CPP_COLON,
+ is_goto
+ ? "expected %<:%>"
+ : "expected %<:%> or %<)%>"))
+ goto error_close_paren;
+
+ /* Once past any colon, we're no longer a simple asm. */
+ simple = false;
+
+ if ((!c_parser_next_token_is (parser, CPP_COLON)
+ && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ || section == 3)
+ switch (section)
+ {
+ case 0:
+ /* For asm goto, we don't allow output operands, but reserve
+ the slot for a future extension that does allow them. */
+ if (!is_goto)
+ outputs = c_parser_asm_operands (parser, false);
+ break;
+ case 1:
+ inputs = c_parser_asm_operands (parser, true);
+ break;
+ case 2:
+ clobbers = c_parser_asm_clobbers (parser);
+ break;
+ case 3:
+ labels = c_parser_asm_goto_operands (parser);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto)
+ goto done_asm;
}
- /* Parse clobbers. */
- clobbers = c_parser_asm_clobbers (parser);
+
done_asm:
- parser->lex_untranslated_string = false;
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- return NULL_TREE;
+ goto error;
}
+
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
- ret = build_asm_stmt (quals, build_asm_expr (str, outputs, inputs,
- clobbers, simple));
+
+ ret = build_asm_stmt (quals, build_asm_expr (asm_loc, str, outputs, inputs,
+ clobbers, labels, simple));
+
+ error:
+ parser->lex_untranslated_string = false;
return ret;
+
+ error_close_paren:
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error;
}
/* Parse asm operands, a GNU extension. If CONVERT_P (for inputs but
c_parser_asm_operands (c_parser *parser, bool convert_p)
{
tree list = NULL_TREE;
+ location_t loc;
while (true)
{
tree name, str;
parser->lex_untranslated_string = true;
return NULL_TREE;
}
+ loc = c_parser_peek_token (parser)->location;
expr = c_parser_expression (parser);
+ mark_exp_read (expr.value);
if (convert_p)
- expr = default_function_array_conversion (expr);
+ expr = default_function_array_conversion (loc, expr);
expr.value = c_fully_fold (expr.value, false, NULL);
parser->lex_untranslated_string = true;
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
return list;
}
+/* Parse asm goto labels, a GNU extension.
+
+ asm-goto-operands:
+ identifier
+ asm-goto-operands , identifier
+*/
+
+static tree
+c_parser_asm_goto_operands (c_parser *parser)
+{
+ tree list = NULL_TREE;
+ while (true)
+ {
+ tree name, label;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ name = tok->value;
+ label = lookup_label_for_goto (tok->location, name);
+ c_parser_consume_token (parser);
+ TREE_USED (label) = 1;
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ return NULL_TREE;
+ }
+
+ name = build_string (IDENTIFIER_LENGTH (name),
+ IDENTIFIER_POINTER (name));
+ list = tree_cons (name, label, list);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ return nreverse (list);
+ }
+}
+
/* Parse an expression other than a compound expression; that is, an
assignment expression (C90 6.3.16, C99 6.5.16). If AFTER is not
NULL then it is an Objective-C message expression which is the
{
struct c_expr lhs, rhs, ret;
enum tree_code code;
- location_t op_location;
+ location_t op_location, exp_location;
gcc_assert (!after || c_dialect_objc ());
lhs = c_parser_conditional_expression (parser, after);
op_location = c_parser_peek_token (parser)->location;
return lhs;
}
c_parser_consume_token (parser);
+ exp_location = c_parser_peek_token (parser)->location;
rhs = c_parser_expr_no_commas (parser, NULL);
- rhs = default_function_array_conversion (rhs);
+ rhs = default_function_array_read_conversion (exp_location, rhs);
ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type,
- code, rhs.value, rhs.original_type);
+ code, exp_location, rhs.value,
+ rhs.original_type);
if (code == NOP_EXPR)
ret.original_code = MODIFY_EXPR;
else
c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
{
struct c_expr cond, exp1, exp2, ret;
- location_t cond_loc;
+ location_t cond_loc, colon_loc, middle_loc;
gcc_assert (!after || c_dialect_objc ());
- cond_loc = c_parser_peek_token (parser)->location;
cond = c_parser_binary_expression (parser, after);
if (c_parser_next_token_is_not (parser, CPP_QUERY))
return cond;
- cond = default_function_array_conversion (cond);
+ cond_loc = c_parser_peek_token (parser)->location;
+ cond = default_function_array_read_conversion (cond_loc, cond);
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COLON))
{
tree eptype = NULL_TREE;
- pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+
+ middle_loc = c_parser_peek_token (parser)->location;
+ pedwarn (middle_loc, OPT_pedantic,
"ISO C forbids omitting the middle term of a ?: expression");
+ warn_for_omitted_condop (middle_loc, cond.value);
if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR)
{
eptype = TREE_TYPE (cond.value);
exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value);
exp1.original_type = NULL;
cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value);
- skip_evaluation += cond.value == truthvalue_true_node;
+ c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node;
}
else
{
cond.value
= c_objc_common_truthvalue_conversion
(cond_loc, default_conversion (cond.value));
- skip_evaluation += cond.value == truthvalue_false_node;
+ c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node;
exp1 = c_parser_expression_conv (parser);
- skip_evaluation += ((cond.value == truthvalue_true_node)
- - (cond.value == truthvalue_false_node));
+ mark_exp_read (exp1.value);
+ c_inhibit_evaluation_warnings +=
+ ((cond.value == truthvalue_true_node)
+ - (cond.value == truthvalue_false_node));
}
+
+ colon_loc = c_parser_peek_token (parser)->location;
if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
{
- skip_evaluation -= cond.value == truthvalue_true_node;
+ c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
ret.value = error_mark_node;
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
return ret;
}
- exp2 = c_parser_conditional_expression (parser, NULL);
- exp2 = default_function_array_conversion (exp2);
- skip_evaluation -= cond.value == truthvalue_true_node;
- ret.value = build_conditional_expr (cond.value,
+ {
+ location_t exp2_loc = c_parser_peek_token (parser)->location;
+ exp2 = c_parser_conditional_expression (parser, NULL);
+ exp2 = default_function_array_read_conversion (exp2_loc, exp2);
+ }
+ c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
+ ret.value = build_conditional_expr (colon_loc, cond.value,
cond.original_code == C_MAYBE_CONST_EXPR,
- exp1.value, exp2.value);
+ exp1.value, exp1.original_type,
+ exp2.value, exp2.original_type);
ret.original_code = ERROR_MARK;
if (exp1.value == error_mark_node || exp2.value == error_mark_node)
ret.original_type = NULL;
the stack has lower precedence than the new operator or there is
only one element on the stack; then the top expression is the LHS
of the new operator. In the case of logical AND and OR
- expressions, we also need to adjust skip_evaluation as
- appropriate when the operators are pushed and popped. */
+ 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. */
switch (stack[sp].op) \
{ \
case TRUTH_ANDIF_EXPR: \
- skip_evaluation -= stack[sp - 1].expr.value == truthvalue_false_node; \
+ c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \
+ == truthvalue_false_node); \
break; \
case TRUTH_ORIF_EXPR: \
- skip_evaluation -= stack[sp - 1].expr.value == truthvalue_true_node; \
+ c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \
+ == truthvalue_true_node); \
break; \
default: \
break; \
} \
stack[sp - 1].expr \
- = default_function_array_conversion (stack[sp - 1].expr); \
+ = default_function_array_read_conversion (stack[sp - 1].loc, \
+ stack[sp - 1].expr); \
stack[sp].expr \
- = default_function_array_conversion (stack[sp].expr); \
+ = default_function_array_read_conversion (stack[sp].loc, \
+ stack[sp].expr); \
stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \
stack[sp].op, \
stack[sp - 1].expr, \
{
case TRUTH_ANDIF_EXPR:
stack[sp].expr
- = default_function_array_conversion (stack[sp].expr);
+ = default_function_array_read_conversion (stack[sp].loc,
+ stack[sp].expr);
stack[sp].expr.value = c_objc_common_truthvalue_conversion
(stack[sp].loc, default_conversion (stack[sp].expr.value));
- skip_evaluation += stack[sp].expr.value == truthvalue_false_node;
+ c_inhibit_evaluation_warnings += (stack[sp].expr.value
+ == truthvalue_false_node);
break;
case TRUTH_ORIF_EXPR:
stack[sp].expr
- = default_function_array_conversion (stack[sp].expr);
+ = default_function_array_read_conversion (stack[sp].loc,
+ stack[sp].expr);
stack[sp].expr.value = c_objc_common_truthvalue_conversion
(stack[sp].loc, default_conversion (stack[sp].expr.value));
- skip_evaluation += stack[sp].expr.value == truthvalue_true_node;
+ c_inhibit_evaluation_warnings += (stack[sp].expr.value
+ == truthvalue_true_node);
break;
default:
break;
stack[sp].expr = c_parser_cast_expression (parser, NULL);
stack[sp].prec = oprec;
stack[sp].op = ocode;
+ stack[sp].loc = binary_loc;
}
out:
while (sp > 0)
static struct c_expr
c_parser_cast_expression (c_parser *parser, struct c_expr *after)
{
+ location_t cast_loc = c_parser_peek_token (parser)->location;
gcc_assert (!after || c_dialect_objc ());
if (after)
- return c_parser_postfix_expression_after_primary (parser, *after);
+ return c_parser_postfix_expression_after_primary (parser,
+ cast_loc, *after);
/* 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)))
{
- location_t loc;
struct c_type_name *type_name;
struct c_expr ret;
struct c_expr expr;
c_parser_consume_token (parser);
- loc = c_parser_peek_token (parser)->location;
type_name = c_parser_type_name (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
if (type_name == NULL)
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
return c_parser_postfix_expression_after_paren_type (parser, type_name,
- loc);
- expr = c_parser_cast_expression (parser, NULL);
- expr = default_function_array_conversion (expr);
- ret.value = c_cast_expr (type_name, expr.value, loc);
+ cast_loc);
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_cast_expression (parser, NULL);
+ expr = default_function_array_read_conversion (expr_loc, expr);
+ }
+ ret.value = c_cast_expr (cast_loc, type_name, expr.value);
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
return ret;
{
int ext;
struct c_expr ret, op;
- location_t loc = c_parser_peek_token (parser)->location;
+ location_t op_loc = c_parser_peek_token (parser)->location;
+ location_t exp_loc;
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
switch (c_parser_peek_token (parser)->type)
{
case CPP_PLUS_PLUS:
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- return parser_build_unary_op (PREINCREMENT_EXPR, op, loc);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op);
case CPP_MINUS_MINUS:
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- return parser_build_unary_op (PREDECREMENT_EXPR, op, loc);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op);
case CPP_AND:
c_parser_consume_token (parser);
- return parser_build_unary_op (ADDR_EXPR,
- c_parser_cast_expression (parser, NULL),
- loc);
+ op = c_parser_cast_expression (parser, NULL);
+ mark_exp_read (op.value);
+ return parser_build_unary_op (op_loc, ADDR_EXPR, op);
case CPP_MULT:
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- ret.value = build_indirect_ref (loc, op.value, "unary *");
+ op = default_function_array_read_conversion (exp_loc, op);
+ ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR);
return ret;
case CPP_PLUS:
if (!c_dialect_objc () && !in_system_header)
- warning_at (c_parser_peek_token (parser)->location,
+ warning_at (op_loc,
OPT_Wtraditional,
"traditional C rejects the unary plus operator");
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- return parser_build_unary_op (CONVERT_EXPR, op, loc);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
case CPP_MINUS:
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- return parser_build_unary_op (NEGATE_EXPR, op, loc);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
case CPP_COMPL:
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- return parser_build_unary_op (BIT_NOT_EXPR, op, loc);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
case CPP_NOT:
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- return parser_build_unary_op (TRUTH_NOT_EXPR, op, loc);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op);
case CPP_AND_AND:
/* Refer to the address of a label as a pointer. */
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
ret.value = finish_label_address_expr
- (c_parser_peek_token (parser)->value, loc);
+ (c_parser_peek_token (parser)->value, op_loc);
c_parser_consume_token (parser);
}
else
return ret;
case RID_REALPART:
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- return parser_build_unary_op (REALPART_EXPR, op, loc);
+ op = default_function_array_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, REALPART_EXPR, op);
case RID_IMAGPART:
c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_conversion (op);
- return parser_build_unary_op (IMAGPART_EXPR, op, loc);
+ op = default_function_array_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
default:
return c_parser_postfix_expression (parser);
}
location_t expr_loc;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
c_parser_consume_token (parser);
- skip_evaluation++;
+ c_inhibit_evaluation_warnings++;
in_sizeof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_typename (c_parser_peek_2nd_token (parser)))
if (type_name == NULL)
{
struct c_expr ret;
- skip_evaluation--;
+ c_inhibit_evaluation_warnings--;
in_sizeof--;
ret.value = error_mark_node;
ret.original_code = ERROR_MARK;
goto sizeof_expr;
}
/* sizeof ( type-name ). */
- skip_evaluation--;
+ c_inhibit_evaluation_warnings--;
in_sizeof--;
- return c_expr_sizeof_type (type_name);
+ return c_expr_sizeof_type (expr_loc, type_name);
}
else
{
expr_loc = c_parser_peek_token (parser)->location;
expr = c_parser_unary_expression (parser);
sizeof_expr:
- skip_evaluation--;
+ c_inhibit_evaluation_warnings--;
in_sizeof--;
+ mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- return c_expr_sizeof_expr (expr);
+ return c_expr_sizeof_expr (expr_loc, expr);
}
}
c_parser_alignof_expression (c_parser *parser)
{
struct c_expr expr;
+ location_t loc = c_parser_peek_token (parser)->location;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
c_parser_consume_token (parser);
- skip_evaluation++;
+ c_inhibit_evaluation_warnings++;
in_alignof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_typename (c_parser_peek_2nd_token (parser)))
if (type_name == NULL)
{
struct c_expr ret;
- skip_evaluation--;
+ c_inhibit_evaluation_warnings--;
in_alignof--;
ret.value = error_mark_node;
ret.original_code = ERROR_MARK;
goto alignof_expr;
}
/* alignof ( type-name ). */
- skip_evaluation--;
+ c_inhibit_evaluation_warnings--;
in_alignof--;
- ret.value = c_alignof (groktypename (type_name, NULL, NULL));
+ ret.value = c_alignof (loc, groktypename (type_name, NULL, NULL));
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
return ret;
struct c_expr ret;
expr = c_parser_unary_expression (parser);
alignof_expr:
- skip_evaluation--;
+ mark_exp_read (expr.value);
+ c_inhibit_evaluation_warnings--;
in_alignof--;
- ret.value = c_alignof_expr (expr.value);
+ ret.value = c_alignof_expr (loc, expr.value);
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
return ret;
@protocol ( identifier )
@encode ( type-name )
objc-string-literal
+ Classname . identifier
*/
static struct c_expr
{
struct c_expr expr, e1, e2, e3;
struct c_type_name *t1, *t2;
- location_t loc;
+ location_t loc = c_parser_peek_token (parser)->location;;
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
switch (c_parser_peek_token (parser)->type)
case CPP_STRING16:
case CPP_STRING32:
case CPP_WSTRING:
+ case CPP_UTF8STRING:
expr.value = c_parser_peek_token (parser)->value;
expr.original_code = STRING_CST;
c_parser_consume_token (parser);
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;
- location_t loc = c_parser_peek_token (parser)->location;
- c_parser_consume_token (parser);
- expr.value = build_external_ref (id,
- (c_parser_peek_token (parser)->type
- == CPP_OPEN_PAREN), loc,
- &expr.original_type);
- }
break;
case CPP_OPEN_PAREN:
/* A parenthesized expression, statement expression or compound
{
/* A statement expression. */
tree stmt;
- location_t here = c_parser_peek_token (parser)->location;
+ location_t brace_loc;
c_parser_consume_token (parser);
+ brace_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
if (cur_stmt_list == NULL)
{
- error_at (here, "braced-group within expression allowed "
+ error_at (loc, "braced-group within expression allowed "
"only inside a function");
parser->error = true;
c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
c_parser_compound_statement_nostart (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
- pedwarn (here, OPT_pedantic,
+ pedwarn (loc, OPT_pedantic,
"ISO C forbids braced-groups within expressions");
- expr.value = c_finish_stmt_expr (stmt);
+ expr.value = c_finish_stmt_expr (brace_loc, stmt);
+ mark_exp_read (expr.value);
}
else if (c_token_starts_typename (c_parser_peek_2nd_token (parser)))
{
case RID_FUNCTION_NAME:
case RID_PRETTY_FUNCTION_NAME:
case RID_C99_FUNCTION_NAME:
- expr.value = fname_decl (c_parser_peek_token (parser)->location,
+ expr.value = fname_decl (loc,
c_parser_peek_token (parser)->keyword,
c_parser_peek_token (parser)->value);
c_parser_consume_token (parser);
break;
}
e1 = c_parser_expr_no_commas (parser, NULL);
+ mark_exp_read (e1.value);
e1.value = c_fully_fold (e1.value, false, NULL);
if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
{
else
{
tree type_expr = NULL_TREE;
- expr.value = c_build_va_arg (e1.value,
- groktypename (t1, &type_expr, NULL),
- loc);
+ expr.value = c_build_va_arg (loc, e1.value,
+ groktypename (t1, &type_expr, NULL));
if (type_expr)
{
expr.value = build2 (C_MAYBE_CONST_EXPR,
}
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;
if (type == error_mark_node)
offsetof_ref = error_mark_node;
else
- offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node);
+ {
+ offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node);
+ SET_EXPR_LOCATION (offsetof_ref, loc);
+ }
/* Parse the second argument to __builtin_offsetof. We
must have one identifier, and beyond that we want to
accept sub structure and sub array references. */
if (c_parser_next_token_is (parser, CPP_NAME))
{
offsetof_ref = build_component_ref
- (offsetof_ref, c_parser_peek_token (parser)->value);
+ (loc, offsetof_ref, c_parser_peek_token (parser)->value);
c_parser_consume_token (parser);
while (c_parser_next_token_is (parser, CPP_DOT)
|| c_parser_next_token_is (parser,
if (c_parser_next_token_is (parser, CPP_DEREF))
{
loc = c_parser_peek_token (parser)->location;
- offsetof_ref = build_array_ref (offsetof_ref,
- integer_zero_node,
- loc);
+ offsetof_ref = build_array_ref (loc,
+ offsetof_ref,
+ integer_zero_node);
goto do_dot;
}
else if (c_parser_next_token_is (parser, CPP_DOT))
break;
}
offsetof_ref = build_component_ref
- (offsetof_ref,
+ (loc, offsetof_ref,
c_parser_peek_token (parser)->value);
c_parser_consume_token (parser);
}
idx = c_fully_fold (idx, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
- offsetof_ref = build_array_ref (offsetof_ref, idx, loc);
+ offsetof_ref = build_array_ref (loc, offsetof_ref, idx);
}
}
}
tree c;
c = e1.value;
+ mark_exp_read (e2.value);
+ mark_exp_read (e3.value);
if (TREE_CODE (c) != INTEGER_CST
|| !INTEGRAL_TYPE_P (TREE_TYPE (c)))
error_at (loc,
e1 = TYPE_MAIN_VARIANT (groktypename (t1, NULL, NULL));
e2 = TYPE_MAIN_VARIANT (groktypename (t2, NULL, NULL));
- expr.value = comptypes (e1, e2)
- ? build_int_cst (NULL_TREE, 1)
- : build_int_cst (NULL_TREE, 0);
+ expr.value
+ = comptypes (e1, e2) ? integer_one_node : integer_zero_node;
}
break;
case RID_AT_SELECTOR:
tree sel = c_parser_objc_selector_arg (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
- expr.value = objc_build_selector_expr (sel);
+ expr.value = objc_build_selector_expr (loc, sel);
}
break;
case RID_AT_PROTOCOL:
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. */
expr.value = error_mark_node;
break;
}
- return c_parser_postfix_expression_after_primary (parser, expr);
+ return c_parser_postfix_expression_after_primary (parser, loc, expr);
}
/* Parse a postfix expression after a parenthesized type name: the
location_t start_loc;
tree type_expr = NULL_TREE;
bool type_expr_const = true;
- check_compound_literal_type (type_name, type_loc);
+ check_compound_literal_type (type_loc, type_name);
start_init (NULL_TREE, NULL, 0);
type = groktypename (type_name, &type_expr, &type_expr_const);
start_loc = c_parser_peek_token (parser)->location;
finish_init ();
maybe_warn_string_init (type, init);
+ if (type != error_mark_node
+ && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type))
+ && current_function_decl)
+ {
+ error ("compound literal qualified by address-space qualifier");
+ type = error_mark_node;
+ }
+
if (!flag_isoc99)
pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals");
non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR)
? CONSTRUCTOR_NON_CONST (init.value)
: init.original_code == C_MAYBE_CONST_EXPR);
non_const |= !type_expr_const;
- expr.value = build_compound_literal (type, init.value, non_const);
+ expr.value = build_compound_literal (start_loc, type, init.value, non_const);
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
if (type_expr)
type_expr, expr.value);
}
}
- return c_parser_postfix_expression_after_primary (parser, expr);
+ return c_parser_postfix_expression_after_primary (parser, start_loc, expr);
}
/* Parse a postfix expression after the initial primary or compound
- literal; that is, parse a series of postfix operators. */
+ literal; that is, parse a series of postfix operators.
+
+ EXPR_LOC is the location of the primary expression. */
static struct c_expr
c_parser_postfix_expression_after_primary (c_parser *parser,
+ location_t expr_loc,
struct c_expr expr)
{
struct c_expr orig_expr;
tree ident, idx;
VEC(tree,gc) *exprlist;
VEC(tree,gc) *origtypes;
- location_t loc = c_parser_peek_token (parser)->location;
while (true)
{
+ location_t op_loc = c_parser_peek_token (parser)->location;
switch (c_parser_peek_token (parser)->type)
{
case CPP_OPEN_SQUARE:
/* Array reference. */
- loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
idx = c_parser_expression (parser).value;
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
- expr.value = build_array_ref (expr.value, idx, loc);
+ expr.value = build_array_ref (op_loc, expr.value, idx);
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
break;
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
orig_expr = expr;
- expr.value = build_function_call_vec (expr.value, exprlist,
+ mark_exp_read (expr.value);
+ /* FIXME diagnostics: Ideally we want the FUNCNAME, not the
+ "(" after the FUNCNAME, which is what we have now. */
+ expr.value = build_function_call_vec (op_loc, expr.value, exprlist,
origtypes);
expr.original_code = ERROR_MARK;
if (TREE_CODE (expr.value) == INTEGER_CST
case CPP_DOT:
/* Structure element reference. */
c_parser_consume_token (parser);
- expr = default_function_array_conversion (expr);
+ expr = default_function_array_conversion (expr_loc, expr);
if (c_parser_next_token_is (parser, CPP_NAME))
ident = c_parser_peek_token (parser)->value;
else
return expr;
}
c_parser_consume_token (parser);
- expr.value = build_component_ref (expr.value, ident);
+ expr.value = build_component_ref (op_loc, expr.value, ident);
expr.original_code = ERROR_MARK;
if (TREE_CODE (expr.value) != COMPONENT_REF)
expr.original_type = NULL;
case CPP_DEREF:
/* Structure element reference. */
c_parser_consume_token (parser);
- expr = default_function_array_conversion (expr);
+ expr = default_function_array_conversion (expr_loc, expr);
if (c_parser_next_token_is (parser, CPP_NAME))
ident = c_parser_peek_token (parser)->value;
else
return expr;
}
c_parser_consume_token (parser);
- expr.value = build_component_ref (build_indirect_ref (loc,
+ expr.value = build_component_ref (op_loc,
+ build_indirect_ref (op_loc,
expr.value,
- "->"),
+ RO_ARROW),
ident);
expr.original_code = ERROR_MARK;
if (TREE_CODE (expr.value) != COMPONENT_REF)
case CPP_PLUS_PLUS:
/* Postincrement. */
c_parser_consume_token (parser);
- expr = default_function_array_conversion (expr);
- expr.value = build_unary_op (loc,
+ expr = default_function_array_read_conversion (expr_loc, expr);
+ expr.value = build_unary_op (op_loc,
POSTINCREMENT_EXPR, expr.value, 0);
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
case CPP_MINUS_MINUS:
/* Postdecrement. */
c_parser_consume_token (parser);
- expr = default_function_array_conversion (expr);
- expr.value = build_unary_op (loc,
+ expr = default_function_array_read_conversion (expr_loc, expr);
+ expr.value = build_unary_op (op_loc,
POSTDECREMENT_EXPR, expr.value, 0);
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
while (c_parser_next_token_is (parser, CPP_COMMA))
{
struct c_expr next;
+ tree lhsval;
+ location_t loc = c_parser_peek_token (parser)->location;
+ location_t expr_loc;
c_parser_consume_token (parser);
+ expr_loc = c_parser_peek_token (parser)->location;
+ lhsval = expr.value;
+ while (TREE_CODE (lhsval) == COMPOUND_EXPR)
+ lhsval = TREE_OPERAND (lhsval, 1);
+ if (DECL_P (lhsval) || handled_component_p (lhsval))
+ mark_exp_read (lhsval);
next = c_parser_expr_no_commas (parser, NULL);
- next = default_function_array_conversion (next);
- expr.value = build_compound_expr (expr.value, next.value);
+ next = default_function_array_conversion (expr_loc, next);
+ expr.value = build_compound_expr (loc, expr.value, next.value);
expr.original_code = COMPOUND_EXPR;
expr.original_type = next.original_type;
}
c_parser_expression_conv (c_parser *parser)
{
struct c_expr expr;
+ location_t loc = c_parser_peek_token (parser)->location;
expr = c_parser_expression (parser);
- expr = default_function_array_conversion (expr);
+ expr = default_function_array_conversion (loc, expr);
return expr;
}
VEC(tree,gc) *ret;
VEC(tree,gc) *orig_types;
struct c_expr expr;
+ location_t loc = c_parser_peek_token (parser)->location;
ret = make_tree_vector ();
if (p_orig_types == NULL)
expr = c_parser_expr_no_commas (parser, NULL);
if (convert_p)
- expr = default_function_array_conversion (expr);
+ expr = default_function_array_read_conversion (loc, expr);
if (fold_p)
expr.value = c_fully_fold (expr.value, false, NULL);
VEC_quick_push (tree, ret, expr.value);
while (c_parser_next_token_is (parser, CPP_COMMA))
{
c_parser_consume_token (parser);
+ loc = c_parser_peek_token (parser)->location;
expr = c_parser_expr_no_commas (parser, NULL);
if (convert_p)
- expr = default_function_array_conversion (expr);
+ expr = default_function_array_read_conversion (loc, expr);
if (fold_p)
expr.value = c_fully_fold (expr.value, false, NULL);
VEC_safe_push (tree, gc, ret, expr.value);
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:
objc-protocol-refs and objc-class-instance-variables are omitted. */
static void
-c_parser_objc_class_definition (c_parser *parser)
+c_parser_objc_class_definition (c_parser *parser, tree attributes)
{
bool iface_p;
tree id1;
iface_p = false;
else
gcc_unreachable ();
+
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
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_LESS))
proto = c_parser_objc_protocol_refs (parser);
- objc_start_category_interface (id1, id2, proto);
+ objc_start_category_interface (id1, id2, proto, attributes);
c_parser_objc_methodprotolist (parser);
c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
objc_finish_interface ();
tree proto = NULL_TREE;
if (c_parser_next_token_is (parser, CPP_LESS))
proto = c_parser_objc_protocol_refs (parser);
- objc_start_class_interface (id1, superclass, proto);
+ objc_start_class_interface (id1, superclass, proto, attributes);
}
else
objc_start_class_implementation (id1, superclass);
/* Parse any stray semicolon. */
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
- pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+ pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"extra semicolon in struct or union specified");
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 (2);
+ objc_set_visibility (OBJC_IVAR_VIS_PRIVATE);
continue;
}
- else if (c_parser_next_token_is_keyword (parser, RID_PROTECTED))
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED))
{
c_parser_consume_token (parser);
- objc_set_visibility (0);
+ objc_set_visibility (OBJC_IVAR_VIS_PROTECTED);
continue;
}
- else if (c_parser_next_token_is_keyword (parser, RID_PUBLIC))
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC))
{
c_parser_consume_token (parser);
- objc_set_visibility (1);
+ objc_set_visibility (OBJC_IVAR_VIS_PUBLIC);
+ continue;
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE))
+ {
+ c_parser_consume_token (parser);
+ objc_set_visibility (OBJC_IVAR_VIS_PACKAGE);
continue;
}
else if (c_parser_next_token_is (parser, CPP_PRAGMA))
/* Comma-separated instance variables are chained together in
reverse order; add them one by one. */
tree ivar = nreverse (decls);
- for (; ivar; ivar = TREE_CHAIN (ivar))
+ 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.
omitted. */
static void
-c_parser_objc_protocol_definition (c_parser *parser)
+c_parser_objc_protocol_definition (c_parser *parser, tree attributes)
{
gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL));
+
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
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
{
if (c_parser_next_token_is (parser, CPP_LESS))
proto = c_parser_objc_protocol_refs (parser);
parser->objc_pq_context = true;
- objc_start_protocol (id, proto);
+ objc_start_protocol (id, proto, attributes);
c_parser_objc_methodprotolist (parser);
c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
parser->objc_pq_context = false;
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;
- objc_set_method_type (type);
+ bool is_class_method = c_parser_objc_method_type (parser);
+ tree decl, attributes = NULL_TREE;
parser->objc_pq_context = true;
- decl = c_parser_objc_method_decl (parser);
+ decl = c_parser_objc_method_decl (parser, is_class_method, &attributes);
+ if (decl == error_mark_node)
+ return; /* Bail here. */
+
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
c_parser_consume_token (parser);
- pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+ pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"extra semicolon in method definition specified");
}
+
if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
{
c_parser_error (parser, "expected %<{%>");
return;
}
+
parser->objc_pq_context = false;
- objc_start_method_definition (decl);
- add_stmt (c_parser_compound_statement (parser));
- objc_finish_method_definition (current_function_decl);
+ if (objc_start_method_definition (is_class_method, decl, attributes))
+ {
+ 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 (or invalid for other
+ reasons). Parse the method (to keep going) but do not emit
+ any code.
+ */
+ c_parser_compound_statement (parser);
+ }
}
/* Parse an objc-methodprotolist.
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
switch (c_parser_peek_token (parser)->type)
{
case CPP_SEMICOLON:
- pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+ pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"ISO C does not allow extra %<;%> outside of a function");
c_parser_consume_token (parser);
break;
default:
if (c_parser_next_token_is_keyword (parser, RID_AT_END))
return;
- c_parser_declaration_or_fndef (parser, 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);
- tree decl;
- objc_set_method_type (type);
+ bool is_class_method = c_parser_objc_method_type (parser);
+ tree decl, attributes = NULL_TREE;
+
/* Remember protocol qualifiers in prototypes. */
parser->objc_pq_context = true;
- decl = c_parser_objc_method_decl (parser);
- /* Forget protocol qualifiers here. */
+ decl = c_parser_objc_method_decl (parser, is_class_method, &attributes);
+ /* Forget protocol qualifiers now. */
parser->objc_pq_context = false;
- objc_add_method_declaration (decl);
+
+ /* Do not allow the presence of attributes to hide an erroneous
+ method implementation in the interface section. */
+ if (!c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_error (parser, "expected %<;%>");
+ return;
+ }
+
+ if (decl != error_mark_node)
+ objc_add_method_declaration (is_class_method, decl, attributes);
+
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
+/* If we are at a position that method attributes may be present, check that
+ there are not any parsed already (a syntax error) and then collect any
+ specified at the current location. Finally, if new attributes were present,
+ check that the next token is legal ( ';' for decls and '{' for defs). */
+
+static bool
+c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes)
+{
+ bool bad = false;
+ if (*attributes)
+ {
+ c_parser_error (parser,
+ "method attributes must be specified at the end only");
+ *attributes = NULL_TREE;
+ bad = true;
+ }
+
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ *attributes = c_parser_attributes (parser);
+
+ /* If there were no attributes here, just report any earlier error. */
+ if (*attributes == NULL_TREE || bad)
+ return bad;
+
+ /* If the attributes are followed by a ; or {, then just report any earlier
+ error. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+ || c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ return bad;
+
+ /* We've got attributes, but not at the end. */
+ c_parser_error (parser,
+ "expected %<;%> or %<{%> after method attribute definition");
+ return true;
+}
+
/* Parse an objc-method-decl.
objc-method-decl:
objc-selector
( objc-type-name ) objc-keyword-selector objc-optparmlist
objc-keyword-selector objc-optparmlist
+ attributes
objc-keyword-selector:
objc-keyword-decl
*/
static tree
-c_parser_objc_method_decl (c_parser *parser)
+c_parser_objc_method_decl (c_parser *parser, bool is_class_method, tree *attributes)
{
tree type = NULL_TREE;
tree sel;
tree parms = NULL_TREE;
bool ellipsis = false;
+ bool attr_err = false;
+ *attributes = NULL_TREE;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
c_parser_consume_token (parser);
while (true)
{
tree atype = NULL_TREE, id, keyworddecl;
+ tree param_attr = NULL_TREE;
if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
break;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
}
+ /* New ObjC allows attributes on method parameters. */
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ param_attr = c_parser_attributes (parser);
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
c_parser_error (parser, "expected identifier");
}
id = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
- keyworddecl = objc_build_keyword_decl (tsel, atype, id);
+ keyworddecl = objc_build_keyword_decl (tsel, atype, id, param_attr);
list = chainon (list, keyworddecl);
tsel = c_parser_objc_selector (parser);
if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON))
break;
}
+
+ attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ;
+
/* Parse the optional parameter list. Optional Objective-C
method parameters follow the C syntax, and may include '...'
to denote a variable number of arguments. */
{
ellipsis = true;
c_parser_consume_token (parser);
+ attr_err |= c_parser_objc_maybe_method_attributes
+ (parser, attributes) ;
break;
}
parm = c_parser_parameter_declaration (parser, NULL_TREE);
}
sel = list;
}
- return objc_build_method_signature (type, sel, parms, ellipsis);
+ else
+ attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ;
+
+ if (sel == NULL)
+ {
+ c_parser_error (parser, "objective-c method declaration is expected");
+ return error_mark_node;
+ }
+
+ if (attr_err)
+ return error_mark_node;
+
+ 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);
+ }
+ 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;
case RID_ALIGNOF:
case RID_UNSIGNED:
case RID_LONG:
+ case RID_INT128:
case RID_CONST:
case RID_SHORT:
case RID_VOLATILE:
{
tree keywordexpr;
if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
- return list;
+ return error_mark_node;
keywordexpr = c_parser_objc_keywordexpr (parser);
list = chainon (list, build_tree_list (sel, keywordexpr));
sel = c_parser_objc_selector (parser);
return ret;
}
+/* A check, needed in several places, that ObjC interface, implementation or
+ method definitions are not prefixed by incorrect items. */
+static bool
+c_parser_objc_diagnose_bad_element_prefix (c_parser *parser,
+ struct c_declspecs *specs)
+{
+ 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,");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return true;
+ }
+ 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_consume_pragma (parser);
c_invoke_pragma_handler (id);
- /* Skip to EOL, but suppress any error message. Those will have been
+ /* Skip to EOL, but suppress any error message. Those will have been
generated by the handler routine through calling error, as opposed
to calling c_parser_error. */
parser->error = true;
for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
if (OMP_CLAUSE_CODE (c) == code)
{
- error ("too many %qs clauses", name);
+ location_t loc = OMP_CLAUSE_LOCATION (c);
+ error_at (loc, "too many %qs clauses", name);
break;
}
}
identifier
variable-list , identifier
- If KIND is nonzero, create the appropriate node and install the decl
- in OMP_CLAUSE_DECL and add the node to the head of the list.
+ If KIND is nonzero, create the appropriate node and install the
+ decl in OMP_CLAUSE_DECL and add the node to the head of the list.
+ If KIND is nonzero, CLAUSE_LOC is the location of the clause.
If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE;
return the list created. */
static tree
-c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind,
+c_parser_omp_variable_list (c_parser *parser,
+ location_t clause_loc,
+ enum omp_clause_code kind,
tree list)
{
if (c_parser_next_token_is_not (parser, CPP_NAME)
tree t = lookup_name (c_parser_peek_token (parser)->value);
if (t == NULL_TREE)
- undeclared_variable (c_parser_peek_token (parser)->value,
- c_parser_peek_token (parser)->location);
+ undeclared_variable (c_parser_peek_token (parser)->location,
+ c_parser_peek_token (parser)->value);
else if (t == error_mark_node)
;
else if (kind != 0)
{
- tree u = build_omp_clause (kind);
+ tree u = build_omp_clause (clause_loc, kind);
OMP_CLAUSE_DECL (u) = t;
OMP_CLAUSE_CHAIN (u) = list;
list = u;
c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
tree list)
{
+ /* The clauses location. */
+ location_t loc = c_parser_peek_token (parser)->location;
+
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
- list = c_parser_omp_variable_list (parser, kind, list);
+ list = c_parser_omp_variable_list (parser, loc, kind, list);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
return list;
"collapse argument needs positive constant integer expression");
return list;
}
- c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
+ c = build_omp_clause (loc, OMP_CLAUSE_COLLAPSE);
OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
OMP_CLAUSE_CHAIN (c) = list;
return c;
c_parser_omp_clause_default (c_parser *parser, tree list)
{
enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+ location_t loc = c_parser_peek_token (parser)->location;
tree c;
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
return list;
check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default");
- c = build_omp_clause (OMP_CLAUSE_DEFAULT);
+ c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT);
OMP_CLAUSE_CHAIN (c) = list;
OMP_CLAUSE_DEFAULT_KIND (c) = kind;
static tree
c_parser_omp_clause_if (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);
check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if");
- c = build_omp_clause (OMP_CLAUSE_IF);
+ c = build_omp_clause (loc, OMP_CLAUSE_IF);
OMP_CLAUSE_IF_EXPR (c) = t;
OMP_CLAUSE_CHAIN (c) = list;
list = c;
c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list)
{
tree c;
+ location_t loc = c_parser_peek_token (parser)->location;
check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait");
- c = build_omp_clause (OMP_CLAUSE_NOWAIT);
+ c = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
OMP_CLAUSE_CHAIN (c) = list;
return c;
}
static tree
c_parser_omp_clause_num_threads (c_parser *parser, tree list)
{
+ location_t num_threads_loc = c_parser_peek_token (parser)->location;
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
location_t expr_loc = c_parser_peek_token (parser)->location;
}
/* Attempt to statically determine when the number isn't positive. */
- c = fold_build2 (LE_EXPR, boolean_type_node, t,
+ c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
build_int_cst (TREE_TYPE (t), 0));
+ if (CAN_HAVE_LOCATION_P (c))
+ SET_EXPR_LOCATION (c, expr_loc);
if (c == boolean_true_node)
{
warning_at (expr_loc, 0,
check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads");
- c = build_omp_clause (OMP_CLAUSE_NUM_THREADS);
+ c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_THREADS);
OMP_CLAUSE_NUM_THREADS_EXPR (c) = t;
OMP_CLAUSE_CHAIN (c) = list;
list = c;
ordered */
static tree
-c_parser_omp_clause_ordered (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+c_parser_omp_clause_ordered (c_parser *parser, tree list)
{
tree c;
check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");
- c = build_omp_clause (OMP_CLAUSE_ORDERED);
+ c = build_omp_clause (c_parser_peek_token (parser)->location,
+ OMP_CLAUSE_ORDERED);
OMP_CLAUSE_CHAIN (c) = list;
+
return c;
}
static tree
c_parser_omp_clause_reduction (c_parser *parser, tree list)
{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
enum tree_code code;
{
tree nl, c;
- nl = c_parser_omp_variable_list (parser, OMP_CLAUSE_REDUCTION, list);
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_REDUCTION, list);
for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
OMP_CLAUSE_REDUCTION_CODE (c) = code;
c_parser_omp_clause_schedule (c_parser *parser, tree list)
{
tree c, t;
+ location_t loc = c_parser_peek_token (parser)->location;
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
return list;
- c = build_omp_clause (OMP_CLAUSE_SCHEDULE);
+ c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE);
if (c_parser_next_token_is (parser, CPP_NAME))
{
/* FIXME: Should we allow duplicates? */
check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied");
- c = build_omp_clause (OMP_CLAUSE_UNTIED);
+ c = build_omp_clause (c_parser_peek_token (parser)->location,
+ OMP_CLAUSE_UNTIED);
OMP_CLAUSE_CHAIN (c) = list;
+
return c;
}
binop:
+, *, -, /, &, ^, |, <<, >>
- where x is an lvalue expression with scalar type. */
+ where x is an lvalue expression with scalar type.
+
+ LOC is the location of the #pragma token. */
static void
-c_parser_omp_atomic (c_parser *parser)
+c_parser_omp_atomic (location_t loc, c_parser *parser)
{
tree lhs, rhs;
tree stmt;
rhs = integer_one_node;
break;
+ case COMPOUND_EXPR:
+ if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
+ && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
+ && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
+ (TREE_OPERAND (lhs, 1), 0), 0)))
+ == BOOLEAN_TYPE)
+ /* Undo effects of boolean_increment for post {in,de}crement. */
+ lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
+ /* FALLTHRU */
+ case MODIFY_EXPR:
+ if (TREE_CODE (lhs) == MODIFY_EXPR
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
+ {
+ /* Undo effects of boolean_increment. */
+ if (integer_onep (TREE_OPERAND (lhs, 1)))
+ {
+ /* This is pre or post increment. */
+ rhs = TREE_OPERAND (lhs, 1);
+ lhs = TREE_OPERAND (lhs, 0);
+ code = NOP_EXPR;
+ break;
+ }
+ if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
+ && TREE_OPERAND (lhs, 0)
+ == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0))
+ {
+ /* This is pre or post decrement. */
+ rhs = TREE_OPERAND (lhs, 1);
+ lhs = TREE_OPERAND (lhs, 0);
+ code = NOP_EXPR;
+ break;
+ }
+ }
+ /* FALLTHRU */
default:
switch (c_parser_peek_token (parser)->type)
{
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);
- rhs_expr = c_parser_expression (parser);
- rhs_expr = default_function_array_conversion (rhs_expr);
+ {
+ location_t rhs_loc = c_parser_peek_token (parser)->location;
+ rhs_expr = c_parser_expression (parser);
+ rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr);
+ }
rhs = rhs_expr.value;
rhs = c_fully_fold (rhs, false, NULL);
break;
}
- stmt = c_finish_omp_atomic (code, lhs, rhs);
+ stmt = c_finish_omp_atomic (loc, code, lhs, rhs);
if (stmt != error_mark_node)
add_stmt (stmt);
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
static void
c_parser_omp_barrier (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_barrier ();
+ c_finish_omp_barrier (loc);
}
/* OpenMP 2.5:
# pragma omp critical [(name)] new-line
structured-block
-*/
+
+ LOC is the location of the #pragma itself. */
static tree
-c_parser_omp_critical (c_parser *parser)
+c_parser_omp_critical (location_t loc, c_parser *parser)
{
tree stmt, name = NULL;
c_parser_skip_to_pragma_eol (parser);
stmt = c_parser_omp_structured_block (parser);
- return c_finish_omp_critical (stmt, name);
+ return c_finish_omp_critical (loc, stmt, name);
}
/* OpenMP 2.5:
static void
c_parser_omp_flush (c_parser *parser)
{
+ location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_pragma (parser);
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
c_parser_error (parser, "expected %<(%> or end of line");
c_parser_skip_to_pragma_eol (parser);
- c_finish_omp_flush ();
+ c_finish_omp_flush (loc);
}
/* Parse the restricted form of the for statement allowed by OpenMP.
The real trick here is to determine the loop control variable early
- so that we can push a new decl if necessary to make it private. */
+ so that we can push a new decl if necessary to make it private.
+ LOC is the location of the OMP in "#pragma omp". */
static tree
-c_parser_omp_for_loop (c_parser *parser, tree clauses, tree *par_clauses)
+c_parser_omp_for_loop (location_t loc,
+ c_parser *parser, tree clauses, tree *par_clauses)
{
tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
- tree declv, condv, incrv, initv, for_block = NULL, ret = NULL;
- location_t loc;
+ tree declv, condv, incrv, initv, ret = NULL;
bool fail = false, open_brace_parsed = false;
int i, collapse = 1, nbraces = 0;
+ location_t for_loc;
+ VEC(tree,gc) *for_block = make_tree_vector ();
for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
c_parser_error (parser, "for statement expected");
return NULL;
}
- loc = c_parser_peek_token (parser)->location;
+ for_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
for (i = 0; i < collapse; i++)
goto pop_scopes;
/* Parse the initialization declaration or expression. */
- if (c_parser_next_token_starts_declspecs (parser))
+ if (c_parser_next_tokens_start_declaration (parser))
{
if (i > 0)
- for_block
- = tree_cons (NULL, c_begin_compound_stmt (true), for_block);
- c_parser_declaration_or_fndef (parser, true, true, true, true);
- decl = check_for_loop_decls ();
+ VEC_safe_push (tree, gc, for_block, c_begin_compound_stmt (true));
+ 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)
decl = decl_exp.value;
c_parser_require (parser, CPP_EQ, "expected %<=%>");
- init_loc = c_parser_peek_token (parser)->location;
+ init_loc = c_parser_peek_token (parser)->location;
init_exp = c_parser_expr_no_commas (parser, NULL);
- init_exp = default_function_array_conversion (init_exp);
+ init_exp = default_function_array_read_conversion (init_loc,
+ init_exp);
init = build_modify_expr (init_loc, decl, decl_exp.original_type,
- NOP_EXPR, init_exp.value,
+ NOP_EXPR, init_loc, init_exp.value,
init_exp.original_type);
- init = c_process_expr_stmt (init);
+ init = c_process_expr_stmt (init_loc, init);
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
{
location_t incr_loc = c_parser_peek_token (parser)->location;
- incr = c_process_expr_stmt (c_parser_expression (parser).value);
- protected_set_expr_location (incr, incr_loc);
+ incr = c_process_expr_stmt (incr_loc,
+ c_parser_expression (parser).value);
}
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
if (open_brace_parsed)
{
+ location_t here = c_parser_peek_token (parser)->location;
stmt = c_begin_compound_stmt (true);
c_parser_compound_statement_nostart (parser);
- add_stmt (c_end_compound_stmt (stmt, true));
+ add_stmt (c_end_compound_stmt (here, stmt, true));
}
else
add_stmt (c_parser_c99_block_statement (parser));
if (c_cont_label)
- add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label));
+ {
+ tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
+ SET_EXPR_LOCATION (t, loc);
+ add_stmt (t);
+ }
body = pop_stmt_list (body);
c_break_label = save_break;
c_parser_error (parser, "collapsed loops not perfectly nested");
while (nbraces)
{
+ location_t here = c_parser_peek_token (parser)->location;
stmt = c_begin_compound_stmt (true);
add_stmt (body);
c_parser_compound_statement_nostart (parser);
- body = c_end_compound_stmt (stmt, true);
+ body = c_end_compound_stmt (here, stmt, true);
nbraces--;
}
goto pop_scopes;
/* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
change it to shared (decl) in
OMP_PARALLEL_CLAUSES. */
- tree l = build_omp_clause (OMP_CLAUSE_LASTPRIVATE);
+ tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c),
+ OMP_CLAUSE_LASTPRIVATE);
OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
OMP_CLAUSE_CHAIN (l) = clauses;
clauses = l;
ret = stmt;
}
pop_scopes:
- while (for_block)
+ while (!VEC_empty (tree, for_block))
{
- stmt = c_end_compound_stmt (TREE_VALUE (for_block), true);
+ /* FIXME diagnostics: LOC below should be the actual location of
+ this particular for block. We need to build a list of
+ locations to go along with FOR_BLOCK. */
+ stmt = c_end_compound_stmt (loc, VEC_pop (tree, for_block), true);
add_stmt (stmt);
- for_block = TREE_CHAIN (for_block);
}
+ release_tree_vector (for_block);
return ret;
}
/* OpenMP 2.5:
#pragma omp for for-clause[optseq] new-line
for-loop
+
+ LOC is the location of the #pragma token.
*/
#define OMP_FOR_CLAUSE_MASK \
| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree
-c_parser_omp_for (c_parser *parser)
+c_parser_omp_for (location_t loc, c_parser *parser)
{
tree block, clauses, ret;
"#pragma omp for");
block = c_begin_compound_stmt (true);
- ret = c_parser_omp_for_loop (parser, clauses, NULL);
- block = c_end_compound_stmt (block, true);
+ ret = c_parser_omp_for_loop (loc, parser, clauses, NULL);
+ block = c_end_compound_stmt (loc, block, true);
add_stmt (block);
return ret;
/* OpenMP 2.5:
# pragma omp master new-line
structured-block
+
+ LOC is the location of the #pragma token.
*/
static tree
-c_parser_omp_master (c_parser *parser)
+c_parser_omp_master (location_t loc, c_parser *parser)
{
c_parser_skip_to_pragma_eol (parser);
- return c_finish_omp_master (c_parser_omp_structured_block (parser));
+ return c_finish_omp_master (loc, c_parser_omp_structured_block (parser));
}
/* OpenMP 2.5:
# pragma omp ordered new-line
structured-block
+
+ LOC is the location of the #pragma itself.
*/
static tree
-c_parser_omp_ordered (c_parser *parser)
+c_parser_omp_ordered (location_t loc, c_parser *parser)
{
c_parser_skip_to_pragma_eol (parser);
- return c_finish_omp_ordered (c_parser_omp_structured_block (parser));
+ return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
}
/* OpenMP 2.5:
section-sequence:
section-directive[opt] structured-block
- section-sequence section-directive structured-block */
+ section-sequence section-directive structured-block
+
+ SECTIONS_LOC is the location of the #pragma omp sections. */
static tree
-c_parser_omp_sections_scope (c_parser *parser)
+c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
{
tree stmt, substmt;
bool error_suppress = false;
location_t loc;
+ loc = c_parser_peek_token (parser)->location;
if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
{
/* Avoid skipping until the end of the block. */
stmt = push_stmt_list ();
- loc = c_parser_peek_token (parser)->location;
if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
{
substmt = push_stmt_list ();
substmt = pop_stmt_list (stmt);
stmt = make_node (OMP_SECTIONS);
+ SET_EXPR_LOCATION (stmt, sections_loc);
TREE_TYPE (stmt) = void_type_node;
OMP_SECTIONS_BODY (stmt) = substmt;
/* OpenMP 2.5:
# pragma omp sections sections-clause[optseq] newline
sections-scope
+
+ LOC is the location of the #pragma token.
*/
#define OMP_SECTIONS_CLAUSE_MASK \
| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree
-c_parser_omp_sections (c_parser *parser)
+c_parser_omp_sections (location_t loc, c_parser *parser)
{
tree block, clauses, ret;
"#pragma omp sections");
block = c_begin_compound_stmt (true);
- ret = c_parser_omp_sections_scope (parser);
+ ret = c_parser_omp_sections_scope (loc, parser);
if (ret)
OMP_SECTIONS_CLAUSES (ret) = clauses;
- block = c_end_compound_stmt (block, true);
+ block = c_end_compound_stmt (loc, block, true);
add_stmt (block);
return ret;
# pragma parallel parallel-clause new-line
# pragma parallel for parallel-for-clause new-line
# pragma parallel sections parallel-sections-clause new-line
+
+ LOC is the location of the #pragma token.
*/
#define OMP_PARALLEL_CLAUSE_MASK \
| (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS))
static tree
-c_parser_omp_parallel (c_parser *parser)
+c_parser_omp_parallel (location_t loc, c_parser *parser)
{
enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
const char *p_name = "#pragma omp parallel";
case PRAGMA_OMP_PARALLEL:
block = c_begin_omp_parallel ();
c_parser_statement (parser);
- stmt = c_finish_omp_parallel (clauses, block);
+ stmt = c_finish_omp_parallel (loc, clauses, block);
break;
case PRAGMA_OMP_PARALLEL_FOR:
block = c_begin_omp_parallel ();
- c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
- c_parser_omp_for_loop (parser, ws_clause, &par_clause);
- stmt = c_finish_omp_parallel (par_clause, block);
+ c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
+ c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause);
+ stmt = c_finish_omp_parallel (loc, par_clause, block);
OMP_PARALLEL_COMBINED (stmt) = 1;
break;
case PRAGMA_OMP_PARALLEL_SECTIONS:
block = c_begin_omp_parallel ();
- c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
- stmt = c_parser_omp_sections_scope (parser);
+ c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
+ stmt = c_parser_omp_sections_scope (loc, parser);
if (stmt)
OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
- stmt = c_finish_omp_parallel (par_clause, block);
+ stmt = c_finish_omp_parallel (loc, par_clause, block);
OMP_PARALLEL_COMBINED (stmt) = 1;
break;
/* OpenMP 2.5:
# pragma omp single single-clause[optseq] new-line
structured-block
+
+ LOC is the location of the #pragma.
*/
#define OMP_SINGLE_CLAUSE_MASK \
| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree
-c_parser_omp_single (c_parser *parser)
+c_parser_omp_single (location_t loc, c_parser *parser)
{
tree stmt = make_node (OMP_SINGLE);
+ SET_EXPR_LOCATION (stmt, loc);
TREE_TYPE (stmt) = void_type_node;
OMP_SINGLE_CLAUSES (stmt)
/* OpenMP 3.0:
# pragma omp task task-clause[optseq] new-line
+
+ LOC is the location of the #pragma.
*/
#define OMP_TASK_CLAUSE_MASK \
| (1u << PRAGMA_OMP_CLAUSE_SHARED))
static tree
-c_parser_omp_task (c_parser *parser)
+c_parser_omp_task (location_t loc, c_parser *parser)
{
tree clauses, block;
block = c_begin_omp_task ();
c_parser_statement (parser);
- return c_finish_omp_task (clauses, block);
+ return c_finish_omp_task (loc, clauses, block);
}
/* OpenMP 3.0:
static void
c_parser_omp_taskwait (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_taskwait ();
+ c_finish_omp_taskwait (loc);
}
/* Main entry point to parsing most OpenMP pragmas. */
p_kind = c_parser_peek_token (parser)->pragma_kind;
c_parser_consume_pragma (parser);
- /* For all constructs below except #pragma omp atomic
- MUST_NOT_THROW catch handlers are needed when exceptions
- are enabled. */
- if (p_kind != PRAGMA_OMP_ATOMIC)
- c_maybe_initialize_eh ();
-
switch (p_kind)
{
case PRAGMA_OMP_ATOMIC:
- c_parser_omp_atomic (parser);
+ c_parser_omp_atomic (loc, parser);
return;
case PRAGMA_OMP_CRITICAL:
- stmt = c_parser_omp_critical (parser);
+ stmt = c_parser_omp_critical (loc, parser);
break;
case PRAGMA_OMP_FOR:
- stmt = c_parser_omp_for (parser);
+ stmt = c_parser_omp_for (loc, parser);
break;
case PRAGMA_OMP_MASTER:
- stmt = c_parser_omp_master (parser);
+ stmt = c_parser_omp_master (loc, parser);
break;
case PRAGMA_OMP_ORDERED:
- stmt = c_parser_omp_ordered (parser);
+ stmt = c_parser_omp_ordered (loc, parser);
break;
case PRAGMA_OMP_PARALLEL:
- stmt = c_parser_omp_parallel (parser);
+ stmt = c_parser_omp_parallel (loc, parser);
break;
case PRAGMA_OMP_SECTIONS:
- stmt = c_parser_omp_sections (parser);
+ stmt = c_parser_omp_sections (loc, parser);
break;
case PRAGMA_OMP_SINGLE:
- stmt = c_parser_omp_single (parser);
+ stmt = c_parser_omp_single (loc, parser);
break;
case PRAGMA_OMP_TASK:
- stmt = c_parser_omp_task (parser);
+ stmt = c_parser_omp_task (loc, parser);
break;
default:
gcc_unreachable ();
}
if (stmt)
- SET_EXPR_LOCATION (stmt, loc);
+ gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION);
}
c_parser_omp_threadprivate (c_parser *parser)
{
tree vars, t;
+ location_t loc;
c_parser_consume_pragma (parser);
+ loc = c_parser_peek_token (parser)->location;
vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
/* Mark every variable in VARS to be assigned thread local storage. */
{
tree v = TREE_PURPOSE (t);
+ /* FIXME diagnostics: Ideally we should keep individual
+ locations for all the variables in the var list to make the
+ following errors more precise. Perhaps
+ c_parser_omp_var_list_parens() should construct a list of
+ locations to go along with the var list. */
+
/* If V had already been marked threadprivate, it doesn't matter
whether it had been used prior to this point. */
if (TREE_CODE (v) != VAR_DECL)
- error ("%qD is not a variable", v);
+ error_at (loc, "%qD is not a variable", v);
else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v))
- error ("%qE declared %<threadprivate%> after first use", v);
+ error_at (loc, "%qE declared %<threadprivate%> after first use", v);
else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
- error ("automatic variable %qE cannot be %<threadprivate%>", v);
+ error_at (loc, "automatic variable %qE cannot be %<threadprivate%>", v);
else if (TREE_TYPE (v) == error_mark_node)
;
else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
- error ("%<threadprivate%> %qE has incomplete type", v);
+ error_at (loc, "%<threadprivate%> %qE has incomplete type", v);
else
{
if (! DECL_THREAD_LOCAL_P (v))
if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
c_parser_pragma_pch_preprocess (&tparser);
- the_parser = GGC_NEW (c_parser);
+ the_parser = ggc_alloc_c_parser ();
*the_parser = tparser;
+ /* Initialize EH, if we've been told to do so. */
+ if (flag_exceptions)
+ using_eh_for_cleanups ();
+
c_parser_translation_unit (the_parser);
the_parser = NULL;
}