summaryrefslogtreecommitdiffstats
path: root/gcc/c-decl.c
diff options
context:
space:
mode:
authorgeoffk <geoffk@138bc75d-0d04-0410-961f-82ee72b054a4>2006-11-01 04:47:30 +0000
committergeoffk <geoffk@138bc75d-0d04-0410-961f-82ee72b054a4>2006-11-01 04:47:30 +0000
commitc42cc79ee514555fad2c8bad93f814600c971e72 (patch)
treecf167878872183d2722b5e3979810401a81da5d0 /gcc/c-decl.c
parentcd29ee4b5a1b281f08bdbf32878efed5285aca6d (diff)
downloadppe42-gcc-c42cc79ee514555fad2c8bad93f814600c971e72.tar.gz
ppe42-gcc-c42cc79ee514555fad2c8bad93f814600c971e72.zip
* 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.c127
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;
}
OpenPOWER on IntegriCloud