| /* Parser for C and Objective-C. |
| Copyright (C) 1987-2021 Free Software Foundation, Inc. |
| |
| Parser actions based on the old Bison parser; structure somewhat |
| influenced by and fragments based on the C++ parser. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* TODO: |
| |
| Make sure all relevant comments, and all relevant code from all |
| actions, brought over from old parser. Verify exact correspondence |
| of syntax accepted. |
| |
| Add testcases covering every input symbol in every state in old and |
| new parsers. |
| |
| Include full syntax for GNU C, including erroneous cases accepted |
| with error messages, in syntax productions in comments. |
| |
| Make more diagnostics in the front end generally take an explicit |
| location rather than implicitly using input_location. */ |
| |
| #include "config.h" |
| #define INCLUDE_UNIQUE_PTR |
| #include "system.h" |
| #include "coretypes.h" |
| #include "target.h" |
| #include "function.h" |
| #include "c-tree.h" |
| #include "timevar.h" |
| #include "stringpool.h" |
| #include "cgraph.h" |
| #include "attribs.h" |
| #include "stor-layout.h" |
| #include "varasm.h" |
| #include "trans-mem.h" |
| #include "c-family/c-pragma.h" |
| #include "c-lang.h" |
| #include "c-family/c-objc.h" |
| #include "plugin.h" |
| #include "omp-general.h" |
| #include "omp-offload.h" |
| #include "builtins.h" |
| #include "gomp-constants.h" |
| #include "c-family/c-indentation.h" |
| #include "gimple-expr.h" |
| #include "context.h" |
| #include "gcc-rich-location.h" |
| #include "c-parser.h" |
| #include "gimple-parser.h" |
| #include "read-rtl-function.h" |
| #include "run-rtl-passes.h" |
| #include "intl.h" |
| #include "c-family/name-hint.h" |
| #include "tree-iterator.h" |
| #include "tree-pretty-print.h" |
| #include "memmodel.h" |
| #include "c-family/known-headers.h" |
| |
| /* We need to walk over decls with incomplete struct/union/enum types |
| after parsing the whole translation unit. |
| In finish_decl(), if the decl is static, has incomplete |
| struct/union/enum type, it is appended to incomplete_record_decls. |
| In c_parser_translation_unit(), we iterate over incomplete_record_decls |
| and report error if any of the decls are still incomplete. */ |
| |
| vec<tree> incomplete_record_decls; |
| |
| void |
| set_c_expr_source_range (c_expr *expr, |
| location_t start, location_t finish) |
| { |
| expr->src_range.m_start = start; |
| expr->src_range.m_finish = finish; |
| if (expr->value) |
| set_source_range (expr->value, start, finish); |
| } |
| |
| void |
| set_c_expr_source_range (c_expr *expr, |
| source_range src_range) |
| { |
| expr->src_range = src_range; |
| if (expr->value) |
| set_source_range (expr->value, src_range); |
| } |
| |
| |
| /* Initialization routine for this file. */ |
| |
| void |
| c_parse_init (void) |
| { |
| /* The only initialization required is of the reserved word |
| identifiers. */ |
| unsigned int i; |
| 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 (flag_no_asm) |
| { |
| mask |= D_ASM | D_EXT; |
| if (!flag_isoc99) |
| mask |= D_EXT89; |
| } |
| if (!c_dialect_objc ()) |
| mask |= D_OBJC | D_CXX_OBJC; |
| |
| ridpointers = ggc_cleared_vec_alloc<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 |
| and so create a canonical spelling that isn't a keyword. */ |
| if (c_common_reswords[i].disable & mask) |
| { |
| if (warn_cxx_compat |
| && (c_common_reswords[i].disable & D_CXXWARN)) |
| { |
| id = get_identifier (c_common_reswords[i].word); |
| C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN); |
| C_IS_RESERVED_WORD (id) = 1; |
| } |
| continue; |
| } |
| |
| id = get_identifier (c_common_reswords[i].word); |
| C_SET_RID_CODE (id, c_common_reswords[i].rid); |
| C_IS_RESERVED_WORD (id) = 1; |
| ridpointers [(int) c_common_reswords[i].rid] = id; |
| } |
| |
| for (i = 0; i < NUM_INT_N_ENTS; i++) |
| { |
| /* We always create the symbols but they aren't always supported. */ |
| char name[50]; |
| sprintf (name, "__int%d", int_n_data[i].bitsize); |
| id = get_identifier (name); |
| C_SET_RID_CODE (id, RID_FIRST_INT_N + i); |
| C_IS_RESERVED_WORD (id) = 1; |
| |
| sprintf (name, "__int%d__", int_n_data[i].bitsize); |
| id = get_identifier (name); |
| C_SET_RID_CODE (id, RID_FIRST_INT_N + i); |
| C_IS_RESERVED_WORD (id) = 1; |
| } |
| } |
| |
| /* A parser structure recording information about the state and |
| context of parsing. Includes lexer information with up to two |
| tokens of look-ahead; more are not needed for C. */ |
| struct GTY(()) c_parser { |
| /* The look-ahead tokens. */ |
| c_token * GTY((skip)) tokens; |
| /* Buffer for look-ahead tokens. */ |
| c_token tokens_buf[4]; |
| /* How many look-ahead tokens are available (0 - 4, or |
| more if parsing from pre-lexed tokens). */ |
| unsigned int tokens_avail; |
| /* Raw look-ahead tokens, used only for checking in Objective-C |
| whether '[[' starts attributes. */ |
| vec<c_token, va_gc> *raw_tokens; |
| /* The number of raw look-ahead tokens that have since been fully |
| lexed. */ |
| unsigned int raw_tokens_used; |
| /* True if a syntax error is being recovered from; false otherwise. |
| c_parser_error sets this flag. It should clear this flag when |
| enough tokens have been consumed to recover from the error. */ |
| BOOL_BITFIELD error : 1; |
| /* True if we're processing a pragma, and shouldn't automatically |
| consume CPP_PRAGMA_EOL. */ |
| BOOL_BITFIELD in_pragma : 1; |
| /* True if we're parsing the outermost block of an if statement. */ |
| BOOL_BITFIELD in_if_block : 1; |
| /* True if we want to lex a translated, joined string (for an |
| initial #pragma pch_preprocess). Otherwise the parser is |
| responsible for concatenating strings and translating to the |
| execution character set as needed. */ |
| BOOL_BITFIELD lex_joined_string : 1; |
| /* True if, when the parser is concatenating string literals, it |
| should translate them to the execution character set (false |
| inside attributes). */ |
| BOOL_BITFIELD translate_strings_p : 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; |
| /* Nonzero if we're processing a __transaction statement. The value |
| is 1 | TM_STMT_ATTR_*. */ |
| unsigned int in_transaction : 4; |
| /* True if we are in a context where the Objective-C "Property attribute" |
| keywords are valid. */ |
| BOOL_BITFIELD objc_property_attr_context : 1; |
| |
| /* Whether we have just seen/constructed a string-literal. Set when |
| returning a string-literal from c_parser_string_literal. Reset |
| in consume_token. Useful when we get a parse error and see an |
| unknown token, which could have been a string-literal constant |
| macro. */ |
| BOOL_BITFIELD seen_string_literal : 1; |
| |
| /* Location of the last consumed token. */ |
| location_t last_token_location; |
| }; |
| |
| /* Return a pointer to the Nth token in PARSERs tokens_buf. */ |
| |
| c_token * |
| c_parser_tokens_buf (c_parser *parser, unsigned n) |
| { |
| return &parser->tokens_buf[n]; |
| } |
| |
| /* Return the error state of PARSER. */ |
| |
| bool |
| c_parser_error (c_parser *parser) |
| { |
| return parser->error; |
| } |
| |
| /* Set the error state of PARSER to ERR. */ |
| |
| void |
| c_parser_set_error (c_parser *parser, bool err) |
| { |
| parser->error = err; |
| } |
| |
| |
| /* The actual parser and external interface. ??? Does this need to be |
| garbage-collected? */ |
| |
| static GTY (()) c_parser *the_parser; |
| |
| /* Read in and lex a single token, storing it in *TOKEN. If RAW, |
| context-sensitive postprocessing of the token is not done. */ |
| |
| static void |
| c_lex_one_token (c_parser *parser, c_token *token, bool raw = false) |
| { |
| timevar_push (TV_LEX); |
| |
| if (raw || vec_safe_length (parser->raw_tokens) == 0) |
| { |
| token->type = c_lex_with_flags (&token->value, &token->location, |
| &token->flags, |
| (parser->lex_joined_string |
| ? 0 : C_LEX_STRING_NO_JOIN)); |
| token->id_kind = C_ID_NONE; |
| token->keyword = RID_MAX; |
| token->pragma_kind = PRAGMA_NONE; |
| } |
| else |
| { |
| /* Use a token previously lexed as a raw look-ahead token, and |
| complete the processing on it. */ |
| *token = (*parser->raw_tokens)[parser->raw_tokens_used]; |
| ++parser->raw_tokens_used; |
| if (parser->raw_tokens_used == vec_safe_length (parser->raw_tokens)) |
| { |
| vec_free (parser->raw_tokens); |
| parser->raw_tokens_used = 0; |
| } |
| } |
| |
| if (raw) |
| goto out; |
| |
| switch (token->type) |
| { |
| case CPP_NAME: |
| { |
| tree decl; |
| |
| bool objc_force_identifier = parser->objc_need_raw_identifier; |
| if (c_dialect_objc ()) |
| parser->objc_need_raw_identifier = false; |
| |
| if (C_IS_RESERVED_WORD (token->value)) |
| { |
| enum rid rid_code = C_RID_CODE (token->value); |
| |
| if (rid_code == RID_CXX_COMPAT_WARN) |
| { |
| warning_at (token->location, |
| OPT_Wc___compat, |
| "identifier %qE conflicts with C++ keyword", |
| token->value); |
| } |
| else if (rid_code >= RID_FIRST_ADDR_SPACE |
| && rid_code <= RID_LAST_ADDR_SPACE) |
| { |
| addr_space_t as; |
| as = (addr_space_t) (rid_code - RID_FIRST_ADDR_SPACE); |
| targetm.addr_space.diagnose_usage (as, token->location); |
| token->id_kind = C_ID_ADDRSPACE; |
| token->keyword = rid_code; |
| break; |
| } |
| else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code)) |
| { |
| /* 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) |
| { |
| /* 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 |
| { |
| token->type = CPP_KEYWORD; |
| token->keyword = rid_code; |
| break; |
| } |
| } |
| |
| decl = lookup_name (token->value); |
| if (decl) |
| { |
| if (TREE_CODE (decl) == TYPE_DECL) |
| { |
| token->id_kind = C_ID_TYPENAME; |
| break; |
| } |
| } |
| else if (c_dialect_objc ()) |
| { |
| tree objc_interface_decl = objc_is_class_name (token->value); |
| /* Objective-C class names are in the same namespace as |
| variables and typedefs, and hence are shadowed by local |
| declarations. */ |
| if (objc_interface_decl |
| && (!objc_force_identifier || global_bindings_p ())) |
| { |
| token->value = objc_interface_decl; |
| token->id_kind = C_ID_CLASSNAME; |
| break; |
| } |
| } |
| token->id_kind = C_ID_ID; |
| } |
| break; |
| case CPP_AT_NAME: |
| /* This only happens in Objective-C; it must be a keyword. */ |
| token->type = CPP_KEYWORD; |
| 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; |
| case RID_SYNCHRONIZED: token->keyword = RID_AT_SYNCHRONIZED; break; |
| default: token->keyword = C_RID_CODE (token->value); |
| } |
| break; |
| case CPP_COLON: |
| case CPP_COMMA: |
| case CPP_CLOSE_PAREN: |
| case CPP_SEMICOLON: |
| /* These tokens may affect the interpretation of any identifiers |
| following, if doing Objective-C. */ |
| if (c_dialect_objc ()) |
| parser->objc_need_raw_identifier = false; |
| break; |
| case CPP_PRAGMA: |
| /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ |
| token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value); |
| token->value = NULL; |
| break; |
| default: |
| break; |
| } |
| out: |
| timevar_pop (TV_LEX); |
| } |
| |
| /* Return a pointer to the next token from PARSER, reading it in if |
| necessary. */ |
| |
| c_token * |
| c_parser_peek_token (c_parser *parser) |
| { |
| if (parser->tokens_avail == 0) |
| { |
| c_lex_one_token (parser, &parser->tokens[0]); |
| parser->tokens_avail = 1; |
| } |
| return &parser->tokens[0]; |
| } |
| |
| /* Return a pointer to the next-but-one token from PARSER, reading it |
| in if necessary. The next token is already read in. */ |
| |
| 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 a pointer to the Nth token from PARSER, reading it |
| in if necessary. The N-1th token is already read in. */ |
| |
| c_token * |
| c_parser_peek_nth_token (c_parser *parser, unsigned int n) |
| { |
| /* N is 1-based, not zero-based. */ |
| gcc_assert (n > 0); |
| |
| if (parser->tokens_avail >= n) |
| return &parser->tokens[n - 1]; |
| gcc_assert (parser->tokens_avail == n - 1); |
| c_lex_one_token (parser, &parser->tokens[n - 1]); |
| parser->tokens_avail = n; |
| return &parser->tokens[n - 1]; |
| } |
| |
| /* Return a pointer to the Nth token from PARSER, reading it in as a |
| raw look-ahead token if necessary. The N-1th token is already read |
| in. Raw look-ahead tokens remain available for when the non-raw |
| functions above are called. */ |
| |
| c_token * |
| c_parser_peek_nth_token_raw (c_parser *parser, unsigned int n) |
| { |
| /* N is 1-based, not zero-based. */ |
| gcc_assert (n > 0); |
| |
| if (parser->tokens_avail >= n) |
| return &parser->tokens[n - 1]; |
| unsigned int raw_len = vec_safe_length (parser->raw_tokens); |
| unsigned int raw_avail |
| = parser->tokens_avail + raw_len - parser->raw_tokens_used; |
| gcc_assert (raw_avail >= n - 1); |
| if (raw_avail >= n) |
| return &(*parser->raw_tokens)[parser->raw_tokens_used |
| + n - 1 - parser->tokens_avail]; |
| vec_safe_reserve (parser->raw_tokens, 1); |
| parser->raw_tokens->quick_grow (raw_len + 1); |
| c_lex_one_token (parser, &(*parser->raw_tokens)[raw_len], true); |
| return &(*parser->raw_tokens)[raw_len]; |
| } |
| |
| bool |
| c_keyword_starts_typename (enum rid keyword) |
| { |
| switch (keyword) |
| { |
| case RID_UNSIGNED: |
| case RID_LONG: |
| case RID_SHORT: |
| case RID_SIGNED: |
| case RID_COMPLEX: |
| case RID_INT: |
| case RID_CHAR: |
| case RID_FLOAT: |
| case RID_DOUBLE: |
| case RID_VOID: |
| case RID_DFLOAT32: |
| case RID_DFLOAT64: |
| case RID_DFLOAT128: |
| CASE_RID_FLOATN_NX: |
| case RID_BOOL: |
| case RID_ENUM: |
| case RID_STRUCT: |
| case RID_UNION: |
| case RID_TYPEOF: |
| case RID_CONST: |
| case RID_ATOMIC: |
| case RID_VOLATILE: |
| case RID_RESTRICT: |
| case RID_ATTRIBUTE: |
| case RID_FRACT: |
| case RID_ACCUM: |
| case RID_SAT: |
| case RID_AUTO_TYPE: |
| case RID_ALIGNAS: |
| return true; |
| default: |
| if (keyword >= RID_FIRST_INT_N |
| && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS |
| && int_n_enabled_p[keyword - RID_FIRST_INT_N]) |
| return true; |
| return false; |
| } |
| } |
| |
| /* Return true if TOKEN can start a type name, |
| false otherwise. */ |
| bool |
| c_token_starts_typename (c_token *token) |
| { |
| switch (token->type) |
| { |
| case CPP_NAME: |
| switch (token->id_kind) |
| { |
| case C_ID_ID: |
| return false; |
| case C_ID_ADDRSPACE: |
| return true; |
| case C_ID_TYPENAME: |
| return true; |
| case C_ID_CLASSNAME: |
| gcc_assert (c_dialect_objc ()); |
| return true; |
| default: |
| gcc_unreachable (); |
| } |
| case CPP_KEYWORD: |
| return c_keyword_starts_typename (token->keyword); |
| case CPP_LESS: |
| if (c_dialect_objc ()) |
| return true; |
| return false; |
| default: |
| return false; |
| } |
| } |
| |
| /* 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: |
| case RID_ATOMIC: |
| 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_is_qualifier (c_parser *parser) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| return c_token_is_qualifier (token); |
| } |
| |
| /* Return true if TOKEN can start declaration specifiers (not |
| including standard attributes), false otherwise. */ |
| static bool |
| c_token_starts_declspecs (c_token *token) |
| { |
| switch (token->type) |
| { |
| case CPP_NAME: |
| switch (token->id_kind) |
| { |
| case C_ID_ID: |
| return false; |
| case C_ID_ADDRSPACE: |
| return true; |
| case C_ID_TYPENAME: |
| return true; |
| case C_ID_CLASSNAME: |
| gcc_assert (c_dialect_objc ()); |
| return true; |
| default: |
| gcc_unreachable (); |
| } |
| case CPP_KEYWORD: |
| switch (token->keyword) |
| { |
| case RID_STATIC: |
| case RID_EXTERN: |
| case RID_REGISTER: |
| case RID_TYPEDEF: |
| case RID_INLINE: |
| case RID_NORETURN: |
| case RID_AUTO: |
| case RID_THREAD: |
| case RID_UNSIGNED: |
| case RID_LONG: |
| case RID_SHORT: |
| case RID_SIGNED: |
| case RID_COMPLEX: |
| case RID_INT: |
| case RID_CHAR: |
| case RID_FLOAT: |
| case RID_DOUBLE: |
| case RID_VOID: |
| case RID_DFLOAT32: |
| case RID_DFLOAT64: |
| case RID_DFLOAT128: |
| CASE_RID_FLOATN_NX: |
| case RID_BOOL: |
| case RID_ENUM: |
| case RID_STRUCT: |
| case RID_UNION: |
| case RID_TYPEOF: |
| case RID_CONST: |
| case RID_VOLATILE: |
| case RID_RESTRICT: |
| case RID_ATTRIBUTE: |
| case RID_FRACT: |
| case RID_ACCUM: |
| case RID_SAT: |
| case RID_ALIGNAS: |
| case RID_ATOMIC: |
| case RID_AUTO_TYPE: |
| return true; |
| default: |
| if (token->keyword >= RID_FIRST_INT_N |
| && token->keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS |
| && int_n_enabled_p[token->keyword - RID_FIRST_INT_N]) |
| return true; |
| return false; |
| } |
| case CPP_LESS: |
| if (c_dialect_objc ()) |
| return true; |
| return false; |
| default: |
| return false; |
| } |
| } |
| |
| |
| /* Return true if TOKEN can start declaration specifiers (not |
| including standard attributes) 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 (not including standard attributes), false |
| otherwise. */ |
| 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 true if the next tokens from PARSER can start declaration |
| specifiers (not including standard attributes) or a static |
| assertion, false otherwise. */ |
| bool |
| c_parser_next_tokens_start_declaration (c_parser *parser) |
| { |
| 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. */ |
| |
| void |
| c_parser_consume_token (c_parser *parser) |
| { |
| gcc_assert (parser->tokens_avail >= 1); |
| gcc_assert (parser->tokens[0].type != CPP_EOF); |
| gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); |
| gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); |
| parser->last_token_location = parser->tokens[0].location; |
| if (parser->tokens != &parser->tokens_buf[0]) |
| parser->tokens++; |
| else if (parser->tokens_avail >= 2) |
| { |
| parser->tokens[0] = parser->tokens[1]; |
| if (parser->tokens_avail >= 3) |
| { |
| parser->tokens[1] = parser->tokens[2]; |
| if (parser->tokens_avail >= 4) |
| parser->tokens[2] = parser->tokens[3]; |
| } |
| } |
| parser->tokens_avail--; |
| parser->seen_string_literal = false; |
| } |
| |
| /* Expect the current token to be a #pragma. Consume it and remember |
| that we've begun parsing a pragma. */ |
| |
| static void |
| c_parser_consume_pragma (c_parser *parser) |
| { |
| gcc_assert (!parser->in_pragma); |
| gcc_assert (parser->tokens_avail >= 1); |
| gcc_assert (parser->tokens[0].type == CPP_PRAGMA); |
| if (parser->tokens != &parser->tokens_buf[0]) |
| parser->tokens++; |
| else if (parser->tokens_avail >= 2) |
| { |
| parser->tokens[0] = parser->tokens[1]; |
| if (parser->tokens_avail >= 3) |
| parser->tokens[1] = parser->tokens[2]; |
| } |
| parser->tokens_avail--; |
| parser->in_pragma = true; |
| } |
| |
| /* Update the global input_location from TOKEN. */ |
| static inline void |
| c_parser_set_source_position_from_token (c_token *token) |
| { |
| if (token->type != CPP_EOF) |
| { |
| input_location = token->location; |
| } |
| } |
| |
| /* Helper function for c_parser_error. |
| Having peeked a token of kind TOK1_KIND that might signify |
| a conflict marker, peek successor tokens to determine |
| if we actually do have a conflict marker. |
| Specifically, we consider a run of 7 '<', '=' or '>' characters |
| at the start of a line as a conflict marker. |
| These come through the lexer as three pairs and a single, |
| e.g. three CPP_LSHIFT ("<<") and a CPP_LESS ('<'). |
| If it returns true, *OUT_LOC is written to with the location/range |
| of the marker. */ |
| |
| static bool |
| c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind, |
| location_t *out_loc) |
| { |
| c_token *token2 = c_parser_peek_2nd_token (parser); |
| if (token2->type != tok1_kind) |
| return false; |
| c_token *token3 = c_parser_peek_nth_token (parser, 3); |
| if (token3->type != tok1_kind) |
| return false; |
| c_token *token4 = c_parser_peek_nth_token (parser, 4); |
| if (token4->type != conflict_marker_get_final_tok_kind (tok1_kind)) |
| return false; |
| |
| /* It must be at the start of the line. */ |
| location_t start_loc = c_parser_peek_token (parser)->location; |
| if (LOCATION_COLUMN (start_loc) != 1) |
| return false; |
| |
| /* We have a conflict marker. Construct a location of the form: |
| <<<<<<< |
| ^~~~~~~ |
| with start == caret, finishing at the end of the marker. */ |
| location_t finish_loc = get_finish (token4->location); |
| *out_loc = make_location (start_loc, start_loc, finish_loc); |
| |
| return true; |
| } |
| |
| /* Issue a diagnostic of the form |
| FILE:LINE: MESSAGE before TOKEN |
| where TOKEN is the next token in the input stream of PARSER. |
| MESSAGE (specified by the caller) is usually of the form "expected |
| OTHER-TOKEN". |
| |
| Use RICHLOC as the location of the diagnostic. |
| |
| Do not issue a diagnostic if still recovering from an error. |
| |
| Return true iff an error was actually emitted. |
| |
| ??? This is taken from the C++ parser, but building up messages in |
| this way is not i18n-friendly and some other approach should be |
| used. */ |
| |
| static bool |
| c_parser_error_richloc (c_parser *parser, const char *gmsgid, |
| rich_location *richloc) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| if (parser->error) |
| return false; |
| parser->error = true; |
| if (!gmsgid) |
| return false; |
| |
| /* If this is actually a conflict marker, report it as such. */ |
| if (token->type == CPP_LSHIFT |
| || token->type == CPP_RSHIFT |
| || token->type == CPP_EQ_EQ) |
| { |
| location_t loc; |
| if (c_parser_peek_conflict_marker (parser, token->type, &loc)) |
| { |
| error_at (loc, "version control conflict marker in file"); |
| return true; |
| } |
| } |
| |
| /* If we were parsing a string-literal and there is an unknown name |
| token right after, then check to see if that could also have been |
| a literal string by checking the name against a list of known |
| standard string literal constants defined in header files. If |
| there is one, then add that as an hint to the error message. */ |
| auto_diagnostic_group d; |
| name_hint h; |
| if (parser->seen_string_literal && token->type == CPP_NAME) |
| { |
| tree name = token->value; |
| const char *token_name = IDENTIFIER_POINTER (name); |
| const char *header_hint |
| = get_c_stdlib_header_for_string_macro_name (token_name); |
| if (header_hint != NULL) |
| h = name_hint (NULL, new suggest_missing_header (token->location, |
| token_name, |
| header_hint)); |
| } |
| |
| c_parse_error (gmsgid, |
| /* Because c_parse_error does not understand |
| CPP_KEYWORD, keywords are treated like |
| identifiers. */ |
| (token->type == CPP_KEYWORD ? CPP_NAME : token->type), |
| /* ??? The C parser does not save the cpp flags of a |
| token, we need to pass 0 here and we will not get |
| the source spelling of some tokens but rather the |
| canonical spelling. */ |
| token->value, /*flags=*/0, richloc); |
| return true; |
| } |
| |
| /* As c_parser_error_richloc, but issue the message at the |
| location of PARSER's next token, or at input_location |
| if the next token is EOF. */ |
| |
| bool |
| c_parser_error (c_parser *parser, const char *gmsgid) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| c_parser_set_source_position_from_token (token); |
| rich_location richloc (line_table, input_location); |
| return c_parser_error_richloc (parser, gmsgid, &richloc); |
| } |
| |
| /* Some tokens naturally come in pairs e.g.'(' and ')'. |
| This class is for tracking such a matching pair of symbols. |
| In particular, it tracks the location of the first token, |
| so that if the second token is missing, we can highlight the |
| location of the first token when notifying the user about the |
| problem. */ |
| |
| template <typename traits_t> |
| class token_pair |
| { |
| public: |
| /* token_pair's ctor. */ |
| token_pair () : m_open_loc (UNKNOWN_LOCATION) {} |
| |
| /* If the next token is the opening symbol for this pair, consume it and |
| return true. |
| Otherwise, issue an error and return false. |
| In either case, record the location of the opening token. */ |
| |
| bool require_open (c_parser *parser) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| if (token) |
| m_open_loc = token->location; |
| |
| return c_parser_require (parser, traits_t::open_token_type, |
| traits_t::open_gmsgid); |
| } |
| |
| /* Consume the next token from PARSER, recording its location as |
| that of the opening token within the pair. */ |
| |
| void consume_open (c_parser *parser) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| gcc_assert (token->type == traits_t::open_token_type); |
| m_open_loc = token->location; |
| c_parser_consume_token (parser); |
| } |
| |
| /* If the next token is the closing symbol for this pair, consume it |
| and return true. |
| Otherwise, issue an error, highlighting the location of the |
| corresponding opening token, and return false. */ |
| |
| bool require_close (c_parser *parser) const |
| { |
| return c_parser_require (parser, traits_t::close_token_type, |
| traits_t::close_gmsgid, m_open_loc); |
| } |
| |
| /* Like token_pair::require_close, except that tokens will be skipped |
| until the desired token is found. An error message is still produced |
| if the next token is not as expected. */ |
| |
| void skip_until_found_close (c_parser *parser) const |
| { |
| c_parser_skip_until_found (parser, traits_t::close_token_type, |
| traits_t::close_gmsgid, m_open_loc); |
| } |
| |
| private: |
| location_t m_open_loc; |
| }; |
| |
| /* Traits for token_pair<T> for tracking matching pairs of parentheses. */ |
| |
| struct matching_paren_traits |
| { |
| static const enum cpp_ttype open_token_type = CPP_OPEN_PAREN; |
| static const char * const open_gmsgid; |
| static const enum cpp_ttype close_token_type = CPP_CLOSE_PAREN; |
| static const char * const close_gmsgid; |
| }; |
| |
| const char * const matching_paren_traits::open_gmsgid = "expected %<(%>"; |
| const char * const matching_paren_traits::close_gmsgid = "expected %<)%>"; |
| |
| /* "matching_parens" is a token_pair<T> class for tracking matching |
| pairs of parentheses. */ |
| |
| typedef token_pair<matching_paren_traits> matching_parens; |
| |
| /* Traits for token_pair<T> for tracking matching pairs of braces. */ |
| |
| struct matching_brace_traits |
| { |
| static const enum cpp_ttype open_token_type = CPP_OPEN_BRACE; |
| static const char * const open_gmsgid; |
| static const enum cpp_ttype close_token_type = CPP_CLOSE_BRACE; |
| static const char * const close_gmsgid; |
| }; |
| |
| const char * const matching_brace_traits::open_gmsgid = "expected %<{%>"; |
| const char * const matching_brace_traits::close_gmsgid = "expected %<}%>"; |
| |
| /* "matching_braces" is a token_pair<T> class for tracking matching |
| pairs of braces. */ |
| |
| typedef token_pair<matching_brace_traits> matching_braces; |
| |
| /* Get a description of the matching symbol to TYPE e.g. "(" for |
| CPP_CLOSE_PAREN. */ |
| |
| static const char * |
| get_matching_symbol (enum cpp_ttype type) |
| { |
| switch (type) |
| { |
| default: |
| gcc_unreachable (); |
| return ""; |
| case CPP_CLOSE_PAREN: |
| return "("; |
| case CPP_CLOSE_BRACE: |
| return "{"; |
| } |
| } |
| |
| /* If the next token is of the indicated TYPE, consume it. Otherwise, |
| issue the error MSGID. If MSGID is NULL then a message has already |
| been produced and no message will be produced this time. Returns |
| true if found, false otherwise. |
| |
| If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it |
| within any error as the location of an "opening" token matching |
| the close token TYPE (e.g. the location of the '(' when TYPE is |
| CPP_CLOSE_PAREN). |
| |
| If TYPE_IS_UNIQUE is true (the default) then msgid describes exactly |
| one type (e.g. "expected %<)%>") and thus it may be reasonable to |
| attempt to generate a fix-it hint for the problem. |
| Otherwise msgid describes multiple token types (e.g. |
| "expected %<;%>, %<,%> or %<)%>"), and thus we shouldn't attempt to |
| generate a fix-it hint. */ |
| |
| bool |
| c_parser_require (c_parser *parser, |
| enum cpp_ttype type, |
| const char *msgid, |
| location_t matching_location, |
| bool type_is_unique) |
| { |
| if (c_parser_next_token_is (parser, type)) |
| { |
| c_parser_consume_token (parser); |
| return true; |
| } |
| else |
| { |
| location_t next_token_loc = c_parser_peek_token (parser)->location; |
| gcc_rich_location richloc (next_token_loc); |
| |
| /* Potentially supply a fix-it hint, suggesting to add the |
| missing token immediately after the *previous* token. |
| This may move the primary location within richloc. */ |
| if (!parser->error && type_is_unique) |
| maybe_suggest_missing_token_insertion (&richloc, type, |
| parser->last_token_location); |
| |
| /* If matching_location != UNKNOWN_LOCATION, highlight it. |
| Attempt to consolidate diagnostics by printing it as a |
| secondary range within the main diagnostic. */ |
| bool added_matching_location = false; |
| if (matching_location != UNKNOWN_LOCATION) |
| added_matching_location |
| = richloc.add_location_if_nearby (matching_location); |
| |
| if (c_parser_error_richloc (parser, msgid, &richloc)) |
| /* If we weren't able to consolidate matching_location, then |
| print it as a secondary diagnostic. */ |
| if (matching_location != UNKNOWN_LOCATION && !added_matching_location) |
| inform (matching_location, "to match this %qs", |
| get_matching_symbol (type)); |
| |
| return false; |
| } |
| } |
| |
| /* If the next token is the indicated keyword, consume it. Otherwise, |
| issue the error MSGID. Returns true if found, false otherwise. */ |
| |
| static bool |
| c_parser_require_keyword (c_parser *parser, |
| enum rid keyword, |
| const char *msgid) |
| { |
| if (c_parser_next_token_is_keyword (parser, keyword)) |
| { |
| c_parser_consume_token (parser); |
| return true; |
| } |
| else |
| { |
| c_parser_error (parser, msgid); |
| return false; |
| } |
| } |
| |
| /* Like c_parser_require, except that tokens will be skipped until the |
| desired token is found. An error message is still produced if the |
| next token is not as expected. If MSGID is NULL then a message has |
| already been produced and no message will be produced this |
| time. |
| |
| If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it |
| within any error as the location of an "opening" token matching |
| the close token TYPE (e.g. the location of the '(' when TYPE is |
| CPP_CLOSE_PAREN). */ |
| |
| void |
| c_parser_skip_until_found (c_parser *parser, |
| enum cpp_ttype type, |
| const char *msgid, |
| location_t matching_location) |
| { |
| unsigned nesting_depth = 0; |
| |
| if (c_parser_require (parser, type, msgid, matching_location)) |
| return; |
| |
| /* Skip tokens until the desired token is found. */ |
| while (true) |
| { |
| /* Peek at the next token. */ |
| c_token *token = c_parser_peek_token (parser); |
| /* If we've reached the token we want, consume it and stop. */ |
| if (token->type == type && !nesting_depth) |
| { |
| c_parser_consume_token (parser); |
| break; |
| } |
| |
| /* If we've run out of tokens, stop. */ |
| if (token->type == CPP_EOF) |
| return; |
| if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) |
| return; |
| if (token->type == CPP_OPEN_BRACE |
| || token->type == CPP_OPEN_PAREN |
| || token->type == CPP_OPEN_SQUARE) |
| ++nesting_depth; |
| else if (token->type == CPP_CLOSE_BRACE |
| || token->type == CPP_CLOSE_PAREN |
| || token->type == CPP_CLOSE_SQUARE) |
| { |
| if (nesting_depth-- == 0) |
| break; |
| } |
| /* Consume this token. */ |
| c_parser_consume_token (parser); |
| } |
| parser->error = false; |
| } |
| |
| /* Skip tokens until the end of a parameter is found, but do not |
| consume the comma, semicolon or closing delimiter. */ |
| |
| static void |
| c_parser_skip_to_end_of_parameter (c_parser *parser) |
| { |
| unsigned nesting_depth = 0; |
| |
| while (true) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON) |
| && !nesting_depth) |
| break; |
| /* If we've run out of tokens, stop. */ |
| if (token->type == CPP_EOF) |
| return; |
| if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) |
| return; |
| if (token->type == CPP_OPEN_BRACE |
| || token->type == CPP_OPEN_PAREN |
| || token->type == CPP_OPEN_SQUARE) |
| ++nesting_depth; |
| else if (token->type == CPP_CLOSE_BRACE |
| || token->type == CPP_CLOSE_PAREN |
| || token->type == CPP_CLOSE_SQUARE) |
| { |
| if (nesting_depth-- == 0) |
| break; |
| } |
| /* Consume this token. */ |
| c_parser_consume_token (parser); |
| } |
| parser->error = false; |
| } |
| |
| /* Expect to be at the end of the pragma directive and consume an |
| end of line marker. */ |
| |
| static void |
| c_parser_skip_to_pragma_eol (c_parser *parser, bool error_if_not_eol = true) |
| { |
| gcc_assert (parser->in_pragma); |
| parser->in_pragma = false; |
| |
| if (error_if_not_eol && c_parser_peek_token (parser)->type != CPP_PRAGMA_EOL) |
| c_parser_error (parser, "expected end of line"); |
| |
| cpp_ttype token_type; |
| do |
| { |
| c_token *token = c_parser_peek_token (parser); |
| token_type = token->type; |
| if (token_type == CPP_EOF) |
| break; |
| c_parser_consume_token (parser); |
| } |
| while (token_type != CPP_PRAGMA_EOL); |
| |
| parser->error = false; |
| } |
| |
| /* Skip tokens until we have consumed an entire block, or until we |
| have consumed a non-nested ';'. */ |
| |
| static void |
| c_parser_skip_to_end_of_block_or_statement (c_parser *parser) |
| { |
| unsigned nesting_depth = 0; |
| bool save_error = parser->error; |
| |
| while (true) |
| { |
| c_token *token; |
| |
| /* Peek at the next token. */ |
| token = c_parser_peek_token (parser); |
| |
| switch (token->type) |
| { |
| case CPP_EOF: |
| return; |
| |
| case CPP_PRAGMA_EOL: |
| if (parser->in_pragma) |
| return; |
| break; |
| |
| case CPP_SEMICOLON: |
| /* If the next token is a ';', we have reached the |
| end of the statement. */ |
| if (!nesting_depth) |
| { |
| /* Consume the ';'. */ |
| c_parser_consume_token (parser); |
| goto finished; |
| } |
| break; |
| |
| case CPP_CLOSE_BRACE: |
| /* If the next token is a non-nested '}', then we have |
| reached the end of the current block. */ |
| if (nesting_depth == 0 || --nesting_depth == 0) |
| { |
| c_parser_consume_token (parser); |
| goto finished; |
| } |
| break; |
| |
| case CPP_OPEN_BRACE: |
| /* If it the next token is a '{', then we are entering a new |
| block. Consume the entire block. */ |
| ++nesting_depth; |
| break; |
| |
| case CPP_PRAGMA: |
| /* If we see a pragma, consume the whole thing at once. We |
| have some safeguards against consuming pragmas willy-nilly. |
| Normally, we'd expect to be here with parser->error set, |
| which disables these safeguards. But it's possible to get |
| here for secondary error recovery, after parser->error has |
| been cleared. */ |
| c_parser_consume_pragma (parser); |
| c_parser_skip_to_pragma_eol (parser); |
| parser->error = save_error; |
| continue; |
| |
| default: |
| break; |
| } |
| |
| c_parser_consume_token (parser); |
| } |
| |
| finished: |
| parser->error = false; |
| } |
| |
| /* CPP's options (initialized by c-opts.c). */ |
| extern cpp_options *cpp_opts; |
| |
| /* Save the warning flags which are controlled by __extension__. */ |
| |
| static inline int |
| disable_extension_diagnostics (void) |
| { |
| int ret = (pedantic |
| | (warn_pointer_arith << 1) |
| | (warn_traditional << 2) |
| | (flag_iso << 3) |
| | (warn_long_long << 4) |
| | (warn_cxx_compat << 5) |
| | (warn_overlength_strings << 6) |
| /* warn_c90_c99_compat has three states: -1/0/1, so we must |
| play tricks to properly restore it. */ |
| | ((warn_c90_c99_compat == 1) << 7) |
| | ((warn_c90_c99_compat == -1) << 8) |
| /* Similarly for warn_c99_c11_compat. */ |
| | ((warn_c99_c11_compat == 1) << 9) |
| | ((warn_c99_c11_compat == -1) << 10) |
| /* Similarly for warn_c11_c2x_compat. */ |
| | ((warn_c11_c2x_compat == 1) << 11) |
| | ((warn_c11_c2x_compat == -1) << 12) |
| ); |
| cpp_opts->cpp_pedantic = pedantic = 0; |
| warn_pointer_arith = 0; |
| cpp_opts->cpp_warn_traditional = warn_traditional = 0; |
| flag_iso = 0; |
| cpp_opts->cpp_warn_long_long = warn_long_long = 0; |
| warn_cxx_compat = 0; |
| warn_overlength_strings = 0; |
| warn_c90_c99_compat = 0; |
| warn_c99_c11_compat = 0; |
| warn_c11_c2x_compat = 0; |
| return ret; |
| } |
| |
| /* Restore the warning flags which are controlled by __extension__. |
| FLAGS is the return value from disable_extension_diagnostics. */ |
| |
| static inline void |
| restore_extension_diagnostics (int flags) |
| { |
| cpp_opts->cpp_pedantic = pedantic = flags & 1; |
| warn_pointer_arith = (flags >> 1) & 1; |
| cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1; |
| flag_iso = (flags >> 3) & 1; |
| cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1; |
| warn_cxx_compat = (flags >> 5) & 1; |
| warn_overlength_strings = (flags >> 6) & 1; |
| /* See above for why is this needed. */ |
| warn_c90_c99_compat = (flags >> 7) & 1 ? 1 : ((flags >> 8) & 1 ? -1 : 0); |
| warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0); |
| warn_c11_c2x_compat = (flags >> 11) & 1 ? 1 : ((flags >> 12) & 1 ? -1 : 0); |
| } |
| |
| /* Helper data structure for parsing #pragma acc routine. */ |
| struct oacc_routine_data { |
| bool error_seen; /* Set if error has been reported. */ |
| bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ |
| tree clauses; |
| location_t loc; |
| }; |
| |
| /* Used for parsing objc foreach statements. */ |
| static tree objc_foreach_break_label, objc_foreach_continue_label; |
| |
| static bool c_parser_nth_token_starts_std_attributes (c_parser *, |
| unsigned int); |
| static tree c_parser_std_attribute_specifier_sequence (c_parser *); |
| static void c_parser_external_declaration (c_parser *); |
| static void c_parser_asm_definition (c_parser *); |
| static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, |
| bool, bool, tree *, vec<c_token>, |
| bool have_attrs = false, |
| tree attrs = NULL, |
| struct oacc_routine_data * = NULL, |
| bool * = NULL); |
| static void c_parser_static_assert_declaration_no_semi (c_parser *); |
| static void c_parser_static_assert_declaration (c_parser *); |
| static struct c_typespec c_parser_enum_specifier (c_parser *); |
| static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); |
| static tree c_parser_struct_declaration (c_parser *); |
| static struct c_typespec c_parser_typeof_specifier (c_parser *); |
| static tree c_parser_alignas_specifier (c_parser *); |
| static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, |
| c_dtr_syn, bool *); |
| static struct c_declarator *c_parser_direct_declarator_inner (c_parser *, |
| bool, |
| struct c_declarator *); |
| static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree, |
| bool); |
| static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree, |
| tree, bool); |
| static struct c_parm *c_parser_parameter_declaration (c_parser *, tree, bool); |
| static tree c_parser_simple_asm_expr (c_parser *); |
| static tree c_parser_gnu_attributes (c_parser *); |
| static struct c_expr c_parser_initializer (c_parser *); |
| static struct c_expr c_parser_braced_init (c_parser *, tree, bool, |
| struct obstack *); |
| 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 *, location_t * = NULL); |
| static location_t c_parser_compound_statement_nostart (c_parser *); |
| static void c_parser_label (c_parser *, tree); |
| static void c_parser_statement (c_parser *, bool *, location_t * = NULL); |
| static void c_parser_statement_after_labels (c_parser *, bool *, |
| vec<tree> * = NULL); |
| static tree c_parser_c99_block_statement (c_parser *, bool *, |
| location_t * = NULL); |
| static void c_parser_if_statement (c_parser *, bool *, vec<tree> *); |
| static void c_parser_switch_statement (c_parser *, bool *); |
| static void c_parser_while_statement (c_parser *, bool, unsigned short, bool *); |
| static void c_parser_do_statement (c_parser *, bool, unsigned short); |
| static void c_parser_for_statement (c_parser *, bool, unsigned short, bool *); |
| static tree c_parser_asm_statement (c_parser *); |
| static tree c_parser_asm_operands (c_parser *); |
| 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 *, |
| tree = NULL_TREE); |
| static struct c_expr c_parser_conditional_expression (c_parser *, |
| struct c_expr *, tree); |
| static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, |
| tree); |
| static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); |
| static struct c_expr c_parser_unary_expression (c_parser *); |
| static struct c_expr c_parser_sizeof_expression (c_parser *); |
| static struct c_expr c_parser_alignof_expression (c_parser *); |
| static struct c_expr c_parser_postfix_expression (c_parser *); |
| static struct c_expr c_parser_postfix_expression_after_paren_type (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 tree c_parser_transaction (c_parser *, enum rid); |
| static struct c_expr c_parser_transaction_expression (c_parser *, enum rid); |
| static tree c_parser_transaction_cancel (c_parser *); |
| static struct c_expr c_parser_expression (c_parser *); |
| static struct c_expr c_parser_expression_conv (c_parser *); |
| static vec<tree, va_gc> *c_parser_expr_list (c_parser *, bool, bool, |
| vec<tree, va_gc> **, location_t *, |
| tree *, vec<location_t> *, |
| unsigned int * = NULL); |
| static struct c_expr c_parser_has_attribute_expression (c_parser *); |
| |
| static void c_parser_oacc_declare (c_parser *); |
| static void c_parser_oacc_enter_exit_data (c_parser *, bool); |
| static void c_parser_oacc_update (c_parser *); |
| static void c_parser_omp_construct (c_parser *, bool *); |
| static void c_parser_omp_threadprivate (c_parser *); |
| static void c_parser_omp_barrier (c_parser *); |
| static void c_parser_omp_depobj (c_parser *); |
| static void c_parser_omp_flush (c_parser *); |
| static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, |
| tree, tree *, bool *); |
| static void c_parser_omp_taskwait (c_parser *); |
| static void c_parser_omp_taskyield (c_parser *); |
| static void c_parser_omp_cancel (c_parser *); |
| |
| enum pragma_context { pragma_external, pragma_struct, pragma_param, |
| pragma_stmt, pragma_compound }; |
| static bool c_parser_pragma (c_parser *, enum pragma_context, bool *); |
| static void c_parser_omp_cancellation_point (c_parser *, enum pragma_context); |
| static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); |
| static void c_parser_omp_end_declare_target (c_parser *); |
| static void c_parser_omp_declare (c_parser *, enum pragma_context); |
| static void c_parser_omp_requires (c_parser *); |
| static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); |
| static void c_parser_oacc_routine (c_parser *, enum pragma_context); |
| |
| /* These Objective-C parser functions are only ever called when |
| compiling Objective-C. */ |
| 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 *, 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 *, bool, tree *, tree *); |
| static tree c_parser_objc_type_name (c_parser *); |
| static tree c_parser_objc_protocol_refs (c_parser *); |
| static void c_parser_objc_try_catch_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 *); |
| static location_t c_parser_parse_rtl_body (c_parser *, char *); |
| |
| /* Parse a translation unit (C90 6.7, C99 6.9, C11 6.9). |
| |
| translation-unit: |
| external-declarations |
| |
| external-declarations: |
| external-declaration |
| external-declarations external-declaration |
| |
| GNU extensions: |
| |
| translation-unit: |
| empty |
| */ |
| |
| static void |
| c_parser_translation_unit (c_parser *parser) |
| { |
| if (c_parser_next_token_is (parser, CPP_EOF)) |
| { |
| pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
| "ISO C forbids an empty translation unit"); |
| } |
| else |
| { |
| void *obstack_position = obstack_alloc (&parser_obstack, 0); |
| mark_valid_location_for_stdc_pragma (false); |
| do |
| { |
| ggc_collect (); |
| c_parser_external_declaration (parser); |
| obstack_free (&parser_obstack, obstack_position); |
| } |
| while (c_parser_next_token_is_not (parser, CPP_EOF)); |
| } |
| |
| unsigned int i; |
| tree decl; |
| FOR_EACH_VEC_ELT (incomplete_record_decls, i, decl) |
| if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node) |
| error ("storage size of %q+D isn%'t known", decl); |
| |
| if (current_omp_declare_target_attribute) |
| { |
| if (!errorcount) |
| error ("%<#pragma omp declare target%> without corresponding " |
| "%<#pragma omp end declare target%>"); |
| current_omp_declare_target_attribute = 0; |
| } |
| } |
| |
| /* Parse an external declaration (C90 6.7, C99 6.9, C11 6.9). |
| |
| external-declaration: |
| function-definition |
| declaration |
| |
| GNU extensions: |
| |
| external-declaration: |
| asm-definition |
| ; |
| __extension__ external-declaration |
| |
| Objective-C: |
| |
| external-declaration: |
| objc-class-definition |
| objc-class-declaration |
| objc-alias-declaration |
| objc-protocol-definition |
| objc-method-definition |
| @end |
| */ |
| |
| static void |
| c_parser_external_declaration (c_parser *parser) |
| { |
| int ext; |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_KEYWORD: |
| switch (c_parser_peek_token (parser)->keyword) |
| { |
| case RID_EXTENSION: |
| ext = disable_extension_diagnostics (); |
| c_parser_consume_token (parser); |
| c_parser_external_declaration (parser); |
| restore_extension_diagnostics (ext); |
| break; |
| case RID_ASM: |
| c_parser_asm_definition (parser); |
| break; |
| case RID_AT_INTERFACE: |
| case RID_AT_IMPLEMENTATION: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_class_definition (parser, NULL_TREE); |
| break; |
| case RID_AT_CLASS: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_class_declaration (parser); |
| break; |
| case RID_AT_ALIAS: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_alias_declaration (parser); |
| break; |
| case RID_AT_PROTOCOL: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_protocol_definition (parser, NULL_TREE); |
| break; |
| case RID_AT_PROPERTY: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_at_property_declaration (parser); |
| break; |
| case RID_AT_SYNTHESIZE: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_at_synthesize_declaration (parser); |
| break; |
| case RID_AT_DYNAMIC: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_at_dynamic_declaration (parser); |
| break; |
| case RID_AT_END: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_consume_token (parser); |
| objc_finish_implementation (); |
| break; |
| default: |
| goto decl_or_fndef; |
| } |
| break; |
| case CPP_SEMICOLON: |
| pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
| "ISO C does not allow extra %<;%> outside of a function"); |
| c_parser_consume_token (parser); |
| break; |
| case CPP_PRAGMA: |
| mark_valid_location_for_stdc_pragma (true); |
| c_parser_pragma (parser, pragma_external, NULL); |
| mark_valid_location_for_stdc_pragma (false); |
| break; |
| case CPP_PLUS: |
| case CPP_MINUS: |
| if (c_dialect_objc ()) |
| { |
| c_parser_objc_method_definition (parser); |
| break; |
| } |
| /* Else fall through, and yield a syntax error trying to parse |
| as a declaration or function definition. */ |
| /* FALLTHRU */ |
| default: |
| decl_or_fndef: |
| /* 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, vNULL); |
| break; |
| } |
| } |
| |
| static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>); |
| static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool); |
| |
| /* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */ |
| |
| static void |
| add_debug_begin_stmt (location_t loc) |
| { |
| /* Don't add DEBUG_BEGIN_STMTs outside of functions, see PR84721. */ |
| if (!MAY_HAVE_DEBUG_MARKER_STMTS || !building_stmt_list_p ()) |
| return; |
| |
| tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node); |
| SET_EXPR_LOCATION (stmt, loc); |
| add_stmt (stmt); |
| } |
| |
| /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 |
| 6.7, 6.9.1, C11 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 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 (GNU or standard); otherwise they may not. |
| OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed |
| declaration when parsing an Objective-C foreach statement. |
| FALLTHRU_ATTR_P is used to signal whether this function parsed |
| "__attribute__((fallthrough));". ATTRS are any standard attributes |
| parsed in the caller (in contexts where such attributes had to be |
| parsed to determine whether what follows is a declaration or a |
| statement); HAVE_ATTRS says whether there were any such attributes |
| (even empty). |
| |
| declaration: |
| declaration-specifiers init-declarator-list[opt] ; |
| static_assert-declaration |
| |
| function-definition: |
| declaration-specifiers[opt] declarator declaration-list[opt] |
| compound-statement |
| |
| declaration-list: |
| declaration |
| declaration-list declaration |
| |
| init-declarator-list: |
| init-declarator |
| init-declarator-list , init-declarator |
| |
| init-declarator: |
| declarator simple-asm-expr[opt] gnu-attributes[opt] |
| declarator simple-asm-expr[opt] gnu-attributes[opt] = initializer |
| |
| GNU extensions: |
| |
| nested-function-definition: |
| declaration-specifiers declarator declaration-list[opt] |
| compound-statement |
| |
| attribute ; |
| |
| Objective-C: |
| gnu-attributes objc-class-definition |
| gnu-attributes objc-category-definition |
| gnu-attributes objc-protocol-definition |
| |
| The simple-asm-expr and gnu-attributes are GNU extensions. |
| |
| This function does not handle __extension__; that is handled in its |
| callers. ??? Following the old parser, __extension__ may start |
| external declarations, declarations in functions and declarations |
| at the start of "for" loops, but not old-style parameter |
| declarations. |
| |
| C99 requires declaration specifiers in a function definition; the |
| absence is diagnosed through the diagnosis of implicit int. In GNU |
| 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 |
| |
| GIMPLE: |
| |
| gimple-function-definition: |
| declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator |
| declaration-list[opt] compound-statement |
| |
| rtl-function-definition: |
| declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator |
| declaration-list[opt] compound-statement */ |
| |
| static void |
| c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, |
| bool static_assert_ok, bool empty_ok, |
| bool nested, bool start_attr_ok, |
| tree *objc_foreach_object_declaration, |
| vec<c_token> omp_declare_simd_clauses, |
| bool have_attrs, tree attrs, |
| struct oacc_routine_data *oacc_routine_data, |
| bool *fallthru_attr_p) |
| { |
| struct c_declspecs *specs; |
| tree prefix_attrs; |
| tree all_prefix_attrs; |
| bool diagnosed_no_specs = false; |
| location_t here = c_parser_peek_token (parser)->location; |
| |
| add_debug_begin_stmt (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 (); |
| |
| /* Handle any standard attributes parsed in the caller. */ |
| if (have_attrs) |
| { |
| declspecs_add_attrs (here, specs, attrs); |
| specs->non_std_attrs_seen_p = false; |
| } |
| |
| /* 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))) |
| { |
| tree name = c_parser_peek_token (parser)->value; |
| |
| /* Issue a warning about NAME being an unknown type name, perhaps |
| with some kind of hint. |
| If the user forgot a "struct" etc, suggest inserting |
| it. Otherwise, attempt to look for misspellings. */ |
| gcc_rich_location richloc (here); |
| if (tag_exists_p (RECORD_TYPE, name)) |
| { |
| /* This is not C++ with its implicit typedef. */ |
| richloc.add_fixit_insert_before ("struct "); |
| error_at (&richloc, |
| "unknown type name %qE;" |
| " use %<struct%> keyword to refer to the type", |
| name); |
| } |
| else if (tag_exists_p (UNION_TYPE, name)) |
| { |
| richloc.add_fixit_insert_before ("union "); |
| error_at (&richloc, |
| "unknown type name %qE;" |
| " use %<union%> keyword to refer to the type", |
| name); |
| } |
| else if (tag_exists_p (ENUMERAL_TYPE, name)) |
| { |
| richloc.add_fixit_insert_before ("enum "); |
| error_at (&richloc, |
| "unknown type name %qE;" |
| " use %<enum%> keyword to refer to the type", |
| name); |
| } |
| else |
| { |
| auto_diagnostic_group d; |
| name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME, |
| here); |
| if (const char *suggestion = hint.suggestion ()) |
| { |
| richloc.add_fixit_replace (suggestion); |
| error_at (&richloc, |
| "unknown type name %qE; did you mean %qs?", |
| name, suggestion); |
| } |
| else |
| error_at (here, "unknown type name %qE", name); |
| } |
| |
| /* 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; |
| } |
| |
| /* When there are standard attributes at the start of the |
| declaration (to apply to the entity being declared), an |
| init-declarator-list or function definition must be present. */ |
| if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
| have_attrs = true; |
| |
| c_parser_declspecs (parser, specs, true, true, start_attr_ok, |
| true, true, start_attr_ok, true, cla_nonabstract_decl); |
| if (parser->error) |
| { |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| if (nested && !specs->declspecs_seen_p) |
| { |
| c_parser_error (parser, "expected declaration specifiers"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| |
| finish_declspecs (specs); |
| bool auto_type_p = specs->typespec_word == cts_auto_type; |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| if (auto_type_p) |
| error_at (here, "%<__auto_type%> in empty declaration"); |
| else if (specs->typespec_kind == ctsk_none |
| && attribute_fallthrough_p (specs->attrs)) |
| { |
| if (fallthru_attr_p != NULL) |
| *fallthru_attr_p = true; |
| if (nested) |
| { |
| tree fn = build_call_expr_internal_loc (here, IFN_FALLTHROUGH, |
| void_type_node, 0); |
| add_stmt (fn); |
| } |
| else |
| pedwarn (here, OPT_Wattributes, |
| "%<fallthrough%> attribute at top level"); |
| } |
| else if (empty_ok && !(have_attrs |
| && specs->non_std_attrs_seen_p)) |
| shadow_tag (specs); |
| else |
| { |
| shadow_tag_warned (specs, 1); |
| pedwarn (here, 0, "empty declaration"); |
| } |
| c_parser_consume_token (parser); |
| if (oacc_routine_data) |
| c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); |
| 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 () && !auto_type_p) |
| { |
| /* 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; |
| } |
| } |
| else if (attribute_fallthrough_p (specs->attrs)) |
| warning_at (here, OPT_Wattributes, |
| "%<fallthrough%> attribute not followed by %<;%>"); |
| |
| pending_xref_error (); |
| prefix_attrs = specs->attrs; |
| all_prefix_attrs = prefix_attrs; |
| specs->attrs = NULL_TREE; |
| while (true) |
| { |
| struct c_declarator *declarator; |
| bool dummy = false; |
| timevar_id_t tv; |
| tree fnbody = NULL_TREE; |
| /* Declaring either one or more declarators (in which case we |
| should diagnose if there were no declaration specifiers) or a |
| function definition (in which case the diagnostic for |
| implicit int suffices). */ |
| declarator = c_parser_declarator (parser, |
| specs->typespec_kind != ctsk_none, |
| C_DTR_NORMAL, &dummy); |
| if (declarator == NULL) |
| { |
| if (omp_declare_simd_clauses.exists ()) |
| c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE, |
| omp_declare_simd_clauses); |
| if (oacc_routine_data) |
| c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| if (auto_type_p && declarator->kind != cdk_id) |
| { |
| error_at (here, |
| "%<__auto_type%> requires a plain identifier" |
| " as declarator"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| if (c_parser_next_token_is (parser, CPP_EQ) |
| || 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_IN)) |
| { |
| tree asm_name = NULL_TREE; |
| tree postfix_attrs = NULL_TREE; |
| if (!diagnosed_no_specs && !specs->declspecs_seen_p) |
| { |
| diagnosed_no_specs = true; |
| pedwarn (here, 0, "data definition has no type or storage class"); |
| } |
| /* Having seen a data definition, there cannot now be a |
| function definition. */ |
| fndef_ok = false; |
| if (c_parser_next_token_is_keyword (parser, RID_ASM)) |
| asm_name = c_parser_simple_asm_expr (parser); |
| if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) |
| { |
| postfix_attrs = c_parser_gnu_attributes (parser); |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| /* This means there is an attribute specifier after |
| the declarator in a function definition. Provide |
| some more information for the user. */ |
| error_at (here, "attributes should be specified before the " |
| "declarator in a function definition"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| } |
| if (c_parser_next_token_is (parser, CPP_EQ)) |
| { |
| tree d; |
| struct c_expr init; |
| location_t init_loc; |
| c_parser_consume_token (parser); |
| if (auto_type_p) |
| { |
| init_loc = c_parser_peek_token (parser)->location; |
| rich_location richloc (line_table, init_loc); |
| start_init (NULL_TREE, asm_name, global_bindings_p (), &richloc); |
| /* A parameter is initialized, which is invalid. Don't |
| attempt to instrument the initializer. */ |
| int flag_sanitize_save = flag_sanitize; |
| if (nested && !empty_ok) |
| flag_sanitize = 0; |
| init = c_parser_expr_no_commas (parser, NULL); |
| flag_sanitize = flag_sanitize_save; |
| if (TREE_CODE (init.value) == COMPONENT_REF |
| && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1))) |
| error_at (here, |
| "%<__auto_type%> used with a bit-field" |
| " initializer"); |
| init = convert_lvalue_to_rvalue (init_loc, init, true, true); |
| tree init_type = TREE_TYPE (init.value); |
| bool vm_type = variably_modified_type_p (init_type, |
| NULL_TREE); |
| if (vm_type) |
| init.value = save_expr (init.value); |
| finish_init (); |
| specs->typespec_kind = ctsk_typeof; |
| specs->locations[cdw_typedef] = init_loc; |
| specs->typedef_p = true; |
| specs->type = init_type; |
| if (vm_type) |
| { |
| bool maybe_const = true; |
| tree type_expr = c_fully_fold (init.value, false, |
| &maybe_const); |
| specs->expr_const_operands &= maybe_const; |
| if (specs->expr) |
| specs->expr = build2 (COMPOUND_EXPR, |
| TREE_TYPE (type_expr), |
| specs->expr, type_expr); |
| else |
| specs->expr = type_expr; |
| } |
| d = start_decl (declarator, specs, true, |
| chainon (postfix_attrs, all_prefix_attrs)); |
| if (!d) |
| d = error_mark_node; |
| if (omp_declare_simd_clauses.exists ()) |
| c_finish_omp_declare_simd (parser, d, NULL_TREE, |
| omp_declare_simd_clauses); |
| } |
| else |
| { |
| /* The declaration of the variable is in effect while |
| its initializer is parsed. */ |
| d = start_decl (declarator, specs, true, |
| chainon (postfix_attrs, all_prefix_attrs)); |
| if (!d) |
| d = error_mark_node; |
| if (omp_declare_simd_clauses.exists ()) |
| c_finish_omp_declare_simd (parser, d, NULL_TREE, |
| omp_declare_simd_clauses); |
| init_loc = c_parser_peek_token (parser)->location; |
| rich_location richloc (line_table, init_loc); |
| start_init (d, asm_name, global_bindings_p (), &richloc); |
| /* A parameter is initialized, which is invalid. Don't |
| attempt to instrument the initializer. */ |
| int flag_sanitize_save = flag_sanitize; |
| if (TREE_CODE (d) == PARM_DECL) |
| flag_sanitize = 0; |
| init = c_parser_initializer (parser); |
| flag_sanitize = flag_sanitize_save; |
| finish_init (); |
| } |
| if (oacc_routine_data) |
| c_finish_oacc_routine (oacc_routine_data, d, false); |
| if (d != error_mark_node) |
| { |
| maybe_warn_string_init (init_loc, TREE_TYPE (d), init); |
| finish_decl (d, init_loc, init.value, |
| init.original_type, asm_name); |
| } |
| } |
| else |
| { |
| if (auto_type_p) |
| { |
| error_at (here, |
| "%<__auto_type%> requires an initialized " |
| "data declaration"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| |
| location_t lastloc = UNKNOWN_LOCATION; |
| tree attrs = chainon (postfix_attrs, all_prefix_attrs); |
| tree d = start_decl (declarator, specs, false, attrs, &lastloc); |
| if (d && TREE_CODE (d) == FUNCTION_DECL) |
| { |
| /* Find the innermost declarator that is neither cdk_id |
| nor cdk_attrs. */ |
| const struct c_declarator *decl = declarator; |
| const struct c_declarator *last_non_id_attrs = NULL; |
| |
| while (decl) |
| switch (decl->kind) |
| { |
| case cdk_array: |
| case cdk_function: |
| case cdk_pointer: |
| last_non_id_attrs = decl; |
| decl = decl->declarator; |
| break; |
| |
| case cdk_attrs: |
| decl = decl->declarator; |
| break; |
| |
| case cdk_id: |
| decl = 0; |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* If it exists and is cdk_function declaration whose |
| arguments have not been set yet, use its arguments. */ |
| if (last_non_id_attrs |
| && last_non_id_attrs->kind == cdk_function) |
| { |
| tree parms = last_non_id_attrs->u.arg_info->parms; |
| if (DECL_ARGUMENTS (d) == NULL_TREE |
| && DECL_INITIAL (d) == NULL_TREE) |
| DECL_ARGUMENTS (d) = parms; |
| |
| warn_parm_array_mismatch (lastloc, d, parms); |
| } |
| } |
| if (omp_declare_simd_clauses.exists ()) |
| { |
| tree parms = NULL_TREE; |
| if (d && TREE_CODE (d) == FUNCTION_DECL) |
| { |
| struct c_declarator *ce = declarator; |
| while (ce != NULL) |
| if (ce->kind == cdk_function) |
| { |
| parms = ce->u.arg_info->parms; |
| break; |
| } |
| else |
| ce = ce->declarator; |
| } |
| if (parms) |
| temp_store_parm_decls (d, parms); |
| c_finish_omp_declare_simd (parser, d, parms, |
| omp_declare_simd_clauses); |
| if (parms) |
| temp_pop_parm_decls (); |
| } |
| if (oacc_routine_data) |
| c_finish_oacc_routine (oacc_routine_data, d, false); |
| if (d) |
| 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)) |
| { |
| if (auto_type_p) |
| { |
| error_at (here, |
| "%<__auto_type%> may only be used with" |
| " a single declarator"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) |
| all_prefix_attrs = chainon (c_parser_gnu_attributes (parser), |
| prefix_attrs); |
| else |
| all_prefix_attrs = prefix_attrs; |
| continue; |
| } |
| else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| c_parser_consume_token (parser); |
| return; |
| } |
| else if (c_parser_next_token_is_keyword (parser, RID_IN)) |
| { |
| /* This can only happen in Objective-C: we found the |
| 'in' that terminates the declaration inside an |
| Objective-C foreach statement. Do not consume the |
| token, so that the caller can use it to determine |
| that this indeed is a foreach context. */ |
| return; |
| } |
| else |
| { |
| c_parser_error (parser, "expected %<,%> or %<;%>"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| } |
| else if (auto_type_p) |
| { |
| error_at (here, |
| "%<__auto_type%> requires an initialized data declaration"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| else if (!fndef_ok) |
| { |
| c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, " |
| "%<asm%> or %<__attribute__%>"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| /* Function definition (nested or otherwise). */ |
| if (nested) |
| { |
| pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions"); |
| c_push_function_context (); |
| } |
| if (!start_function (specs, declarator, all_prefix_attrs)) |
| { |
| /* At this point we've consumed: |
| declaration-specifiers declarator |
| and the next token isn't CPP_EQ, CPP_COMMA, CPP_SEMICOLON, |
| RID_ASM, RID_ATTRIBUTE, or RID_IN, |
| but the |
| declaration-specifiers declarator |
| aren't grokkable as a function definition, so we have |
| an error. */ |
| gcc_assert (!c_parser_next_token_is (parser, CPP_SEMICOLON)); |
| if (c_parser_next_token_starts_declspecs (parser)) |
| { |
| /* If we have |
| declaration-specifiers declarator decl-specs |
| then assume we have a missing semicolon, which would |
| give us: |
| declaration-specifiers declarator decl-specs |
| ^ |
| ; |
| <~~~~~~~~~ declaration ~~~~~~~~~~> |
| Use c_parser_require to get an error with a fix-it hint. */ |
| c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"); |
| parser->error = false; |
| } |
| else |
| { |
| /* This can appear in many cases looking nothing like a |
| function definition, so we don't give a more specific |
| error suggesting there was one. */ |
| c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> " |
| "or %<__attribute__%>"); |
| } |
| if (nested) |
| c_pop_function_context (); |
| break; |
| } |
| |
| if (DECL_DECLARED_INLINE_P (current_function_decl)) |
| tv = TV_PARSE_INLINE; |
| else |
| tv = TV_PARSE_FUNC; |
| auto_timevar at (g_timer, tv); |
| |
| /* Parse old-style parameter declarations. ??? Attributes are |
| not allowed to start declaration specifiers here because of a |
| syntax conflict between a function declaration with attribute |
| suffix and a function definition with an attribute prefix on |
| first old-style parameter declaration. Following the old |
| parser, they are not accepted on subsequent old-style |
| parameter declarations either. However, there is no |
| ambiguity after the first declaration, nor indeed on the |
| first as long as we don't allow postfix attributes after a |
| declarator with a nonempty identifier list in a definition; |
| and postfix attributes have never been accepted here in |
| 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, false, |
| true, false, NULL, vNULL); |
| store_parm_decls (); |
| if (omp_declare_simd_clauses.exists ()) |
| c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, |
| omp_declare_simd_clauses); |
| if (oacc_routine_data) |
| c_finish_oacc_routine (oacc_routine_data, current_function_decl, true); |
| location_t startloc = c_parser_peek_token (parser)->location; |
| DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus |
| = startloc; |
| location_t endloc = startloc; |
| |
| /* If the definition was marked with __RTL, use the RTL parser now, |
| consuming the function body. */ |
| if (specs->declspec_il == cdil_rtl) |
| { |
| endloc = c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass); |
| |
| /* Normally, store_parm_decls sets next_is_function_body, |
| anticipating a function body. We need a push_scope/pop_scope |
| pair to flush out this state, or subsequent function parsing |
| will go wrong. */ |
| push_scope (); |
| pop_scope (); |
| |
| finish_function (endloc); |
| return; |
| } |
| /* If the definition was marked with __GIMPLE then parse the |
| function body as GIMPLE. */ |
| else if (specs->declspec_il != cdil_none) |
| { |
| bool saved = in_late_binary_op; |
| in_late_binary_op = true; |
| c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass, |
| specs->declspec_il, |
| specs->entry_bb_count); |
| in_late_binary_op = saved; |
| } |
| else |
| fnbody = c_parser_compound_statement (parser, &endloc); |
| tree fndecl = current_function_decl; |
| 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 (endloc); |
| c_pop_function_context (); |
| add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); |
| } |
| else |
| { |
| if (fnbody) |
| add_stmt (fnbody); |
| finish_function (endloc); |
| } |
| /* Get rid of the empty stmt list for GIMPLE/RTL. */ |
| if (specs->declspec_il != cdil_none) |
| DECL_SAVED_TREE (fndecl) = NULL_TREE; |
| |
| break; |
| } |
| } |
| |
| /* Parse an asm-definition (asm() outside a function body). This is a |
| GNU extension. |
| |
| asm-definition: |
| simple-asm-expr ; |
| */ |
| |
| static void |
| c_parser_asm_definition (c_parser *parser) |
| { |
| tree asm_str = c_parser_simple_asm_expr (parser); |
| if (asm_str) |
| symtab->finalize_toplevel_asm (asm_str); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| |
| /* Parse a static assertion (C11 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 (C11 6.7.10), without the trailing |
| semicolon. |
| |
| static_assert-declaration-no-semi: |
| _Static_assert ( constant-expression , string-literal ) |
| |
| C2X: |
| static_assert-declaration-no-semi: |
| _Static_assert ( constant-expression ) |
| */ |
| |
| static void |
| c_parser_static_assert_declaration_no_semi (c_parser *parser) |
| { |
| location_t assert_loc, value_loc; |
| tree value; |
| tree string = NULL_TREE; |
| |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)); |
| assert_loc = c_parser_peek_token (parser)->location; |
| if (flag_isoc99) |
| pedwarn_c99 (assert_loc, OPT_Wpedantic, |
| "ISO C99 does not support %<_Static_assert%>"); |
| else |
| pedwarn_c99 (assert_loc, OPT_Wpedantic, |
| "ISO C90 does not support %<_Static_assert%>"); |
| c_parser_consume_token (parser); |
| matching_parens parens; |
| if (!parens.require_open (parser)) |
| return; |
| location_t value_tok_loc = c_parser_peek_token (parser)->location; |
| value = c_parser_expr_no_commas (parser, NULL).value; |
| value_loc = EXPR_LOC_OR_LOC (value, value_tok_loc); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| { |
| c_parser_consume_token (parser); |
| 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_string_literal (parser, false, true).value; |
| break; |
| default: |
| c_parser_error (parser, "expected string literal"); |
| return; |
| } |
| } |
| else if (flag_isoc11) |
| /* If pedantic for pre-C11, the use of _Static_assert itself will |
| have been diagnosed, so do not also diagnose the use of this |
| new C2X feature of _Static_assert. */ |
| pedwarn_c11 (assert_loc, OPT_Wpedantic, |
| "ISO C11 does not support omitting the string in " |
| "%<_Static_assert%>"); |
| parens.require_close (parser); |
| |
| 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); |
| /* Strip no-op conversions. */ |
| STRIP_TYPE_NOPS (value); |
| if (TREE_CODE (value) == INTEGER_CST) |
| pedwarn (value_loc, OPT_Wpedantic, "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)) |
| { |
| if (string) |
| error_at (assert_loc, "static assertion failed: %E", string); |
| else |
| error_at (assert_loc, "static assertion failed"); |
| } |
| } |
| |
| /* Parse some declaration specifiers (possibly none) (C90 6.5, C99 |
| 6.7, C11 6.7), adding them to SPECS (which may already include some). |
| Storage class specifiers are accepted iff SCSPEC_OK; type |
| specifiers are accepted iff TYPESPEC_OK; alignment specifiers are |
| accepted iff ALIGNSPEC_OK; gnu-attributes are accepted at the start |
| iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK. In |
| addition to the syntax shown, standard attributes are accepted at |
| the start iff START_STD_ATTR_OK and at the end iff END_STD_ATTR_OK; |
| unlike gnu-attributes, they are not accepted in the middle of the |
| list. (This combines various different syntax productions in the C |
| standard, and in some cases gnu-attributes and standard attributes |
| at the start may already have been parsed before this function is |
| called.) |
| |
| declaration-specifiers: |
| storage-class-specifier declaration-specifiers[opt] |
| type-specifier declaration-specifiers[opt] |
| type-qualifier declaration-specifiers[opt] |
| function-specifier declaration-specifiers[opt] |
| alignment-specifier declaration-specifiers[opt] |
| |
| Function specifiers (inline) are from C99, and are currently |
| handled as storage class specifiers, as is __thread. Alignment |
| specifiers are from C11. |
| |
| C90 6.5.1, C99 6.7.1, C11 6.7.1: |
| storage-class-specifier: |
| typedef |
| extern |
| static |
| auto |
| register |
| _Thread_local |
| |
| (_Thread_local is new in C11.) |
| |
| C99 6.7.4, C11 6.7.4: |
| function-specifier: |
| inline |
| _Noreturn |
| |
| (_Noreturn is new in C11.) |
| |
| C90 6.5.2, C99 6.7.2, C11 6.7.2: |
| type-specifier: |
| void |
| char |
| short |
| int |
| long |
| float |
| double |
| signed |
| unsigned |
| _Bool |
| _Complex |
| [_Imaginary removed in C99 TC2] |
| struct-or-union-specifier |
| enum-specifier |
| typedef-name |
| atomic-type-specifier |
| |
| (_Bool and _Complex are new in C99.) |
| (atomic-type-specifier is new in C11.) |
| |
| C90 6.5.3, C99 6.7.3, C11 6.7.3: |
| |
| type-qualifier: |
| const |
| restrict |
| volatile |
| address-space-qualifier |
| _Atomic |
| |
| (restrict is new in C99.) |
| (_Atomic is new in C11.) |
| |
| GNU extensions: |
| |
| declaration-specifiers: |
| gnu-attributes declaration-specifiers[opt] |
| |
| type-qualifier: |
| address-space |
| |
| address-space: |
| identifier recognized by the target |
| |
| storage-class-specifier: |
| __thread |
| |
| type-specifier: |
| typeof-specifier |
| __auto_type |
| __intN |
| _Decimal32 |
| _Decimal64 |
| _Decimal128 |
| _Fract |
| _Accum |
| _Sat |
| |
| (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037: |
| http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf) |
| |
| atomic-type-specifier |
| _Atomic ( type-name ) |
| |
| Objective-C: |
| |
| type-specifier: |
| class-name objc-protocol-refs[opt] |
| typedef-name objc-protocol-refs |
| objc-protocol-refs |
| */ |
| |
| void |
| c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, |
| bool scspec_ok, bool typespec_ok, bool start_attr_ok, |
| bool alignspec_ok, bool auto_type_ok, |
| bool start_std_attr_ok, bool end_std_attr_ok, |
| enum c_lookahead_kind la) |
| { |
| bool attrs_ok = start_attr_ok; |
| bool seen_type = specs->typespec_kind != ctsk_none; |
| |
| if (!typespec_ok) |
| gcc_assert (la == cla_prefer_id); |
| |
| if (start_std_attr_ok |
| && c_parser_nth_token_starts_std_attributes (parser, 1)) |
| { |
| gcc_assert (!specs->non_std_attrs_seen_p); |
| location_t loc = c_parser_peek_token (parser)->location; |
| tree attrs = c_parser_std_attribute_specifier_sequence (parser); |
| declspecs_add_attrs (loc, specs, attrs); |
| specs->non_std_attrs_seen_p = false; |
| } |
| |
| while (c_parser_next_token_is (parser, CPP_NAME) |
| || c_parser_next_token_is (parser, CPP_KEYWORD) |
| || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS))) |
| { |
| struct c_typespec t; |
| tree attrs; |
| tree align; |
| location_t loc = c_parser_peek_token (parser)->location; |
| |
| /* If we cannot accept a type, exit if the next token must start |
| one. Also, if we already have seen a tagged definition, |
| a typename would be an error anyway and likely the user |
| has simply forgotten a semicolon, so we exit. */ |
| if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef) |
| && c_parser_next_tokens_start_typename (parser, la) |
| && !c_parser_next_token_is_qualifier (parser) |
| && !c_parser_next_token_is_keyword (parser, RID_ALIGNAS)) |
| break; |
| |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| c_token *name_token = c_parser_peek_token (parser); |
| tree value = name_token->value; |
| c_id_kind kind = name_token->id_kind; |
| |
| if (kind == C_ID_ADDRSPACE) |
| { |
| addr_space_t as |
| = name_token->keyword - RID_FIRST_ADDR_SPACE; |
| declspecs_add_addrspace (name_token->location, 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_ID) |
| { |
| error_at (loc, "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); |
| } |
| else |
| { |
| tree proto = NULL_TREE; |
| gcc_assert (c_dialect_objc ()); |
| t.kind = ctsk_objc; |
| 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 (name_token->location, specs, t); |
| continue; |
| } |
| if (c_parser_next_token_is (parser, CPP_LESS)) |
| { |
| /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" - |
| nisse@lysator.liu.se. */ |
| tree proto; |
| gcc_assert (c_dialect_objc ()); |
| if (!typespec_ok || seen_type) |
| break; |
| proto = c_parser_objc_protocol_refs (parser); |
| t.kind = ctsk_objc; |
| t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); |
| t.expr = NULL_TREE; |
| t.expr_const_operands = true; |
| declspecs_add_type (loc, specs, t); |
| continue; |
| } |
| gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD)); |
| switch (c_parser_peek_token (parser)->keyword) |
| { |
| case RID_STATIC: |
| case RID_EXTERN: |
| case RID_REGISTER: |
| case RID_TYPEDEF: |
| case RID_INLINE: |
| case RID_NORETURN: |
| case RID_AUTO: |
| case RID_THREAD: |
| if (!scspec_ok) |
| goto out; |
| attrs_ok = true; |
| /* TODO: Distinguish between function specifiers (inline, noreturn) |
| and storage class specifiers, either here or in |
| declspecs_add_scspec. */ |
| declspecs_add_scspec (loc, specs, |
| c_parser_peek_token (parser)->value); |
| c_parser_consume_token (parser); |
| break; |
| case RID_AUTO_TYPE: |
| if (!auto_type_ok) |
| goto out; |
| /* Fall through. */ |
| case RID_UNSIGNED: |
| case RID_LONG: |
| case RID_SHORT: |
| case RID_SIGNED: |
| case RID_COMPLEX: |
| case RID_INT: |
| case RID_CHAR: |
| case RID_FLOAT: |
| case RID_DOUBLE: |
| case RID_VOID: |
| case RID_DFLOAT32: |
| case RID_DFLOAT64: |
| case RID_DFLOAT128: |
| CASE_RID_FLOATN_NX: |
| case RID_BOOL: |
| case RID_FRACT: |
| case RID_ACCUM: |
| case RID_SAT: |
| case RID_INT_N_0: |
| case RID_INT_N_1: |
| case RID_INT_N_2: |
| case RID_INT_N_3: |
| if (!typespec_ok) |
| goto out; |
| attrs_ok = true; |
| seen_type = true; |
| if (c_dialect_objc ()) |
| parser->objc_need_raw_identifier = true; |
| t.kind = ctsk_resword; |
| t.spec = c_parser_peek_token (parser)->value; |
| t.expr = NULL_TREE; |
| t.expr_const_operands = true; |
| declspecs_add_type (loc, specs, t); |
| c_parser_consume_token (parser); |
| break; |
| case RID_ENUM: |
| if (!typespec_ok) |
| goto out; |
| attrs_ok = true; |
| seen_type = true; |
| t = c_parser_enum_specifier (parser); |
| invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); |
| declspecs_add_type (loc, specs, t); |
| break; |
| case RID_STRUCT: |
| case RID_UNION: |
| if (!typespec_ok) |
| goto out; |
| attrs_ok = true; |
| seen_type = true; |
| t = c_parser_struct_or_union_specifier (parser); |
| invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); |
| declspecs_add_type (loc, specs, t); |
| break; |
| case RID_TYPEOF: |
| /* ??? The old parser rejected typeof after other type |
| specifiers, but is a syntax error the best way of |
| handling this? */ |
| if (!typespec_ok || seen_type) |
| goto out; |
| attrs_ok = true; |
| seen_type = true; |
| t = c_parser_typeof_specifier (parser); |
| declspecs_add_type (loc, specs, t); |
| break; |
| case RID_ATOMIC: |
| /* C parser handling of Objective-C constructs needs |
| checking for correct lvalue-to-rvalue conversions, and |
| the code in build_modify_expr handling various |
| Objective-C cases, and that in build_unary_op handling |
| Objective-C cases for increment / decrement, also needs |
| updating; uses of TYPE_MAIN_VARIANT in objc_compare_types |
| and objc_types_are_equivalent may also need updates. */ |
| if (c_dialect_objc ()) |
| sorry ("%<_Atomic%> in Objective-C"); |
| if (flag_isoc99) |
| pedwarn_c99 (loc, OPT_Wpedantic, |
| "ISO C99 does not support the %<_Atomic%> qualifier"); |
| else |
| pedwarn_c99 (loc, OPT_Wpedantic, |
| "ISO C90 does not support the %<_Atomic%> qualifier"); |
| attrs_ok = true; |
| tree value; |
| value = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| if (typespec_ok && c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| { |
| /* _Atomic ( type-name ). */ |
| seen_type = true; |
| c_parser_consume_token (parser); |
| struct c_type_name *type = c_parser_type_name (parser); |
| t.kind = ctsk_typeof; |
| t.spec = error_mark_node; |
| t.expr = NULL_TREE; |
| t.expr_const_operands = true; |
| if (type != NULL) |
| t.spec = groktypename (type, &t.expr, |
| &t.expr_const_operands); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| if (t.spec != error_mark_node) |
| { |
| if (TREE_CODE (t.spec) == ARRAY_TYPE) |
| error_at (loc, "%<_Atomic%>-qualified array type"); |
| else if (TREE_CODE (t.spec) == FUNCTION_TYPE) |
| error_at (loc, "%<_Atomic%>-qualified function type"); |
| else if (TYPE_QUALS (t.spec) != TYPE_UNQUALIFIED) |
| error_at (loc, "%<_Atomic%> applied to a qualified type"); |
| else |
| t.spec = c_build_qualified_type (t.spec, TYPE_QUAL_ATOMIC); |
| } |
| declspecs_add_type (loc, specs, t); |
| } |
| else |
| declspecs_add_qual (loc, specs, value); |
| break; |
| case RID_CONST: |
| case RID_VOLATILE: |
| case RID_RESTRICT: |
| attrs_ok = true; |
| declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value); |
| c_parser_consume_token (parser); |
| break; |
| case RID_ATTRIBUTE: |
| if (!attrs_ok) |
| goto out; |
| attrs = c_parser_gnu_attributes (parser); |
| declspecs_add_attrs (loc, specs, attrs); |
| break; |
| case RID_ALIGNAS: |
| if (!alignspec_ok) |
| goto out; |
| align = c_parser_alignas_specifier (parser); |
| declspecs_add_alignas (loc, specs, align); |
| break; |
| case RID_GIMPLE: |
| if (! flag_gimple) |
| error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>"); |
| c_parser_consume_token (parser); |
| specs->declspec_il = cdil_gimple; |
| specs->locations[cdw_gimple] = loc; |
| c_parser_gimple_or_rtl_pass_list (parser, specs); |
| break; |
| case RID_RTL: |
| c_parser_consume_token (parser); |
| specs->declspec_il = cdil_rtl; |
| specs->locations[cdw_rtl] = loc; |
| c_parser_gimple_or_rtl_pass_list (parser, specs); |
| break; |
| default: |
| goto out; |
| } |
| } |
| out: |
| if (end_std_attr_ok |
| && c_parser_nth_token_starts_std_attributes (parser, 1)) |
| specs->postfix_attrs = c_parser_std_attribute_specifier_sequence (parser); |
| } |
| |
| /* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2). |
| |
| enum-specifier: |
| enum gnu-attributes[opt] identifier[opt] { enumerator-list } |
| gnu-attributes[opt] |
| enum gnu-attributes[opt] identifier[opt] { enumerator-list , } |
| gnu-attributes[opt] |
| enum gnu-attributes[opt] identifier |
| |
| The form with trailing comma is new in C99. The forms with |
| gnu-attributes are GNU extensions. In GNU C, we accept any expression |
| without commas in the syntax (assignment expressions, not just |
| conditional expressions); assignment expressions will be diagnosed |
| as non-constant. |
| |
| enumerator-list: |
| enumerator |
| enumerator-list , enumerator |
| |
| enumerator: |
| enumeration-constant attribute-specifier-sequence[opt] |
| enumeration-constant attribute-specifier-sequence[opt] |
| = constant-expression |
| |
| GNU Extensions: |
| |
| enumerator: |
| enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt] |
| enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt] |
| = constant-expression |
| |
| */ |
| |
| static struct c_typespec |
| c_parser_enum_specifier (c_parser *parser) |
| { |
| struct c_typespec ret; |
| bool have_std_attrs; |
| tree std_attrs = NULL_TREE; |
| tree attrs; |
| tree ident = NULL_TREE; |
| location_t enum_loc; |
| location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); |
| c_parser_consume_token (parser); |
| have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); |
| if (have_std_attrs) |
| std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
| attrs = c_parser_gnu_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)) |
| { |
| ident = c_parser_peek_token (parser)->value; |
| ident_loc = c_parser_peek_token (parser)->location; |
| enum_loc = ident_loc; |
| c_parser_consume_token (parser); |
| } |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| /* Parse an enum definition. */ |
| struct c_enum_contents the_enum; |
| tree type; |
| tree postfix_attrs; |
| /* We chain the enumerators in reverse order, then put them in |
| forward order at the end. */ |
| tree values; |
| timevar_push (TV_PARSE_ENUM); |
| type = start_enum (enum_loc, &the_enum, ident); |
| values = NULL_TREE; |
| c_parser_consume_token (parser); |
| while (true) |
| { |
| tree enum_id; |
| tree enum_value; |
| tree enum_decl; |
| bool seen_comma; |
| c_token *token; |
| location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
| location_t decl_loc, value_loc; |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| /* Give a nicer error for "enum {}". */ |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE) |
| && !parser->error) |
| { |
| error_at (c_parser_peek_token (parser)->location, |
| "empty enum is invalid"); |
| parser->error = true; |
| } |
| else |
| c_parser_error (parser, "expected identifier"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); |
| values = error_mark_node; |
| break; |
| } |
| token = c_parser_peek_token (parser); |
| enum_id = token->value; |
| /* Set the location in case we create a decl now. */ |
| c_parser_set_source_position_from_token (token); |
| decl_loc = value_loc = token->location; |
| c_parser_consume_token (parser); |
| /* Parse any specified attributes. */ |
| tree std_attrs = NULL_TREE; |
| if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
| std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
| tree enum_attrs = chainon (std_attrs, |
| c_parser_gnu_attributes (parser)); |
| if (c_parser_next_token_is (parser, CPP_EQ)) |
| { |
| c_parser_consume_token (parser); |
| value_loc = c_parser_peek_token (parser)->location; |
| enum_value = c_parser_expr_no_commas (parser, NULL).value; |
| } |
| else |
| enum_value = NULL_TREE; |
| enum_decl = build_enumerator (decl_loc, value_loc, |
| &the_enum, enum_id, enum_value); |
| if (enum_attrs) |
| decl_attributes (&TREE_PURPOSE (enum_decl), enum_attrs, 0); |
| TREE_CHAIN (enum_decl) = values; |
| values = enum_decl; |
| seen_comma = false; |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| { |
| comma_loc = c_parser_peek_token (parser)->location; |
| seen_comma = true; |
| c_parser_consume_token (parser); |
| } |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| { |
| if (seen_comma) |
| pedwarn_c90 (comma_loc, OPT_Wpedantic, |
| "comma at end of enumerator list"); |
| c_parser_consume_token (parser); |
| break; |
| } |
| if (!seen_comma) |
| { |
| c_parser_error (parser, "expected %<,%> or %<}%>"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); |
| values = error_mark_node; |