X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-lang.c;h=54f86dfab12095e6fbd9ce3d7a2cb40ae07b6d87;hb=4206f59199f12699c724219ebf37a58cfeaecbd1;hp=331ff54e5dce74ca9608f060528ab3f2dd75399b;hpb=0b387d23327ce63d1f865a1716b346e590061bcb;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-lang.c b/gcc/c-lang.c index 331ff54e5dc..54f86dfab12 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -1,115 +1,154 @@ /* Language-specific hook definitions for C front end. Copyright (C) 1991, 1995, 1997, 1998, - 1999, 2000 Free Software Foundation, Inc. + 1999, 2000, 2001 Free Software Foundation, Inc. -This file is part of GNU CC. +This file is part of GCC. -GNU CC 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 2, or (at your option) -any later version. +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 2, or (at your option) any later +version. -GNU CC 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. +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #include "config.h" #include "system.h" #include "tree.h" +#include "tree-inline.h" #include "function.h" #include "input.h" -#include "c-tree.h" -#include "c-lex.h" #include "toplev.h" +#include "diagnostic.h" #include "output.h" #include "flags.h" #include "ggc.h" - -#if USE_CPPLIB +#include "rtl.h" +#include "expr.h" +#include "c-tree.h" +#include "c-lex.h" #include "cpplib.h" -extern char *yy_cur; -extern cpp_reader parse_in; -extern cpp_options parse_options; -#endif - -/* Each of the functions defined here - is an alternative to a function in objc-actions.c. */ - -int -lang_decode_option (argc, argv) - int argc; - char **argv; +#include "insn-config.h" +#include "integrate.h" +#include "varray.h" +#include "langhooks.h" +#include "langhooks-def.h" + +static int c_tree_printer PARAMS ((output_buffer *)); +static int c_missing_noreturn_ok_p PARAMS ((tree)); +static const char *c_init PARAMS ((const char *)); +static void c_init_options PARAMS ((void)); +static void c_post_options PARAMS ((void)); +static int c_disregard_inline_limits PARAMS ((tree)); +static int c_cannot_inline_tree_fn PARAMS ((tree *)); + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "GNU C" +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT c_init +#undef LANG_HOOKS_FINISH +#define LANG_HOOKS_FINISH c_common_finish +#undef LANG_HOOKS_INIT_OPTIONS +#define LANG_HOOKS_INIT_OPTIONS c_init_options +#undef LANG_HOOKS_DECODE_OPTION +#define LANG_HOOKS_DECODE_OPTION c_decode_option +#undef LANG_HOOKS_POST_OPTIONS +#define LANG_HOOKS_POST_OPTIONS c_post_options +#undef LANG_HOOKS_GET_ALIAS_SET +#define LANG_HOOKS_GET_ALIAS_SET c_common_get_alias_set +#undef LANG_HOOKS_PRINT_IDENTIFIER +#define LANG_HOOKS_PRINT_IDENTIFIER c_print_identifier +#undef LANG_HOOKS_SET_YYDEBUG +#define LANG_HOOKS_SET_YYDEBUG c_set_yydebug + +#undef LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN +#define LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN \ + c_cannot_inline_tree_fn +#undef LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS +#define LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS \ + c_disregard_inline_limits +#undef LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P +#define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P \ + anon_aggr_type_p + +/* Each front end provides its own. */ +const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +static varray_type deferred_fns; + +/* Post-switch processing. */ +static void +c_post_options () { - return c_decode_option (argc, argv); + cpp_post_options (parse_in); + + /* Use tree inlining if possible. Function instrumentation is only + done in the RTL level, so we disable tree inlining. */ + if (! flag_instrument_function_entry_exit) + { + if (!flag_no_inline) + { + flag_inline_trees = 1; + flag_no_inline = 1; + } + if (flag_inline_functions) + { + flag_inline_trees = 2; + flag_inline_functions = 0; + } + } } -void -lang_init_options () +static void +c_init_options () { -#if USE_CPPLIB - cpp_reader_init (&parse_in); - parse_in.opts = &parse_options; - cpp_options_init (&parse_options); -#endif + parse_in = cpp_create_reader (CLK_GNUC89); + /* Mark as "unspecified". */ flag_bounds_check = -1; } -void -lang_init () -{ - /* If still "unspecified", make it match -fbounded-pointers. */ - if (flag_bounds_check < 0) - flag_bounds_check = flag_bounded_pointers; - - /* the beginning of the file is a new line; check for # */ - /* With luck, we discover the real source file's name from that - and put it in input_filename. */ -#if !USE_CPPLIB - ungetc (check_newline (), finput); -#else - check_newline (); - yy_cur--; -#endif - - save_lang_status = &push_c_function_context; - restore_lang_status = &pop_c_function_context; - mark_lang_status = &mark_c_function_context; +static const char * +c_init (filename) + const char *filename; +{ + c_init_decl_processing (); - c_parse_init (); -} + filename = c_common_lang_init (filename); -void -lang_finish () -{ -} + add_c_tree_codes (); -const char * -lang_identify () -{ - return "c"; -} + /* If still unspecified, make it match -std=c99 + (allowing for -pedantic-errors). */ + if (mesg_implicit_function_declaration < 0) + { + if (flag_isoc99) + mesg_implicit_function_declaration = flag_pedantic_errors ? 2 : 1; + else + mesg_implicit_function_declaration = 0; + } -void -print_lang_statistics () -{ -} + save_lang_status = &push_c_function_context; + restore_lang_status = &pop_c_function_context; + mark_lang_status = &mark_c_function_context; + lang_expand_expr = &c_expand_expr; + lang_safe_from_p = &c_safe_from_p; + diagnostic_format_decoder (global_dc) = &c_tree_printer; + lang_expand_decl_stmt = &c_expand_decl_stmt; + lang_missing_noreturn_ok_p = &c_missing_noreturn_ok_p; -/* used by print-tree.c */ + VARRAY_TREE_INIT (deferred_fns, 32, "deferred_fns"); + ggc_add_tree_varray_root (&deferred_fns, 1); -void -lang_print_xnode (file, node, indent) - FILE *file ATTRIBUTE_UNUSED; - tree node ATTRIBUTE_UNUSED; - int indent ATTRIBUTE_UNUSED; -{ + return filename; } /* Used by c-lex.c, but only for objc. */ @@ -144,13 +183,6 @@ maybe_objc_comptypes (lhs, rhs, reflexive) } tree -maybe_objc_method_name (decl) - tree decl ATTRIBUTE_UNUSED; -{ - return 0; -} - -tree maybe_building_objc_message_expr () { return 0; @@ -162,13 +194,75 @@ recognize_objc_keyword () return 0; } +/* Used by c-typeck.c (build_external_ref), but only for objc. */ + tree -build_objc_string (len, str) - int len ATTRIBUTE_UNUSED; - const char *str ATTRIBUTE_UNUSED; +lookup_objc_ivar (id) + tree id ATTRIBUTE_UNUSED; { - abort (); - return NULL_TREE; + return 0; +} + +extern tree static_ctors; +extern tree static_dtors; + +static tree start_cdtor PARAMS ((int)); +static void finish_cdtor PARAMS ((tree)); + +static tree +start_cdtor (method_type) + int method_type; +{ + tree fnname = get_file_function_name (method_type); + tree void_list_node_1 = build_tree_list (NULL_TREE, void_type_node); + tree body; + + start_function (void_list_node_1, + build_nt (CALL_EXPR, fnname, + tree_cons (NULL_TREE, NULL_TREE, void_list_node_1), + NULL_TREE), + NULL_TREE); + store_parm_decls (); + + current_function_cannot_inline + = "static constructors and destructors cannot be inlined"; + + body = c_begin_compound_stmt (); + + pushlevel (0); + clear_last_expr (); + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); + + return body; +} + +static void +finish_cdtor (body) + tree body; +{ + tree scope; + tree block; + + scope = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + block = poplevel (0, 0, 0); + SCOPE_STMT_BLOCK (TREE_PURPOSE (scope)) = block; + SCOPE_STMT_BLOCK (TREE_VALUE (scope)) = block; + + RECHAIN_STMTS (body, COMPOUND_BODY (body)); + + finish_function (0); +} + +/* Register a function tree, so that its optimization and conversion + to RTL is only done at the end of the compilation. */ + +int +defer_fn (fn) + tree fn; +{ + VARRAY_PUSH_TREE (deferred_fns, fn); + + return 1; } /* Called at end of parsing, but before end-of-file processing. */ @@ -176,58 +270,269 @@ build_objc_string (len, str) void finish_file () { -#ifndef ASM_OUTPUT_CONSTRUCTOR - extern tree static_ctors; -#endif -#ifndef ASM_OUTPUT_DESTRUCTOR - extern tree static_dtors; -#endif - extern tree build_function_call PARAMS ((tree, tree)); -#if !defined(ASM_OUTPUT_CONSTRUCTOR) || !defined(ASM_OUTPUT_DESTRUCTOR) - tree void_list_node_1 = build_tree_list (NULL_TREE, void_type_node); -#endif -#ifndef ASM_OUTPUT_CONSTRUCTOR + unsigned int i; + bool reconsider; + + for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++) + { + tree decl = VARRAY_TREE (deferred_fns, i); + + if (! TREE_ASM_WRITTEN (decl) && TREE_PUBLIC (decl)) + { + c_expand_deferred_function (decl); + VARRAY_TREE (deferred_fns, i) = NULL; + } + } + + do + { + reconsider = false; + for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++) + { + tree decl = VARRAY_TREE (deferred_fns, i); + + if (decl + && ! TREE_ASM_WRITTEN (decl) + && (flag_keep_inline_functions + || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) + { + c_expand_deferred_function (decl); + VARRAY_TREE (deferred_fns, i) = NULL; + reconsider = true; + } + } + } while (reconsider); + + VARRAY_FREE (deferred_fns); + if (static_ctors) { - tree fnname = get_file_function_name ('I'); - start_function (void_list_node_1, - build_parse_node (CALL_EXPR, fnname, - tree_cons (NULL_TREE, NULL_TREE, - void_list_node_1), - NULL_TREE), - NULL_TREE, NULL_TREE); - fnname = DECL_ASSEMBLER_NAME (current_function_decl); - store_parm_decls (); + tree body = start_cdtor ('I'); for (; static_ctors; static_ctors = TREE_CHAIN (static_ctors)) - expand_expr_stmt (build_function_call (TREE_VALUE (static_ctors), - NULL_TREE)); - - finish_function (0); + c_expand_expr_stmt (build_function_call (TREE_VALUE (static_ctors), + NULL_TREE)); - assemble_constructor (IDENTIFIER_POINTER (fnname)); + finish_cdtor (body); } -#endif -#ifndef ASM_OUTPUT_DESTRUCTOR if (static_dtors) { - tree fnname = get_file_function_name ('D'); - start_function (void_list_node_1, - build_parse_node (CALL_EXPR, fnname, - tree_cons (NULL_TREE, NULL_TREE, - void_list_node_1), - NULL_TREE), - NULL_TREE, NULL_TREE); - fnname = DECL_ASSEMBLER_NAME (current_function_decl); - store_parm_decls (); + tree body = start_cdtor ('D'); for (; static_dtors; static_dtors = TREE_CHAIN (static_dtors)) - expand_expr_stmt (build_function_call (TREE_VALUE (static_dtors), - NULL_TREE)); + c_expand_expr_stmt (build_function_call (TREE_VALUE (static_dtors), + NULL_TREE)); + + finish_cdtor (body); + } - finish_function (0); + if (back_end_hook) + (*back_end_hook) (getdecls ()); + + { + int flags; + FILE *stream = dump_begin (TDI_all, &flags); + + if (stream) + { + dump_node (getdecls (), flags & ~TDF_SLIM, stream); + dump_end (TDI_all, stream); + } + } +} - assemble_destructor (IDENTIFIER_POINTER (fnname)); +/* Called during diagnostic message formatting process to print a + source-level entity onto BUFFER. The meaning of the format specifiers + is as follows: + %D: a general decl, + %F: a function declaration, + %T: a type. + + These format specifiers form a subset of the format specifiers set used + by the C++ front-end. + Please notice when called, the `%' part was already skipped by the + diagnostic machinery. */ +static int +c_tree_printer (buffer) + output_buffer *buffer; +{ + tree t = va_arg (output_buffer_format_args (buffer), tree); + + switch (*output_buffer_text_cursor (buffer)) + { + case 'D': + case 'F': + case 'T': + { + const char *n = DECL_NAME (t) + ? (*decl_printable_name) (t, 2) + : "({anonymous})"; + output_add_string (buffer, n); + } + return 1; + + default: + return 0; } +} + +static int +c_missing_noreturn_ok_p (decl) + tree decl; +{ + /* A missing noreturn is not ok for freestanding implementations and + ok for the `main' function in hosted implementations. */ + return flag_hosted && MAIN_NAME_P (DECL_ASSEMBLER_NAME (decl)); +} + +/* We want to inline `extern inline' functions even if this would + violate inlining limits. Some glibc and linux constructs depend on + such functions always being inlined when optimizing. */ + +static int +c_disregard_inline_limits (fn) + tree fn; +{ + return DECL_DECLARED_INLINE_P (fn) && DECL_EXTERNAL (fn); +} + +static tree inline_forbidden_p PARAMS ((tree *, int *, void *)); + +static tree +inline_forbidden_p (nodep, walk_subtrees, fn) + tree *nodep; + int *walk_subtrees ATTRIBUTE_UNUSED; + void *fn; +{ + tree node = *nodep; + tree t; + + switch (TREE_CODE (node)) + { + case CALL_EXPR: + t = get_callee_fndecl (node); + + if (! t) + break; + + /* We cannot inline functions that call setjmp. */ + if (setjmp_call_p (t)) + return node; + + switch (DECL_FUNCTION_CODE (t)) + { + /* We cannot inline functions that take a variable number of + arguments. */ + case BUILT_IN_VARARGS_START: + case BUILT_IN_STDARG_START: +#if 0 + /* Functions that need information about the address of the + caller can't (shouldn't?) be inlined. */ + case BUILT_IN_RETURN_ADDRESS: #endif + return node; + + default: + break; + } + + break; + + case DECL_STMT: + /* We cannot inline functions that contain other functions. */ + if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL + && DECL_INITIAL (TREE_OPERAND (node, 0))) + return node; + break; + + case GOTO_STMT: + case GOTO_EXPR: + t = TREE_OPERAND (node, 0); + + /* We will not inline a function which uses computed goto. The + addresses of its local labels, which may be tucked into + global storage, are of course not constant across + instantiations, which causes unexpected behaviour. */ + if (TREE_CODE (t) != LABEL_DECL) + return node; + + /* We cannot inline a nested function that jumps to a nonlocal + label. */ + if (TREE_CODE (t) == LABEL_DECL + && DECL_CONTEXT (t) && DECL_CONTEXT (t) != fn) + return node; + + break; + + default: + break; + } + + return NULL_TREE; +} + +static int +c_cannot_inline_tree_fn (fnp) + tree *fnp; +{ + tree fn = *fnp; + tree t; + + if (! function_attribute_inlinable_p (fn)) + { + DECL_UNINLINABLE (fn) = 1; + return 1; + } + + /* If a function has pending sizes, we must not defer its + compilation, and we can't inline it as a tree. */ + if (fn == current_function_decl) + { + t = get_pending_sizes (); + put_pending_sizes (t); + + if (t) + { + DECL_UNINLINABLE (fn) = 1; + return 1; + } + } + + if (DECL_CONTEXT (fn)) + { + /* If a nested function has pending sizes, we may have already + saved them. */ + if (DECL_LANG_SPECIFIC (fn)->pending_sizes) + { + DECL_UNINLINABLE (fn) = 1; + return 1; + } + } + else + { + /* We rely on the fact that this function is called upfront, + just before we start expanding a function. If FN is active + (i.e., it's the current_function_decl or a parent thereof), + we have to walk FN's saved tree. Otherwise, we can safely + assume we have done it before and, if we didn't mark it as + uninlinable (in which case we wouldn't have been called), it + is inlinable. Unfortunately, this strategy doesn't work for + nested functions, because they're only expanded as part of + their enclosing functions, so the inlinability test comes in + late. */ + t = current_function_decl; + + while (t && t != fn) + t = DECL_CONTEXT (t); + if (! t) + return 0; + } + + if (walk_tree (&DECL_SAVED_TREE (fn), inline_forbidden_p, fn, NULL)) + { + DECL_UNINLINABLE (fn) = 1; + return 1; + } + + return 0; }