diff options
author | geoffk <geoffk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-11-01 04:47:30 +0000 |
---|---|---|
committer | geoffk <geoffk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-11-01 04:47:30 +0000 |
commit | c42cc79ee514555fad2c8bad93f814600c971e72 (patch) | |
tree | cf167878872183d2722b5e3979810401a81da5d0 /gcc/c-decl.c | |
parent | cd29ee4b5a1b281f08bdbf32878efed5285aca6d (diff) | |
download | gcc-c42cc79ee514555fad2c8bad93f814600c971e72.tar.gz |
* c-decl.c (grokdeclarator): Don't set DECL_EXTERNAL on
inline static functions in c99 mode.
PR 16622
* doc/extend.texi (Inline): Update.
* c-tree.h (struct language_function): Remove field 'extern_inline'.
* c-decl.c (current_extern_inline): Delete.
(pop_scope): Adjust test for an undefined nested function.
Add warning about undeclared inline function.
(diagnose_mismatched_decls): Update comments. Disallow overriding
of inline functions in a translation unit in C99. Allow inline
declarations in C99 at any time.
(merge_decls): Boolize variables. Handle C99 'extern inline'
semantics.
(grokdeclarator): Set DECL_EXTERNAL here for functions. Handle
C99 inline semantics.
(start_function): Don't clear current_extern_inline. Don't set
DECL_EXTERNAL.
(c_push_function_context): Don't push current_extern_inline.
(c_pop_function_context): Don't restore current_extern_inline.
PR 11377
* c-typeck.c (build_external_ref): Warn about static variables
used in extern inline functions.
* c-decl.c (start_decl): Warn about static variables declared
in extern inline functions.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@118356 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c-decl.c')
-rw-r--r-- | gcc/c-decl.c | 127 |
1 files changed, 82 insertions, 45 deletions
diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 7ebb8b9c4f1..34709df5cfe 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -154,10 +154,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 +793,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 +1299,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 +1329,11 @@ 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) + || flag_isoc99) && same_translation_unit_p (newdecl, olddecl)) { error ("redefinition of %q+D", newdecl); @@ -1521,9 +1524,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 +1607,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 +1760,18 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) } } + /* In c99, 'extern' declaration before (or after) 'inline' means this + function is not DECL_EXTERNAL. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL + && (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) + && flag_isoc99) + DECL_EXTERNAL (newdecl) = 0; + if (DECL_EXTERNAL (newdecl)) { TREE_STATIC (newdecl) = TREE_STATIC (olddecl); @@ -1844,6 +1864,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 +1908,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 @@ -3282,6 +3311,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); @@ -4726,8 +4766,15 @@ 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) + DECL_EXTERNAL (decl) = (storage_class == csc_extern) == !flag_isoc99; else - DECL_EXTERNAL (decl) = 1; + DECL_EXTERNAL (decl) = !initialized; /* Record absence of global scope for `static' or `auto'. */ TREE_PUBLIC (decl) @@ -4757,11 +4804,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 +5302,15 @@ start_struct (enum tree_code code, tree name) error ("nested redefinition of %<union %E%>", name); else error ("nested redefinition of %<struct %E%>", 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 +6002,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); @@ -6108,12 +6153,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; @@ -6846,7 +6885,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. */ @@ -6875,7 +6913,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; } |