These are the C (and ObjC) Frontend changes required by the GIMPLE Frontend which is now itself contained in c/gimple-parser.[ch].
Most changes are due to a new c-parser.h header where we export stuff from the C parser that the GIMPLE frontend requires. Other changes include new __GIMPLE and __PHI keywords, handling __GIMPLE as new declspec and dispatching to the GIMPLE parser for __GIMPLE marked function definitions. We'd like to include the GIMPLE parser for GCC 7, as the parser is pretty self-contained (and now works to a good extent) it can be improved during stage3 or when testcases show that it needs improvement. Bootstrapped and tested on x86_64-unknown-linux-gnu (together with [2/2]) for C, ObjC. Ok for trunk? Thanks, Richard. 2016-10-28 Prasad Ghangal <prasad.ghan...@gmail.com> Richard Biener <rguent...@suse.de> c/ * Make-lang.in (C_AND_OBJC_OBJS): Add gimple-parser.o. * config-lang.in (gtfiles): Add c/c-parser.h. * c-tree.h (enum c_declspec_word): Add cdw_gimple. (struct c_declspecs): Add gimple_pass member and gimple_p flag. * c-parser.c (enum c_id_kind, struct c_token, c_parser_next_token_is, c_parser_next_token_is_not, c_parser_next_token_is_keyword, enum c_lookahead_kind, enum c_dtr_syn, enum c_parser_prec): Split out to ... * c-parser.h: ... new header. * c-parser.c: Include c-parser.h and gimple-parser.h. (c_parser_peek_token, c_parser_peek_2nd_token, c_token_starts_typename, c_parser_next_token_starts_declspecs, c_parser_next_tokens_start_declaration, c_parser_consume_token, c_parser_error, c_parser_require, c_parser_skip_until_found, c_parser_declspecs, c_parser_declarator, c_parser_peek_nth_token, c_parser_cast_expression): Export. (c_parser_tokens_buf): New function. (c_parser_error): Likewise. (c_parser_set_error): Likewise. (c_parser_declspecs): Handle RID_GIMPLE. (c_parser_declaration_or_fndef): Parse __GIMPLE marked body via c_parser_parse_gimple_body. * c-parser.h (c_parser_peek_token, c_parser_peek_2nd_token, c_token_starts_typename, c_parser_next_token_starts_declspecs, c_parser_next_tokens_start_declaration, c_parser_consume_token, c_parser_error, c_parser_require, c_parser_skip_until_found, c_parser_declspecs, c_parser_declarator, c_parser_peek_nth_token, c_parser_cast_expression): Declare. (struct c_parser): Declare forward. (c_parser_tokens_buf): Declare. (c_parser_error): Likewise. (c_parser_set_error): Likewise. * gimple-parser.c: New file. * gimple-parser.h: Likewise. obj-c/ * config-lang.in (gtfiles): Add c/c-parser.h. c-family/ * c-common.h (c_common_resword): Add RID_GIMPLE, RID_PHI types. * c-common.h (enum rid): Add RID_GIMPLE, RID_PHI. * c.opt (fgimple): New option. * doc/invoke.texi (fgimple): Document. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 307862b..2997c83 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -435,6 +435,8 @@ const struct c_common_resword c_common_reswords[] = { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, { "__volatile", RID_VOLATILE, 0 }, { "__volatile__", RID_VOLATILE, 0 }, + { "__GIMPLE", RID_GIMPLE, D_CONLY }, + { "__PHI", RID_PHI, D_CONLY }, { "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX11 | D_CXXWARN }, { "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX11 | D_CXXWARN }, { "asm", RID_ASM, D_ASM }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 547bab2..1fbe060 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -118,6 +118,12 @@ enum rid RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN, + /* "__GIMPLE", for the GIMPLE-parsing extension to the C frontend. */ + RID_GIMPLE, + + /* "__PHI", for parsing PHI function in GIMPLE FE. */ + RID_PHI, + /* C11 */ RID_ALIGNAS, RID_GENERIC, diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 458d453..24d3b8e 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -200,6 +200,10 @@ F Driver C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs) -F <dir> Add <dir> to the end of the main framework include path. +fgimple +C Var(flag_gimple) Init(0) +Enable parsing GIMPLE. + H C ObjC C++ ObjC++ Print the name of header files as they are used. diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in index 72c9ae7..cd7108b 100644 --- a/gcc/c/Make-lang.in +++ b/gcc/c/Make-lang.in @@ -51,7 +51,8 @@ CFLAGS-c/gccspec.o += $(DRIVER_DEFINES) # Language-specific object files for C and Objective C. C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \ c/c-convert.o c/c-aux-info.o c/c-objc-common.o c/c-parser.o \ - c/c-array-notation.o c/c-fold.o $(C_COMMON_OBJS) $(C_TARGET_OBJS) + c/c-array-notation.o c/c-fold.o c/gimple-parser.o \ + $(C_COMMON_OBJS) $(C_TARGET_OBJS) # Language-specific object files for C. C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS) diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 6bc42da..d21b8e9 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -59,6 +59,8 @@ along with GCC; see the file COPYING3. If not see #include "gimple-expr.h" #include "context.h" #include "gcc-rich-location.h" +#include "c-parser.h" +#include "gimple-parser.h" /* We need to walk over decls with incomplete struct/union/enum types after parsing the whole translation unit. @@ -150,63 +152,6 @@ c_parse_init (void) } } -/* The C lexer intermediates between the lexer in cpplib and c-lex.c - and the C parser. Unlike the C++ lexer, the parser structure - stores the lexer information instead of using a separate structure. - Identifiers are separated into ordinary identifiers, type names, - keywords and some other Objective-C types of identifiers, and some - look-ahead is maintained. - - ??? It might be a good idea to lex the whole file up front (as for - C++). It would then be possible to share more of the C and C++ - lexer code, if desired. */ - -/* More information about the type of a CPP_NAME token. */ -enum c_id_kind { - /* An ordinary identifier. */ - C_ID_ID, - /* An identifier declared as a typedef name. */ - C_ID_TYPENAME, - /* An identifier declared as an Objective-C class name. */ - C_ID_CLASSNAME, - /* An address space identifier. */ - C_ID_ADDRSPACE, - /* Not an identifier. */ - C_ID_NONE -}; - -/* A single C token after string literal concatenation and conversion - of preprocessing tokens to tokens. */ -struct GTY (()) c_token { - /* The kind of token. */ - ENUM_BITFIELD (cpp_ttype) type : 8; - /* If this token is a CPP_NAME, this value indicates whether also - declared as some kind of type. Otherwise, it is C_ID_NONE. */ - ENUM_BITFIELD (c_id_kind) id_kind : 8; - /* If this token is a keyword, this value indicates which keyword. - Otherwise, this value is RID_MAX. */ - ENUM_BITFIELD (rid) keyword : 8; - /* If this token is a CPP_PRAGMA, this indicates the pragma that - was seen. Otherwise it is PRAGMA_NONE. */ - ENUM_BITFIELD (pragma_kind) pragma_kind : 8; - /* The location at which this token was found. */ - location_t location; - /* The value associated with this token, if any. */ - tree value; - /* Token flags. */ - unsigned char flags; - - source_range get_range () const - { - return get_range_from_loc (line_table, location); - } - - location_t get_finish () const - { - return get_range ().m_finish; - } -}; - /* 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. */ @@ -259,6 +204,30 @@ struct GTY(()) c_parser { vec <c_token, va_gc> *cilk_simd_fn_tokens; }; +/* Return a pointer to the Nth token in PARERs 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? */ @@ -454,7 +423,7 @@ c_lex_one_token (c_parser *parser, c_token *token) /* Return a pointer to the next token from PARSER, reading it in if necessary. */ -static inline c_token * +c_token * c_parser_peek_token (c_parser *parser) { if (parser->tokens_avail == 0) @@ -465,37 +434,10 @@ c_parser_peek_token (c_parser *parser) return &parser->tokens[0]; } -/* Return true if the next token from PARSER has the indicated - TYPE. */ - -static inline bool -c_parser_next_token_is (c_parser *parser, enum cpp_ttype type) -{ - return c_parser_peek_token (parser)->type == type; -} - -/* Return true if the next token from PARSER does not have the - indicated TYPE. */ - -static inline bool -c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type) -{ - return !c_parser_next_token_is (parser, type); -} - -/* Return true if the next token from PARSER is the indicated - KEYWORD. */ - -static inline bool -c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword) -{ - return c_parser_peek_token (parser)->keyword == keyword; -} - /* Return a pointer to the next-but-one token from PARSER, reading it in if necessary. The next token is already read in. */ -static c_token * +c_token * c_parser_peek_2nd_token (c_parser *parser) { if (parser->tokens_avail >= 2) @@ -511,7 +453,7 @@ c_parser_peek_2nd_token (c_parser *parser) /* Return a pointer to the Nth token from PARSER, reading it in if necessary. The N-1th token is already read in. */ -static c_token * +c_token * c_parser_peek_nth_token (c_parser *parser, unsigned int n) { /* N is 1-based, not zero-based. */ @@ -570,7 +512,7 @@ c_keyword_starts_typename (enum rid keyword) /* Return true if TOKEN can start a type name, false otherwise. */ -static bool +bool c_token_starts_typename (c_token *token) { switch (token->type) @@ -601,18 +543,6 @@ c_token_starts_typename (c_token *token) } } -enum c_lookahead_kind { - /* Always treat unknown identifiers as typenames. */ - cla_prefer_type, - - /* Could be parsing a nonabstract declarator. Only treat an identifier - as a typename if followed by another identifier or a star. */ - cla_nonabstract_decl, - - /* Never treat identifiers as typenames. */ - cla_prefer_id -}; - /* Return true if the next token from PARSER can start a type name, false otherwise. LA specifies how to do lookahead in order to detect unknown type names. If unsure, pick CLA_PREFER_ID. */ @@ -779,7 +709,7 @@ c_token_starts_declaration (c_token *token) /* Return true if the next token from PARSER can start declaration specifiers, false otherwise. */ -static inline bool +bool c_parser_next_token_starts_declspecs (c_parser *parser) { c_token *token = c_parser_peek_token (parser); @@ -801,7 +731,7 @@ c_parser_next_token_starts_declspecs (c_parser *parser) /* Return true if the next tokens from PARSER can start declaration specifiers or a static assertion, false otherwise. */ -static inline bool +bool c_parser_next_tokens_start_declaration (c_parser *parser) { c_token *token = c_parser_peek_token (parser); @@ -829,7 +759,7 @@ c_parser_next_tokens_start_declaration (c_parser *parser) /* Consume the next token from PARSER. */ -static void +void c_parser_consume_token (c_parser *parser) { gcc_assert (parser->tokens_avail >= 1); @@ -922,7 +852,7 @@ c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind, this way is not i18n-friendly and some other approach should be used. */ -static void +void c_parser_error (c_parser *parser, const char *gmsgid) { c_token *token = c_parser_peek_token (parser); @@ -965,7 +895,7 @@ c_parser_error (c_parser *parser, const char *gmsgid) been produced and no message will be produced this time. Returns true if found, false otherwise. */ -static bool +bool c_parser_require (c_parser *parser, enum cpp_ttype type, const char *msgid) @@ -1008,7 +938,7 @@ c_parser_require_keyword (c_parser *parser, already been produced and no message will be produced this time. */ -static void +void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type, const char *msgid) @@ -1243,42 +1173,6 @@ restore_extension_diagnostics (int flags) warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0); } -/* Possibly kinds of declarator to parse. */ -enum c_dtr_syn { - /* A normal declarator with an identifier. */ - C_DTR_NORMAL, - /* An abstract declarator (maybe empty). */ - C_DTR_ABSTRACT, - /* A parameter declarator: may be either, but after a type name does - not redeclare a typedef name as an identifier if it can - alternatively be interpreted as a typedef name; see DR#009, - applied in C90 TC1, omitted from C99 and reapplied in C99 TC2 - following DR#249. For example, given a typedef T, "int T" and - "int *T" are valid parameter declarations redeclaring T, while - "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are - abstract declarators rather than involving redundant parentheses; - the same applies with attributes inside the parentheses before - "T". */ - C_DTR_PARM -}; - -/* The binary operation precedence levels, where 0 is a dummy lowest level - used for the bottom of the stack. */ -enum c_parser_prec { - PREC_NONE, - PREC_LOGOR, - PREC_LOGAND, - PREC_BITOR, - PREC_BITXOR, - PREC_BITAND, - PREC_EQ, - PREC_REL, - PREC_SHIFT, - PREC_ADD, - PREC_MULT, - NUM_PRECS -}; - /* Helper data structure for parsing #pragma acc routine. */ struct oacc_routine_data { bool error_seen; /* Set if error has been reported. */ @@ -1295,15 +1189,11 @@ static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool * = NULL); static void c_parser_static_assert_declaration_no_semi (c_parser *); static void c_parser_static_assert_declaration (c_parser *); -static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, - bool, bool, bool, enum c_lookahead_kind); static struct c_typespec c_parser_enum_specifier (c_parser *); static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); static tree c_parser_struct_declaration (c_parser *); static struct c_typespec c_parser_typeof_specifier (c_parser *); static tree c_parser_alignas_specifier (c_parser *); -static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn, - bool *); static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, c_dtr_syn, bool *); static struct c_declarator *c_parser_direct_declarator_inner (c_parser *, @@ -1343,7 +1233,6 @@ 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 *); @@ -1652,7 +1541,13 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool); OpenMP: declaration: - threadprivate-directive */ + threadprivate-directive + + GIMPLE: + + gimple-function-definition: + declaration-specifiers[opt] __GIMPLE (gimple-pass-list) declarator + declaration-list[opt] compound-statement */ static void c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, @@ -1752,6 +1647,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, 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)) @@ -1882,7 +1778,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, struct c_declarator *declarator; bool dummy = false; timevar_id_t tv; - tree fnbody; + 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 @@ -2173,9 +2069,24 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_finish_oacc_routine (oacc_routine_data, current_function_decl, true); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; - fnbody = c_parser_compound_statement (parser); - if (flag_cilkplus && contains_array_notation_expr (fnbody)) - fnbody = expand_array_notation_exprs (fnbody); + + /* If the definition was marked with __GIMPLE then parse the + function body as GIMPLE. */ + if (specs->gimple_p) + { + cfun->pass_startwith = specs->gimple_pass; + bool saved = in_late_binary_op; + in_late_binary_op = true; + c_parser_parse_gimple_body (parser); + in_late_binary_op = saved; + } + else + { + fnbody = c_parser_compound_statement (parser); + if (flag_cilkplus && contains_array_notation_expr (fnbody)) + fnbody = expand_array_notation_exprs (fnbody); + } + tree fndecl = current_function_decl; if (nested) { tree decl = current_function_decl; @@ -2191,9 +2102,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } else { - add_stmt (fnbody); + if (fnbody) + add_stmt (fnbody); finish_function (); } + /* Get rid of the empty stmt list for GIMPLE. */ + if (specs->gimple_p) + DECL_SAVED_TREE (fndecl) = NULL_TREE; timevar_pop (tv); break; @@ -2416,7 +2331,7 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) objc-protocol-refs */ -static void +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, @@ -2681,6 +2596,14 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, 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->gimple_p = true; + specs->locations[cdw_gimple] = loc; + specs->gimple_pass = c_parser_gimple_pass_list (parser); + break; default: goto out; } @@ -3415,7 +3338,7 @@ c_parser_alignas_specifier (c_parser * parser) This function also accepts an omitted abstract declarator as being an abstract declarator, although not part of the formal syntax. */ -static struct c_declarator * +struct c_declarator * c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, bool *seen_id) { @@ -6866,7 +6789,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, ( type-name ) unary-expression */ -static struct c_expr +struct c_expr c_parser_cast_expression (c_parser *parser, struct c_expr *after) { location_t cast_loc = c_parser_peek_token (parser)->location; diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h new file mode 100644 index 0000000..04fa681 --- /dev/null +++ b/gcc/c/c-parser.h @@ -0,0 +1,189 @@ +/* Declarations for the parser for C and Objective-C. + Copyright (C) 1987-2016 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/>. */ + +#ifndef GCC_C_PARSER_H +#define GCC_C_PARSER_H + +/* The C lexer intermediates between the lexer in cpplib and c-lex.c + and the C parser. Unlike the C++ lexer, the parser structure + stores the lexer information instead of using a separate structure. + Identifiers are separated into ordinary identifiers, type names, + keywords and some other Objective-C types of identifiers, and some + look-ahead is maintained. + + ??? It might be a good idea to lex the whole file up front (as for + C++). It would then be possible to share more of the C and C++ + lexer code, if desired. */ + +/* More information about the type of a CPP_NAME token. */ +enum c_id_kind { + /* An ordinary identifier. */ + C_ID_ID, + /* An identifier declared as a typedef name. */ + C_ID_TYPENAME, + /* An identifier declared as an Objective-C class name. */ + C_ID_CLASSNAME, + /* An address space identifier. */ + C_ID_ADDRSPACE, + /* Not an identifier. */ + C_ID_NONE +}; + +/* A single C token after string literal concatenation and conversion + of preprocessing tokens to tokens. */ +struct GTY (()) c_token { + /* The kind of token. */ + ENUM_BITFIELD (cpp_ttype) type : 8; + /* If this token is a CPP_NAME, this value indicates whether also + declared as some kind of type. Otherwise, it is C_ID_NONE. */ + ENUM_BITFIELD (c_id_kind) id_kind : 8; + /* If this token is a keyword, this value indicates which keyword. + Otherwise, this value is RID_MAX. */ + ENUM_BITFIELD (rid) keyword : 8; + /* If this token is a CPP_PRAGMA, this indicates the pragma that + was seen. Otherwise it is PRAGMA_NONE. */ + ENUM_BITFIELD (pragma_kind) pragma_kind : 8; + /* The location at which this token was found. */ + location_t location; + /* The value associated with this token, if any. */ + tree value; + /* Token flags. */ + unsigned char flags; + + source_range get_range () const + { + return get_range_from_loc (line_table, location); + } + + location_t get_finish () const + { + return get_range ().m_finish; + } +}; + +/* The parser. */ +struct c_parser; + +/* Possibly kinds of declarator to parse. */ +enum c_dtr_syn { + /* A normal declarator with an identifier. */ + C_DTR_NORMAL, + /* An abstract declarator (maybe empty). */ + C_DTR_ABSTRACT, + /* A parameter declarator: may be either, but after a type name does + not redeclare a typedef name as an identifier if it can + alternatively be interpreted as a typedef name; see DR#009, + applied in C90 TC1, omitted from C99 and reapplied in C99 TC2 + following DR#249. For example, given a typedef T, "int T" and + "int *T" are valid parameter declarations redeclaring T, while + "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are + abstract declarators rather than involving redundant parentheses; + the same applies with attributes inside the parentheses before + "T". */ + C_DTR_PARM +}; + +/* The binary operation precedence levels, where 0 is a dummy lowest level + used for the bottom of the stack. */ +enum c_parser_prec { + PREC_NONE, + PREC_LOGOR, + PREC_LOGAND, + PREC_BITOR, + PREC_BITXOR, + PREC_BITAND, + PREC_EQ, + PREC_REL, + PREC_SHIFT, + PREC_ADD, + PREC_MULT, + NUM_PRECS +}; + +enum c_lookahead_kind { + /* Always treat unknown identifiers as typenames. */ + cla_prefer_type, + + /* Could be parsing a nonabstract declarator. Only treat an identifier + as a typename if followed by another identifier or a star. */ + cla_nonabstract_decl, + + /* Never treat identifiers as typenames. */ + cla_prefer_id +}; + + +extern c_token * c_parser_peek_token (c_parser *parser); +extern c_token * c_parser_peek_2nd_token (c_parser *parser); +extern c_token * c_parser_peek_nth_token (c_parser *parser, unsigned int n); +extern bool c_parser_require (c_parser *parser, enum cpp_ttype type, + const char *msgid); +extern void c_parser_error (c_parser *parser, const char *gmsgid); +extern void c_parser_consume_token (c_parser *parser); +extern void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type, + const char *msgid); +extern bool c_parser_next_token_starts_declspecs (c_parser *parser); +bool c_parser_next_tokens_start_declaration (c_parser *parser); +bool c_token_starts_typename (c_token *token); + +/* Abstraction to avoid defining c_parser here which messes up gengtype + output wrt ObjC due to vec<c_token> routines being put in gtype-c.h + but not gtype-objc.h. */ +extern c_token * c_parser_tokens_buf (c_parser *parser, unsigned n); +extern bool c_parser_error (c_parser *parser); +extern void c_parser_set_error (c_parser *parser, bool); + +/* Return true if the next token from PARSER has the indicated + TYPE. */ + +static inline bool +c_parser_next_token_is (c_parser *parser, enum cpp_ttype type) +{ + return c_parser_peek_token (parser)->type == type; +} + +/* Return true if the next token from PARSER does not have the + indicated TYPE. */ + +static inline bool +c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type) +{ + return !c_parser_next_token_is (parser, type); +} + +/* Return true if the next token from PARSER is the indicated + KEYWORD. */ + +static inline bool +c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword) +{ + return c_parser_peek_token (parser)->keyword == keyword; +} + +extern struct c_declarator * +c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, + bool *seen_id); +extern void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, + bool, bool, bool, enum c_lookahead_kind); +extern struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); + +#endif diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index e8060f8..a8cf353 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -267,6 +267,7 @@ enum c_declspec_word { cdw_saturating, cdw_alignas, cdw_address_space, + cdw_gimple, cdw_number_of_elements /* This one must always be the last enumerator. */ }; @@ -290,6 +291,8 @@ struct c_declspecs { NULL; attributes (possibly from multiple lists) will be passed separately. */ tree attrs; + /* The pass to start compiling a __GIMPLE function with. */ + char *gimple_pass; /* The base-2 log of the greatest alignment required by an _Alignas specifier, in bytes, or -1 if no such specifiers with nonzero alignment. */ @@ -362,6 +365,8 @@ struct c_declspecs { /* Whether any alignment specifier (even with zero alignment) was specified. */ BOOL_BITFIELD alignas_p : 1; + /* Whether any __GIMPLE specifier was specified. */ + BOOL_BITFIELD gimple_p : 1; /* The address space that the declaration belongs to. */ addr_space_t address_space; }; diff --git a/gcc/c/config-lang.in b/gcc/c/config-lang.in index b9cdc8e..51fbb53 100644 --- a/gcc/c/config-lang.in +++ b/gcc/c/config-lang.in @@ -29,4 +29,4 @@ compilers="cc1\$(exeext)" target_libs= -gtfiles="\$(srcdir)/c/c-lang.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c/c-objc-common.c \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-lang.h" +gtfiles="\$(srcdir)/c/c-lang.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c/c-objc-common.c \$(srcdir)/c/c-parser.h \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-lang.h" diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c new file mode 100644 index 0000000..7f8d948 --- /dev/null +++ b/gcc/c/gimple-parser.c @@ -0,0 +1,1483 @@ +/* Parser for GIMPLE. + Copyright (C) 2016 Free Software Foundation, Inc. + +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/>. */ + +#include "config.h" +#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-low.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 "tree-vrp.h" +#include "tree-pass.h" +#include "tree-pretty-print.h" +#include "tree.h" +#include "basic-block.h" +#include "gimple.h" +#include "gimple-pretty-print.h" +#include "tree-ssa.h" +#include "pass_manager.h" +#include "tree-ssanames.h" +#include "gimple-ssa.h" +#include "tree-dfa.h" +#include "tree-dump.h" + + +/* Gimple parsing functions. */ +static bool c_parser_gimple_compound_statement (c_parser *, gimple_seq *); +static void c_parser_gimple_label (c_parser *, gimple_seq *); +static void c_parser_gimple_expression (c_parser *, gimple_seq *); +static struct c_expr c_parser_gimple_binary_expression (c_parser *, enum tree_code *); +static struct c_expr c_parser_gimple_unary_expression (c_parser *); +static struct c_expr c_parser_gimple_postfix_expression (c_parser *); +static struct c_expr c_parser_gimple_postfix_expression_after_primary (c_parser *, + location_t, + struct c_expr); +static void c_parser_gimple_declaration (c_parser *); +static void c_parser_gimple_goto_stmt (location_t, tree, gimple_seq *); +static void c_parser_gimple_if_stmt (c_parser *, gimple_seq *); +static void c_parser_gimple_switch_stmt (c_parser *, gimple_seq *); +static void c_parser_gimple_return_stmt (c_parser *, gimple_seq *); +static void c_finish_gimple_return (location_t, tree); +static tree c_parser_gimple_paren_condition (c_parser *); +static vec<tree, va_gc> *c_parser_gimple_expr_list (c_parser *, + vec<tree, va_gc> **, vec<location_t> *); + + +/* Parse the body of a function declaration marked with "__GIMPLE". */ + +void +c_parser_parse_gimple_body (c_parser *parser) +{ + gimple_seq seq = NULL; + gimple_seq body = NULL; + tree stmt = push_stmt_list (); + push_scope (); + location_t loc1 = c_parser_peek_token (parser)->location; + + init_tree_ssa (cfun); + + if (! c_parser_gimple_compound_statement (parser, &seq)) + { + gimple *ret = gimple_build_return (NULL); + gimple_seq_add_stmt (&seq, ret); + } + + tree block = pop_scope (); + stmt = pop_stmt_list (stmt); + stmt = c_build_bind_expr (loc1, block, stmt); + + block = DECL_INITIAL (current_function_decl); + BLOCK_SUBBLOCKS (block) = NULL_TREE; + BLOCK_CHAIN (block) = NULL_TREE; + TREE_ASM_WRITTEN (block) = 1; + + gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL, + BIND_EXPR_BLOCK (stmt)); + gimple_bind_set_body (bind_stmt, seq); + gimple_seq_add_stmt (&body, bind_stmt); + gimple_set_body (current_function_decl, body); + + /* While we have SSA names in the IL we do not have a CFG built yet + and PHIs are represented using a PHI internal function. We do + have lowered control flow and exception handling (well, we do not + have parser support for EH yet). But as we still have BINDs + we have to go through lowering again. */ + cfun->curr_properties = PROP_gimple_any; + + dump_function (TDI_generic, current_function_decl); +} + +/* Parse a compound statement in gimple function body. + + gimple-statement: + gimple-statement + gimple-declaration-statement + gimple-if-statement + gimple-switch-statement + gimple-labeled-statement + gimple-expression-statement + gimple-goto-statement + gimple-phi-statement + gimple-return-statement +*/ + +static bool +c_parser_gimple_compound_statement (c_parser *parser, gimple_seq *seq) +{ + bool return_p = false; + + if (! c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + return false; + + /* A compund statement starts with optional declarations. */ + while (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_gimple_declaration (parser); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + return false; + } + + while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) + { + if (c_parser_error (parser)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + return return_p; + } + else if (c_parser_next_token_is (parser, CPP_EOF)) + { + c_parser_error (parser, "expected declaration or statement"); + return return_p; + } + + switch (c_parser_peek_token (parser)->type) + { + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_IF: + c_parser_gimple_if_stmt (parser, seq); + break; + case RID_SWITCH: + c_parser_gimple_switch_stmt (parser, seq); + break; + case RID_GOTO: + { + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_gimple_goto_stmt (loc, + c_parser_peek_token + (parser)->value, + seq); + c_parser_consume_token (parser); + if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<;%>")) + return return_p; + } + } + break; + case RID_RETURN: + return_p = true; + c_parser_gimple_return_stmt (parser, seq); + if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<;%>")) + return return_p; + break; + default: + goto expr_stmt; + } + break; + case CPP_NAME: + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_parser_gimple_label (parser, seq); + break; + } + goto expr_stmt; + + default: +expr_stmt: + c_parser_gimple_expression (parser, seq); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + return return_p; + } + } + c_parser_consume_token (parser); + return return_p; +} + +/* Parse a gimple expression. + + gimple-expression: + gimple-unary-expression + gimple-call-statement + gimple-binary-expression + gimple-assign-expression + gimple-cast-expression + +*/ + +static void +c_parser_gimple_expression (c_parser *parser, gimple_seq *seq) +{ + struct c_expr lhs, rhs; + gimple *assign = NULL; + enum tree_code subcode = NOP_EXPR; + location_t loc; + tree arg = NULL_TREE; + auto_vec<tree> vargs; + + lhs = c_parser_gimple_unary_expression (parser); + rhs.value = error_mark_node; + + if (c_parser_next_token_is (parser, CPP_EQ)) + c_parser_consume_token (parser); + + loc = EXPR_LOCATION (lhs.value); + + /* GIMPLE call expression. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + && TREE_CODE (lhs.value) == CALL_EXPR) + { + gimple *call; + call = gimple_build_call_from_tree (lhs.value); + gimple_seq_add_stmt (seq, call); + gimple_set_location (call, loc); + return; + } + + /* Cast expression. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + /* TODO: have a gimple_cast_expr function. */ + rhs = c_parser_cast_expression (parser, NULL); + if (lhs.value != error_mark_node && + rhs.value != error_mark_node) + { + assign = gimple_build_assign (lhs.value, rhs.value); + gimple_seq_add_stmt (seq, assign); + gimple_set_location (assign, loc); + return; + } + } + + /* Pointer expression. */ + if (TREE_CODE (lhs.value) == INDIRECT_REF) + { + tree save_expr = lhs.value; + bool volatilep = TREE_THIS_VOLATILE (lhs.value); + bool notrap = TREE_THIS_NOTRAP (lhs.value); + tree saved_ptr_type = TREE_TYPE (TREE_OPERAND (lhs.value, 0)); + + lhs.value = fold_indirect_ref_loc (loc, lhs.value); + if (lhs.value == save_expr) + { + lhs.value = fold_build2_loc (input_location, MEM_REF, + TREE_TYPE (lhs.value), + TREE_OPERAND (lhs.value, 0), + build_int_cst (saved_ptr_type, 0)); + TREE_THIS_VOLATILE (lhs.value) = volatilep; + TREE_THIS_NOTRAP (lhs.value) = notrap; + } + } + + switch (c_parser_peek_token (parser)->type) + { + case CPP_AND: + case CPP_PLUS: + case CPP_MINUS: + case CPP_COMPL: + case CPP_NOT: + case CPP_MULT: /* pointer deref */ + rhs = c_parser_gimple_unary_expression (parser); + assign = gimple_build_assign (lhs.value, rhs.value); + gimple_set_location (assign, loc); + gimple_seq_add_stmt (seq, assign); + return; + + default:; + } + + /* GIMPLE PHI expression. */ + if (c_parser_next_token_is_keyword (parser, RID_PHI)) + { + c_parser_consume_token (parser); + + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + c_parser_consume_token (parser); + + while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + arg = lookup_label_for_goto (loc, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_COLON)) + c_parser_consume_token (parser); + vargs.safe_push (arg); + } + else if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + { + arg = c_parser_gimple_unary_expression (parser).value; + vargs.safe_push (arg); + } + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + + /* Build internal function for PHI. */ + gcall *call_stmt = gimple_build_call_internal_vec (IFN_PHI, vargs); + gimple_call_set_lhs (call_stmt, lhs.value); + gimple_set_location (call_stmt, UNKNOWN_LOCATION); + gimple_seq_add_stmt (seq, call_stmt); + return; + } + + /* GIMPLE call with lhs. */ + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN + && lookup_name (c_parser_peek_token (parser)->value)) + { + rhs = c_parser_gimple_unary_expression (parser); + gimple *call = gimple_build_call_from_tree (rhs.value); + gimple_call_set_lhs (call, lhs.value); + gimple_seq_add_stmt (seq, call); + gimple_set_location (call, loc); + return; + } + + rhs = c_parser_gimple_binary_expression (parser, &subcode); + + if (lhs.value != error_mark_node + && rhs.value != error_mark_node) + { + if (subcode == NOP_EXPR) + assign = gimple_build_assign (lhs.value, rhs.value); + else + assign = gimple_build_assign (lhs.value, subcode, + TREE_OPERAND (rhs.value, 0), + TREE_OPERAND (rhs.value, 1)); + gimple_seq_add_stmt (seq, assign); + gimple_set_location (assign, loc); + } + return; +} + +/* Parse gimple binary expr. + + gimple-multiplicative-expression: + gimple-unary-expression * gimple-unary-expression + gimple-unary-expression / gimple-unary-expression + gimple-unary-expression % gimple-unary-expression + + gimple-additive-expression: + gimple-unary-expression + gimple-unary-expression + gimple-unary-expression - gimple-unary-expression + + gimple-shift-expression: + gimple-unary-expression << gimple-unary-expression + gimple-unary-expression >> gimple-unary-expression + + gimple-relational-expression: + gimple-unary-expression < gimple-unary-expression + gimple-unary-expression > gimple-unary-expression + gimple-unary-expression <= gimple-unary-expression + gimple-unary-expression >= gimple-unary-expression + + gimple-equality-expression: + gimple-unary-expression == gimple-unary-expression + gimple-unary-expression != gimple-unary-expression + + gimple-AND-expression: + gimple-unary-expression & gimple-unary-expression + + gimple-exclusive-OR-expression: + gimple-unary-expression ^ gimple-unary-expression + + gimple-inclusive-OR-expression: + gimple-unary-expression | gimple-unary-expression + + gimple-logical-AND-expression: + gimple-unary-expression && gimple-unary-expression + + gimple-logical-OR-expression: + gimple-unary-expression || gimple-unary-expression + +*/ + +static c_expr +c_parser_gimple_binary_expression (c_parser *parser, enum tree_code *subcode) +{ + struct { + /* The expression at this stack level. */ + struct c_expr expr; + /* The operation on its left. */ + enum tree_code op; + /* The source location of this operation. */ + location_t loc; + } stack[2]; + int sp; + /* Location of the binary operator. */ + location_t binary_loc = UNKNOWN_LOCATION; /* Quiet warning. */ +#define POP \ + do { \ + if (sp == 1 \ + && c_parser_peek_token (parser)->type == CPP_SEMICOLON \ + && (((1 << PREC_BITOR) | (1 << PREC_BITXOR) | (1 << PREC_BITAND) \ + | (1 << PREC_SHIFT) | (1 << PREC_ADD) | (1 << PREC_MULT))) \ + && stack[sp].op != TRUNC_MOD_EXPR \ + && stack[0].expr.value != error_mark_node \ + && stack[1].expr.value != error_mark_node) \ + stack[0].expr.value \ + = build2 (stack[1].op, TREE_TYPE (stack[0].expr.value), \ + stack[0].expr.value, stack[1].expr.value); \ + else \ + stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ + stack[sp].op, \ + stack[sp - 1].expr, \ + stack[sp].expr); \ + sp--; \ + } while (0) + stack[0].loc = c_parser_peek_token (parser)->location; + stack[0].expr = c_parser_gimple_unary_expression (parser); + sp = 0; + source_range src_range; + if (c_parser_error (parser)) + goto out; + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT: + *subcode = MULT_EXPR; + break; + case CPP_DIV: + *subcode = TRUNC_DIV_EXPR; + break; + case CPP_MOD: + *subcode = TRUNC_MOD_EXPR; + break; + case CPP_PLUS: + *subcode = PLUS_EXPR; + break; + case CPP_MINUS: + *subcode = MINUS_EXPR; + break; + case CPP_LSHIFT: + *subcode = LSHIFT_EXPR; + break; + case CPP_RSHIFT: + *subcode = RSHIFT_EXPR; + break; + case CPP_LESS: + *subcode = LT_EXPR; + break; + case CPP_GREATER: + *subcode = GT_EXPR; + break; + case CPP_LESS_EQ: + *subcode = LE_EXPR; + break; + case CPP_GREATER_EQ: + *subcode = GE_EXPR; + break; + case CPP_EQ_EQ: + *subcode = EQ_EXPR; + break; + case CPP_NOT_EQ: + *subcode = NE_EXPR; + break; + case CPP_AND: + *subcode = BIT_AND_EXPR; + break; + case CPP_XOR: + *subcode = BIT_XOR_EXPR; + break; + case CPP_OR: + *subcode = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + *subcode = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + *subcode = TRUTH_ORIF_EXPR; + break; + default: + /* Not a binary operator, so end of the binary expression. */ + *subcode = NOP_EXPR; + goto out; + } + binary_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + switch (*subcode) + { + case TRUTH_ANDIF_EXPR: + src_range = stack[sp].expr.src_range; + stack[sp].expr.value = c_objc_common_truthvalue_conversion + (stack[sp].loc, default_conversion (stack[sp].expr.value)); + set_c_expr_source_range (&stack[sp].expr, src_range); + break; + case TRUTH_ORIF_EXPR: + src_range = stack[sp].expr.src_range; + stack[sp].expr.value = c_objc_common_truthvalue_conversion + (stack[sp].loc, default_conversion (stack[sp].expr.value)); + set_c_expr_source_range (&stack[sp].expr, src_range); + break; + default: + break; + } + sp++; + stack[sp].loc = binary_loc; + stack[sp].expr = c_parser_gimple_unary_expression (parser); + stack[sp].op = *subcode; +out: + while (sp > 0) + POP; + return stack[0].expr; +#undef POP +} + +/* Parse gimple unary expression. + + gimple-unary-expression: + gimple-postfix-expression + unary-operator cast-expression + + unary-operator: one of + & * + - ~ ! +*/ + +static c_expr +c_parser_gimple_unary_expression (c_parser *parser) +{ + struct c_expr ret, op; + location_t op_loc = c_parser_peek_token (parser)->location; + location_t finish; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + switch (c_parser_peek_token (parser)->type) + { + case CPP_AND: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + mark_exp_read (op.value); + return parser_build_unary_op (op_loc, ADDR_EXPR, op); + case CPP_MULT: + { + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + finish = op.get_finish (); + location_t combined_loc = make_location (op_loc, op_loc, finish); + ret.value = build_indirect_ref (combined_loc, op.value, + RO_UNARY_STAR); + ret.src_range.m_start = op_loc; + ret.src_range.m_finish = finish; + return ret; + } + case CPP_PLUS: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + return parser_build_unary_op (op_loc, CONVERT_EXPR, op); + case CPP_MINUS: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + return parser_build_unary_op (op_loc, NEGATE_EXPR, op); + case CPP_COMPL: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); + case CPP_NOT: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op); + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_REALPART: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + return parser_build_unary_op (op_loc, REALPART_EXPR, op); + case RID_IMAGPART: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); + default: + return c_parser_gimple_postfix_expression (parser); + } + default: + return c_parser_gimple_postfix_expression (parser); + } +} + +/* Decompose ID into base name (ID until ver_offset) and VERSION. Return + true if ID matches a SSA name. */ + +static bool +c_parser_parse_ssa_name_id (tree id, unsigned *version, unsigned *ver_offset) +{ + const char *token = IDENTIFIER_POINTER (id); + const char *var_version = strrchr (token, '_'); + if (! var_version) + return false; + + *ver_offset = var_version - token; + for (const char *p = var_version + 1; *p; ++p) + if (! ISDIGIT (*p)) + return false; + *version = atoi (var_version + 1); + return *version > 0; +} + +/* Get at the actual SSA name ID with VERSION starting at VER_OFFSET. + TYPE is the type if the SSA name is being declared. */ + +static tree +c_parser_parse_ssa_name (c_parser *parser, + tree id, tree type, unsigned version, + unsigned ver_offset) +{ + tree name = NULL_TREE; + const char *token = IDENTIFIER_POINTER (id); + + if (ver_offset == 0) + { + /* Anonymous unnamed SSA name. */ + if (version < num_ssa_names) + name = ssa_name (version); + if (! name) + { + if (! type) + { + c_parser_error (parser, "SSA name not declared"); + return error_mark_node; + } + name = make_ssa_name_fn (cfun, type, NULL, version); + } + } + else + { + if (version < num_ssa_names) + name = ssa_name (version); + if (! name) + { + /* Separate var name from version. */ + char *var_name = XNEWVEC (char, ver_offset + 1); + memcpy (var_name, token, ver_offset); + var_name[ver_offset] = '\0'; + /* lookup for parent decl. */ + id = get_identifier (var_name); + tree parent = lookup_name (id); + XDELETEVEC (var_name); + if (! parent) + { + c_parser_error (parser, "base variable or SSA name not declared"); + return error_mark_node; + } + if (VECTOR_TYPE_P (TREE_TYPE (parent)) + || TREE_CODE (TREE_TYPE (parent)) == COMPLEX_TYPE) + DECL_GIMPLE_REG_P (parent) = 1; + name = make_ssa_name_fn (cfun, parent, + gimple_build_nop (), version); + } + } + + return name; +} + +/* Parse gimple postfix expression. + + gimple-postfix-expression: + gimple-primary-expression + gimple-primary-xpression [ gimple-primary-expression ] + gimple-primary-expression ( gimple-argument-expression-list[opt] ) + postfix-expression . identifier + postfix-expression -> identifier + + gimple-argument-expression-list: + gimple-unary-expression + gimple-argument-expression-list , gimple-unary-expression + + gimple-primary-expression: + identifier + constant + string-literal + +*/ + +static struct c_expr +c_parser_gimple_postfix_expression (c_parser *parser) +{ + struct c_expr expr; + location_t loc = c_parser_peek_token (parser)->location; + source_range tok_range = c_parser_peek_token (parser)->get_range (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + switch (c_parser_peek_token (parser)->type) + { + case CPP_NUMBER: + expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + break; + case CPP_CHAR: + case CPP_CHAR16: + case CPP_CHAR32: + case CPP_WCHAR: + expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); + c_parser_consume_token (parser); + break; + case CPP_STRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_WSTRING: + case CPP_UTF8STRING: + expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); + expr.original_code = STRING_CST; + c_parser_consume_token (parser); + break; + case CPP_NAME: + if (c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree id = c_parser_peek_token (parser)->value; + unsigned version, ver_offset; + if (! lookup_name (id) + && c_parser_parse_ssa_name_id (id, &version, &ver_offset)) + { + c_parser_consume_token (parser); + expr.value = c_parser_parse_ssa_name (parser, id, NULL_TREE, + version, ver_offset); + /* For default definition SSA names. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME + && strcmp ("D", + IDENTIFIER_POINTER + (c_parser_peek_2nd_token (parser)->value)) == 0 + && c_parser_peek_nth_token (parser, 3)->type == CPP_CLOSE_PAREN) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + c_parser_consume_token (parser); + if (! SSA_NAME_IS_DEFAULT_DEF (expr.value)) + { + set_ssa_default_def (cfun, SSA_NAME_VAR (expr.value), + expr.value); + SSA_NAME_DEF_STMT (expr.value) = gimple_build_nop (); + } + } + } + else + { + c_parser_consume_token (parser); + expr.value + = build_external_ref (loc, id, + (c_parser_peek_token (parser)->type + == CPP_OPEN_PAREN), &expr.original_type); + set_c_expr_source_range (&expr, tok_range); + } + break; + } + else + { + c_parser_error (parser, "expected expression"); + expr.set_error (); + break; + } + break; + default: + c_parser_error (parser, "expected expression"); + expr.set_error (); + break; + } + return c_parser_gimple_postfix_expression_after_primary + (parser, EXPR_LOC_OR_LOC (expr.value, loc), expr); +} + +/* Parse a gimple postfix expression after the initial primary or compound + literal. */ + +static struct c_expr +c_parser_gimple_postfix_expression_after_primary (c_parser *parser, + location_t expr_loc, + struct c_expr expr) +{ + struct c_expr orig_expr; + vec<tree, va_gc> *exprlist; + vec<tree, va_gc> *origtypes = NULL; + vec<location_t> arg_loc = vNULL; + location_t start; + location_t finish; + tree ident; + location_t comp_loc; + + while (true) + { + location_t op_loc = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->type) + { + case CPP_OPEN_SQUARE: + { + c_parser_consume_token (parser); + tree idx = c_parser_gimple_unary_expression (parser).value; + + if (! c_parser_require (parser, CPP_CLOSE_SQUARE, "expected %<]%>")) + break; + + start = expr.get_start (); + finish = c_parser_tokens_buf (parser, 0)->location; + expr.value = build_array_ref (op_loc, expr.value, idx); + set_c_expr_source_range (&expr, start, finish); + + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + } + case CPP_OPEN_PAREN: + { + /* Function call. */ + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + exprlist = NULL; + else + exprlist = c_parser_gimple_expr_list (parser, &origtypes, + &arg_loc); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + orig_expr = expr; + start = expr.get_start (); + finish = c_parser_tokens_buf (parser, 0)->get_finish (); + expr.value = c_build_function_call_vec (expr_loc, arg_loc, + expr.value, + exprlist, origtypes); + set_c_expr_source_range (&expr, start, finish); + + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) == INTEGER_CST + && TREE_CODE (orig_expr.value) == FUNCTION_DECL + && DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P) + expr.original_code = C_MAYBE_CONST_EXPR; + expr.original_type = NULL; + if (exprlist) + { + release_tree_vector (exprlist); + release_tree_vector (origtypes); + } + arg_loc.release (); + break; + } + case CPP_DOT: + { + /* Structure element reference. */ + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *comp_tok = c_parser_peek_token (parser); + ident = comp_tok->value; + comp_loc = comp_tok->location; + } + else + { + c_parser_error (parser, "expected identifier"); + expr.set_error (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + start = expr.get_start (); + finish = c_parser_peek_token (parser)->get_finish (); + c_parser_consume_token (parser); + expr.value = build_component_ref (op_loc, expr.value, ident, + comp_loc); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } + break; + } + case CPP_DEREF: + { + /* Structure element reference. */ + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *comp_tok = c_parser_peek_token (parser); + ident = comp_tok->value; + comp_loc = comp_tok->location; + } + else + { + c_parser_error (parser, "expected identifier"); + expr.set_error (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + start = expr.get_start (); + finish = c_parser_peek_token (parser)->get_finish (); + c_parser_consume_token (parser); + expr.value = build_component_ref (op_loc, + build_simple_mem_ref_loc + (op_loc, expr.value), + ident, comp_loc); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } + break; + } + default: + return expr; + } + } +} + +/* Parse expression list. + + gimple-expr-list: + gimple-unary-expression + gimple-expr-list , gimple-unary-expression + + */ + +static vec<tree, va_gc> * +c_parser_gimple_expr_list (c_parser *parser, vec<tree, va_gc> **p_orig_types, + vec<location_t> *locations) +{ + vec<tree, va_gc> *ret; + vec<tree, va_gc> *orig_types; + struct c_expr expr; + location_t loc = c_parser_peek_token (parser)->location; + + ret = make_tree_vector (); + if (p_orig_types == NULL) + orig_types = NULL; + else + orig_types = make_tree_vector (); + + expr = c_parser_gimple_unary_expression (parser); + vec_safe_push (ret, expr.value); + if (orig_types) + vec_safe_push (orig_types, expr.original_type); + if (locations) + locations->safe_push (loc); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; + expr = c_parser_gimple_unary_expression (parser); + vec_safe_push (ret, expr.value); + if (orig_types) + vec_safe_push (orig_types, expr.original_type); + if (locations) + locations->safe_push (loc); + } + if (orig_types) + *p_orig_types = orig_types; + return ret; +} + +/* Parse gimple label. + + gimple-label: + identifier : + case constant-expression : + default : + +*/ + +static void +c_parser_gimple_label (c_parser *parser, gimple_seq *seq) +{ + tree name = c_parser_peek_token (parser)->value; + location_t loc1 = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); + c_parser_consume_token (parser); + gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); + c_parser_consume_token (parser); + tree label = define_label (loc1, name); + gimple_seq_add_stmt (seq, gimple_build_label (label)); + return; +} + +/* Parse gimple pass list. + + gimple-pass-list: + startwith("pass-name") + */ + +char * +c_parser_gimple_pass_list (c_parser *parser) +{ + char *pass = NULL; + + /* Accept __GIMPLE. */ + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + return NULL; + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *op = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + if (! strcmp (op, "startwith")) + { + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return NULL; + if (c_parser_next_token_is_not (parser, CPP_STRING)) + { + error_at (c_parser_peek_token (parser)->location, + "expected pass name"); + return NULL; + } + pass = xstrdup (TREE_STRING_POINTER + (c_parser_peek_token (parser)->value)); + c_parser_consume_token (parser); + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return NULL; + } + else + { + error_at (c_parser_peek_token (parser)->location, + "invalid operation"); + return NULL; + } + } + + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return NULL; + + return pass; +} + +/* Parse gimple local declaration. + + 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] + + storage-class-specifier: + typedef + extern + static + auto + register + + type-specifier: + void + char + short + int + long + float + double + signed + unsigned + _Bool + _Complex + + type-qualifier: + const + restrict + volatile + address-space-qualifier + _Atomic + + */ + +static void +c_parser_gimple_declaration (c_parser *parser) +{ + struct c_declarator *declarator; + struct c_declspecs *specs = build_null_declspecs (); + c_parser_declspecs (parser, specs, true, true, true, + true, true, cla_nonabstract_decl); + finish_declspecs (specs); + + /* Provide better error recovery. Note that a type name here is usually + better diagnosed as a redeclaration. */ + if (c_parser_next_token_starts_declspecs (parser) + && ! c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %<;%>"); + c_parser_set_error (parser, false); + return; + } + + bool dummy = false; + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_NORMAL, &dummy); + + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + /* Handle SSA name decls specially, they do not go into the identifier + table but we simply build the SSA name for later lookup. */ + unsigned version, ver_offset; + if (declarator->kind == cdk_id + && is_gimple_reg_type (specs->type) + && c_parser_parse_ssa_name_id (declarator->u.id, + &version, &ver_offset) + /* The following restricts it to unnamed anonymous SSA names + which fails parsing of named ones in dumps (we could + decide to not dump their name for -gimple). */ + && ver_offset == 0) + c_parser_parse_ssa_name (parser, declarator->u.id, specs->type, + version, ver_offset); + else + { + tree postfix_attrs = NULL_TREE; + tree all_prefix_attrs = specs->attrs; + specs->attrs = NULL; + tree decl = start_decl (declarator, specs, false, + chainon (postfix_attrs, all_prefix_attrs)); + if (decl) + finish_decl (decl, UNKNOWN_LOCATION, NULL_TREE, NULL_TREE, + NULL_TREE); + } + } + else + { + c_parser_error (parser, "expected %<;%>"); + return; + } +} + +/* Parse gimple goto statement. */ + +static void +c_parser_gimple_goto_stmt (location_t loc, tree label, gimple_seq *seq) +{ + tree decl = lookup_label_for_goto (loc, label); + gimple_seq_add_stmt (seq, gimple_build_goto (decl)); + return; +} + +/* Parse a parenthesized condition. + gimple-condition: + ( gimple-binary-expression ) */ + +static tree +c_parser_gimple_paren_condition (c_parser *parser) +{ + enum tree_code subcode = NOP_EXPR; + location_t loc = c_parser_peek_token (parser)->location; + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return error_mark_node; + tree cond = c_parser_gimple_binary_expression (parser, &subcode).value; + cond = c_objc_common_truthvalue_conversion (loc, cond); + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return error_mark_node; + return cond; +} + +/* Parse gimple if-else statement. + + if-statement: + if ( gimple-binary-expression ) gimple-goto-statement + if ( gimple-binary-expression ) gimple-goto-statement \ + else gimple-goto-statement + */ + +static void +c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq) +{ + tree t_label, f_label, label; + location_t loc; + c_parser_consume_token (parser); + tree cond = c_parser_gimple_paren_condition (parser); + + if (c_parser_next_token_is_keyword (parser, RID_GOTO)) + { + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + label = c_parser_peek_token (parser)->value; + t_label = lookup_label_for_goto (loc, label); + c_parser_consume_token (parser); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + return; + } + else + { + c_parser_error (parser, "expected goto expression"); + return; + } + + if (c_parser_next_token_is_keyword (parser, RID_ELSE)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "expected else statement"); + return; + } + + if (c_parser_next_token_is_keyword (parser, RID_GOTO)) + { + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + label = c_parser_peek_token (parser)->value; + f_label = lookup_label_for_goto (loc, label); + c_parser_consume_token (parser); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + return; + } + else + { + c_parser_error (parser, "expected goto expression"); + return; + } + + gimple_seq_add_stmt (seq, gimple_build_cond_from_tree (cond, t_label, + f_label)); +} + +/* Parse gimple switch-statement. + + gimple-switch-statement: + switch (gimple-unary-expression) gimple-case-statement + + gimple-case-statement: + gimple-case-statement + gimple-label-statement : gimple-goto-statment +*/ + +static void +c_parser_gimple_switch_stmt (c_parser *parser, gimple_seq *seq) +{ + c_expr cond_expr; + tree case_label, label; + auto_vec<tree> labels; + tree default_label = NULL_TREE; + gimple_seq switch_body = NULL; + c_parser_consume_token (parser); + + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + cond_expr = c_parser_gimple_unary_expression (parser); + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return; + } + + if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) + { + if (c_parser_next_token_is (parser, CPP_EOF)) + { + c_parser_error (parser, "expected statement"); + return; + } + + switch (c_parser_peek_token (parser)->keyword) + { + case RID_CASE: + { + c_expr exp1; + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_NAME) + || c_parser_peek_token (parser)->type == CPP_NUMBER) + exp1 = c_parser_gimple_unary_expression (parser); + else + c_parser_error (parser, "expected expression"); + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + label = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + tree decl = lookup_label_for_goto (loc, label); + case_label = build_case_label (exp1.value, NULL_TREE, + decl); + labels.safe_push (case_label); + if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<;%>")) + return; + } + else if (! c_parser_require (parser, CPP_NAME, + "expected label")) + return; + } + else if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<:%>")) + return; + break; + } + case RID_DEFAULT: + { + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + label = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + tree decl = lookup_label_for_goto (loc, label); + default_label = build_case_label (NULL_TREE, NULL_TREE, + decl); + if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<;%>")) + return; + } + else if (! c_parser_require (parser, CPP_NAME, + "expected label")) + return; + } + else if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<:%>")) + return; + break; + } + case RID_GOTO: + { + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_gimple_goto_stmt (loc, + c_parser_peek_token + (parser)->value, + &switch_body); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "expected semicolon"); + return; + } + } + else if (! c_parser_require (parser, CPP_NAME, + "expected label")) + return; + break; + } + default: + c_parser_error (parser, "expected case label or goto statement"); + return; + } + + } + } + if (! c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) + return; + gimple_seq_add_stmt (seq, gimple_build_switch (cond_expr.value, + default_label, labels)); + gimple_seq_add_seq (seq, switch_body); + labels.release(); +} + +/* Parse gimple return statement. */ + +static void +c_parser_gimple_return_stmt (c_parser *parser, gimple_seq *seq) +{ + location_t loc = c_parser_peek_token (parser)->location; + gimple *ret = NULL; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_finish_gimple_return (loc, NULL_TREE); + ret = gimple_build_return (NULL); + gimple_seq_add_stmt (seq, ret); + } + else + { + location_t xloc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_gimple_unary_expression (parser); + c_finish_gimple_return (xloc, expr.value); + ret = gimple_build_return (expr.value); + gimple_seq_add_stmt (seq, ret); + } +} + +/* Support function for c_parser_gimple_return_stmt. */ + +static void +c_finish_gimple_return (location_t loc, tree retval) +{ + tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)); + + /* Use the expansion point to handle cases such as returning NULL + in a function returning void. */ + source_location xloc = expansion_point_location_if_in_system_header (loc); + + if (TREE_THIS_VOLATILE (current_function_decl)) + warning_at (xloc, 0, + "function declared %<noreturn%> has a %<return%> statement"); + + if (! retval) + current_function_returns_null = 1; + else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE) + { + current_function_returns_null = 1; + if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) + { + error_at + (xloc, "%<return%> with a value, in function returning void"); + inform (DECL_SOURCE_LOCATION (current_function_decl), + "declared here"); + } + } + else if (TREE_CODE (valtype) != TREE_CODE (TREE_TYPE (retval))) + { + error_at + (xloc, "invalid conversion in return statement"); + inform (DECL_SOURCE_LOCATION (current_function_decl), + "declared here"); + } + return; +} diff --git a/gcc/c/gimple-parser.h b/gcc/c/gimple-parser.h new file mode 100644 index 0000000..f72b626 --- /dev/null +++ b/gcc/c/gimple-parser.h @@ -0,0 +1,27 @@ +/* Declarations for the parser for GIMPLE. + Copyright (C) 2016 Free Software Foundation, Inc. + +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/>. */ + +#ifndef GCC_GIMPLE_PARSER_H +#define GCC_GIMPLE_PARSER_H + +/* Gimple parsing functions. */ +extern void c_parser_parse_gimple_body (c_parser *); +extern char *c_parser_gimple_pass_list (c_parser *); + +#endif diff --git a/gcc/objc/config-lang.in b/gcc/objc/config-lang.in index f5a74a7..912af22 100644 --- a/gcc/objc/config-lang.in +++ b/gcc/objc/config-lang.in @@ -35,4 +35,4 @@ lang_requires="c" # Order is important. If you change this list, make sure you test # building without C++ as well; that is, remove the gcc/cp directory, # and build with --enable-languages=c,objc. -gtfiles="\$(srcdir)/objc/objc-map.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c/c-lang.h \$(srcdir)/c/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c" +gtfiles="\$(srcdir)/objc/objc-map.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c/c-parser.h \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c/c-lang.h \$(srcdir)/c/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c" diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 5ccd424..e0517b6 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -179,7 +179,7 @@ in the following sections. @xref{C Dialect Options,,Options Controlling C Dialect}. @gccoptlist{-ansi -std=@var{standard} -fgnu89-inline @gol -aux-info @var{filename} -fallow-parameterless-variadic-functions @gol --fno-asm -fno-builtin -fno-builtin-@var{function} @gol +-fno-asm -fno-builtin -fno-builtin-@var{function} -fgimple@gol -fhosted -ffreestanding -fopenacc -fopenmp -fopenmp-simd @gol -fms-extensions -fplan9-extensions -fsso-struct=@var{endianness} -fallow-single-precision -fcond-mismatch -flax-vector-conversions @gol @@ -1948,6 +1948,13 @@ built-in functions selectively when using @option{-fno-builtin} or #define strcpy(d, s) __builtin_strcpy ((d), (s)) @end smallexample +@item -fgimple +@opindex fgimple + +Enable parsing of function definitions marked with @code{__GIMPLE}. +This is an experimental feature that allows unit testing of GIMPLE +passes. + @item -fhosted @opindex fhosted @cindex hosted environment