X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-decl.c;h=bd737d16e7ce43f9827e72976869cac4449229d7;hb=9db402ecdaa81223f3910b379a546c45f44db4a1;hp=e740fcac9172c128bc9ef1e77702739e0402aff1;hpb=54be5d7e4e5aaee714a12a972bcf5ba628e5a239;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-decl.c b/gcc/c-decl.c index e740fcac917..bd737d16e7c 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -62,6 +62,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "langhooks-def.h" #include "pointer-set.h" +/* Set this to 1 if you want the standard ISO C99 semantics of 'inline' + when you specify -std=c99 or -std=gnu99, and to 0 if you want + behaviour compatible with the nonstandard semantics implemented by + GCC 2.95 through 4.2. */ +#define WANT_C99_INLINE_SEMANTICS 1 + /* In grokdeclarator, distinguish syntactic contexts of declarators. */ enum decl_context { NORMAL, /* Ordinary declaration */ @@ -154,10 +160,6 @@ int current_function_returns_abnormally; static int warn_about_return_type; -/* Nonzero when starting a function declared `extern inline'. */ - -static int current_extern_inline; - /* Nonzero when the current toplevel function contains a declaration of a nested function which is never defined. */ @@ -797,11 +799,22 @@ pop_scope (void) && DECL_ABSTRACT_ORIGIN (p) != p) TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1; if (!DECL_EXTERNAL (p) - && DECL_INITIAL (p) == 0) + && !DECL_INITIAL (p) + && scope != file_scope + && scope != external_scope) { error ("nested function %q+D declared but never defined", p); undef_nested_function = true; } + /* C99 6.7.4p6: "a function with external linkage... declared + with an inline function specifier ... shall also be defined in the + same translation unit." */ + else if (DECL_DECLARED_INLINE_P (p) + && TREE_PUBLIC (p) + && !DECL_INITIAL (p) + && flag_isoc99) + pedwarn ("inline function %q+D declared but never defined", p); + goto common_symbol; case VAR_DECL: @@ -1292,10 +1305,11 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, /* Function declarations can either be 'static' or 'extern' (no qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore - can never conflict with each other on account of linkage (6.2.2p4). - Multiple definitions are not allowed (6.9p3,5) but GCC permits - two definitions if one is 'extern inline' and one is not. The non- - extern-inline definition supersedes the extern-inline definition. */ + can never conflict with each other on account of linkage + (6.2.2p4). Multiple definitions are not allowed (6.9p3,5) but + gnu89 mode permits two definitions if one is 'extern inline' and + one is not. The non- extern-inline definition supersedes the + extern-inline definition. */ else if (TREE_CODE (newdecl) == FUNCTION_DECL) { @@ -1321,16 +1335,20 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, { /* If both decls are in the same TU and the new declaration isn't overriding an extern inline reject the new decl. - When we handle c99 style inline rules we'll want to reject - the following: - - DECL_EXTERN_INLINE (olddecl) - && !DECL_EXTERN_INLINE (newdecl) - - if they're in the same translation unit. Until we implement - the full semantics we accept the construct. */ - if (!(DECL_EXTERN_INLINE (olddecl) - && !DECL_EXTERN_INLINE (newdecl)) + In c99, no overriding is allowed in the same translation + unit. */ + if ((!DECL_EXTERN_INLINE (olddecl) + || DECL_EXTERN_INLINE (newdecl) +#if WANT_C99_INLINE_SEMANTICS + || (flag_isoc99 + && (!DECL_DECLARED_INLINE_P (olddecl) + || !lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (olddecl))) + && (!DECL_DECLARED_INLINE_P (newdecl) + || !lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (newdecl)))) +#endif /* WANT_C99_INLINE_SEMANTICS */ + ) && same_translation_unit_p (newdecl, olddecl)) { error ("redefinition of %q+D", newdecl); @@ -1390,6 +1408,23 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, warned = true; } } + + /* Make sure gnu_inline attribute is either not present, or + present on all inline decls. */ + if (DECL_DECLARED_INLINE_P (olddecl) + && DECL_DECLARED_INLINE_P (newdecl)) + { + bool newa = lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (newdecl)) != NULL; + bool olda = lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (olddecl)) != NULL; + if (newa != olda) + { + error ("% attribute present on %q+D", + newa ? newdecl : olddecl); + error ("%Jbut not here", newa ? olddecl : newdecl); + } + } } else if (TREE_CODE (newdecl) == VAR_DECL) { @@ -1521,9 +1556,13 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, ??? Should we still warn about this now we have unit-at-a-time mode and can get it right? Definitely don't complain if the decls are in different translation - units. */ + units. + C99 permits this, so don't warn in that case. (The function + may not be inlined everywhere in function-at-a-time mode, but + we still shouldn't warn.) */ if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl) - && same_translation_unit_p (olddecl, newdecl)) + && same_translation_unit_p (olddecl, newdecl) + && ! flag_isoc99) { if (TREE_USED (olddecl)) { @@ -1600,12 +1639,13 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, static void merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) { - int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL - && DECL_INITIAL (newdecl) != 0); - int new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL - && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0); - int old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL - && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0); + bool new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) != 0); + bool new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL + && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0); + bool old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL + && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0); + bool extern_changed = false; /* For real parm decl following a forward decl, rechain the old decl in its new location and clear TREE_ASM_WRITTEN (it's not a @@ -1752,6 +1792,22 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) } } +#if WANT_C99_INLINE_SEMANTICS + /* In c99, 'extern' declaration before (or after) 'inline' means this + function is not DECL_EXTERNAL, unless 'gnu_inline' attribute + is present. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL + && flag_isoc99 + && (DECL_DECLARED_INLINE_P (newdecl) + || DECL_DECLARED_INLINE_P (olddecl)) + && (!DECL_DECLARED_INLINE_P (newdecl) + || !DECL_DECLARED_INLINE_P (olddecl) + || !DECL_EXTERNAL (olddecl)) + && DECL_EXTERNAL (newdecl) + && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (newdecl))) + DECL_EXTERNAL (newdecl) = 0; +#endif /* WANT_C99_INLINE_SEMANTICS */ + if (DECL_EXTERNAL (newdecl)) { TREE_STATIC (newdecl) = TREE_STATIC (olddecl); @@ -1844,6 +1900,8 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) } } + extern_changed = DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl); + /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. But preserve OLDDECL's DECL_UID and DECL_CONTEXT. */ { @@ -1886,6 +1944,13 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) || (TREE_CODE (olddecl) == VAR_DECL && TREE_STATIC (olddecl)))) make_decl_rtl (olddecl); + + /* If we changed a function from DECL_EXTERNAL to !DECL_EXTERNAL, + and the definition is coming from the old version, cgraph needs + to be called again. */ + if (extern_changed && !new_is_definition + && TREE_CODE (olddecl) == FUNCTION_DECL && DECL_INITIAL (olddecl)) + cgraph_finalize_function (olddecl, false); } /* Handle when a new declaration NEWDECL has the same name as an old @@ -3255,6 +3320,20 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, /* Set attributes here so if duplicate decl, will have proper attributes. */ decl_attributes (&decl, attributes, 0); +#if WANT_C99_INLINE_SEMANTICS + /* Handle gnu_inline attribute. */ + if (declspecs->inline_p + && flag_isoc99 + && TREE_CODE (decl) == FUNCTION_DECL + && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl))) + { + if (declspecs->storage_class == csc_auto && current_scope != file_scope) + ; + else if (declspecs->storage_class != csc_static) + DECL_EXTERNAL (decl) = !DECL_EXTERNAL (decl); + } +#endif /* WANT_C99_INLINE_SEMANTICS */ + if (TREE_CODE (decl) == FUNCTION_DECL && targetm.calls.promote_prototypes (TREE_TYPE (decl))) { @@ -3282,6 +3361,17 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, warning (OPT_Wattributes, "inline function %q+D given attribute noinline", decl); + /* C99 6.7.4p3: An inline definition of a function with external + linkage shall not contain a definition of a modifiable object + with static storage duration... */ + if (TREE_CODE (decl) == VAR_DECL + && current_scope != file_scope + && TREE_STATIC (decl) + && DECL_DECLARED_INLINE_P (current_function_decl) + && DECL_EXTERNAL (current_function_decl)) + pedwarn ("%q+D is static but declared in inline function %qD " + "which is not static", decl, current_function_decl); + /* Add this decl to the current scope. TEM may equal DECL or it may be a previous decl of the same name. */ tem = pushdecl (decl); @@ -3295,6 +3385,23 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, return tem; } +/* Initialize EH if not initialized yet and exceptions are enabled. */ + +void +c_maybe_initialize_eh (void) +{ + if (!flag_exceptions || c_eh_initialized_p) + return; + + c_eh_initialized_p = true; + eh_personality_libfunc + = init_one_libfunc (USING_SJLJ_EXCEPTIONS + ? "__gcc_personality_sj0" + : "__gcc_personality_v0"); + default_init_unwind_resume_libfunc (); + using_eh_for_cleanups (); +} + /* Finish processing of a declaration; install its initial value. If the length of an array type is not known before, @@ -3586,16 +3693,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree) TREE_USED (cleanup_decl) = 1; /* Initialize EH, if we've been told to do so. */ - if (flag_exceptions && !c_eh_initialized_p) - { - c_eh_initialized_p = true; - eh_personality_libfunc - = init_one_libfunc (USING_SJLJ_EXCEPTIONS - ? "__gcc_personality_sj0" - : "__gcc_personality_v0"); - default_init_unwind_resume_libfunc (); - using_eh_for_cleanups (); - } + c_maybe_initialize_eh (); push_cleanup (decl, cleanup, false); } @@ -4726,8 +4824,19 @@ grokdeclarator (const struct c_declarator *declarator, GCC to signify a forward declaration of a nested function. */ if (storage_class == csc_auto && current_scope != file_scope) DECL_EXTERNAL (decl) = 0; + /* In C99, a function which is declared 'inline' with 'extern' + is not an external reference (which is confusing). It + means that the later definition of the function must be output + in this file, C99 6.7.4p6. In GNU C89, a function declared + 'extern inline' is an external reference. */ + else if (declspecs->inline_p && storage_class != csc_static) +#if WANT_C99_INLINE_SEMANTICS + DECL_EXTERNAL (decl) = (storage_class == csc_extern) == !flag_isoc99; +#else + DECL_EXTERNAL (decl) = (storage_class == csc_extern); +#endif else - DECL_EXTERNAL (decl) = 1; + DECL_EXTERNAL (decl) = !initialized; /* Record absence of global scope for `static' or `auto'. */ TREE_PUBLIC (decl) @@ -4757,11 +4866,7 @@ grokdeclarator (const struct c_declarator *declarator, the abstract origin pointing between the declarations, which will confuse dwarf2out. */ if (initialized) - { - DECL_INLINE (decl) = 1; - if (storage_class == csc_extern) - current_extern_inline = 1; - } + DECL_INLINE (decl) = 1; } /* If -finline-functions, assume it can be inlined. This does two things: let the function be deferred until it is actually @@ -5259,12 +5364,15 @@ start_struct (enum tree_code code, tree name) error ("nested redefinition of %", name); else error ("nested redefinition of %", name); + /* Don't create structures that contain themselves. */ + ref = NULL_TREE; } } - else - { - /* Otherwise create a forward-reference just so the tag is in scope. */ + /* Otherwise create a forward-reference just so the tag is in scope. */ + + if (ref == NULL_TREE || TREE_CODE (ref) != code) + { ref = make_node (code); pushtag (name, ref); } @@ -5956,7 +6064,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, current_function_returns_null = 0; current_function_returns_abnormally = 0; warn_about_return_type = 0; - current_extern_inline = 0; c_switch_stack = NULL; nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se); @@ -5996,6 +6103,18 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, warning (OPT_Wattributes, "inline function %q+D given attribute noinline", decl1); +#if WANT_C99_INLINE_SEMANTICS + /* Handle gnu_inline attribute. */ + if (declspecs->inline_p + && flag_isoc99 + && TREE_CODE (decl1) == FUNCTION_DECL + && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1))) + { + if (declspecs->storage_class != csc_static) + DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1); + } +#endif /* WANT_C99_INLINE_SEMANTICS */ + announce_function (decl1); if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1)))) @@ -6108,12 +6227,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, warning (OPT_Wmissing_declarations, "%q+D was used with no declaration before its definition", decl1); - /* This is a definition, not a reference. - So normally clear DECL_EXTERNAL. - However, `extern inline' acts like a declaration - except for defining how to inline. So set DECL_EXTERNAL in that case. */ - DECL_EXTERNAL (decl1) = current_extern_inline; - /* This function exists in static storage. (This does not mean `static' in the C sense!) */ TREE_STATIC (decl1) = 1; @@ -6133,54 +6246,11 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, /* Warn for unlikely, improbable, or stupid declarations of `main'. */ if (warn_main > 0 && MAIN_NAME_P (DECL_NAME (decl1))) { - tree args; - int argct = 0; - if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) != integer_type_node) pedwarn ("return type of %q+D is not %", decl1); - for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args; - args = TREE_CHAIN (args)) - { - tree type = args ? TREE_VALUE (args) : 0; - - if (type == void_type_node) - break; - - ++argct; - switch (argct) - { - case 1: - if (TYPE_MAIN_VARIANT (type) != integer_type_node) - pedwarn ("first argument of %q+D should be %", decl1); - break; - - case 2: - if (TREE_CODE (type) != POINTER_TYPE - || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE - || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) - != char_type_node)) - pedwarn ("second argument of %q+D should be %", - decl1); - break; - - case 3: - if (TREE_CODE (type) != POINTER_TYPE - || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE - || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) - != char_type_node)) - pedwarn ("third argument of %q+D should probably be " - "%", decl1); - break; - } - } - - /* It is intentional that this message does not mention the third - argument because it's only mentioned in an appendix of the - standard. */ - if (argct > 0 && (argct < 2 || argct > 3)) - pedwarn ("%q+D takes only zero or two arguments", decl1); + check_main_parameter_types(decl1); if (!TREE_PUBLIC (decl1)) pedwarn ("%q+D is normally a non-static function", decl1); @@ -6412,8 +6482,8 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) tree type; for (parm = DECL_ARGUMENTS (fndecl), type = current_function_prototype_arg_types; - parm || (type && (TYPE_MAIN_VARIANT (TREE_VALUE (type)) - != void_type_node)); + parm || (type && TREE_VALUE (type) != error_mark_node + && (TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node)); parm = TREE_CHAIN (parm), type = TREE_CHAIN (type)) { if (parm == 0 || type == 0 @@ -6889,7 +6959,6 @@ c_push_function_context (struct function *f) p->returns_null = current_function_returns_null; p->returns_abnormally = current_function_returns_abnormally; p->warn_about_return_type = warn_about_return_type; - p->extern_inline = current_extern_inline; } /* Restore the variables used during compilation of a C function. */ @@ -6918,7 +6987,6 @@ c_pop_function_context (struct function *f) current_function_returns_null = p->returns_null; current_function_returns_abnormally = p->returns_abnormally; warn_about_return_type = p->warn_about_return_type; - current_extern_inline = p->extern_inline; f->language = NULL; }