summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog29
-rw-r--r--gcc/c-decl.c127
-rw-r--r--gcc/c-tree.h1
-rw-r--r--gcc/c-typeck.c11
-rw-r--r--gcc/testsuite/ChangeLog15
-rw-r--r--gcc/testsuite/gcc.dg/inline-10.c2
-rw-r--r--gcc/testsuite/gcc.dg/inline-13.c56
-rw-r--r--gcc/testsuite/gcc.dg/inline-14.c23
-rw-r--r--gcc/testsuite/gcc.dg/inline-15.c7
-rw-r--r--gcc/testsuite/gcc.dg/inline-16.c21
-rw-r--r--gcc/testsuite/gcc.dg/inline6.c14
-rw-r--r--gcc/testsuite/gcc.dg/inline7.c9
12 files changed, 268 insertions, 47 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 65b835a337c..0b9caa31f2e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,32 @@
+2006-10-31 Geoffrey Keating <geoffk@apple.com>
+
+ * 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.
+
2006-10-31 Roger Sayle <roger@eyesopen.com>
PR middle-end/23470
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;
}
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index 4bc4928ff1d..5785e1cb96f 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -384,7 +384,6 @@ struct language_function GTY(())
int returns_null;
int returns_abnormally;
int warn_about_return_type;
- int extern_inline;
};
/* Save lists of labels used or defined in particular contexts.
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 2534c25e75d..30b438260c6 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -2109,6 +2109,17 @@ build_external_ref (tree id, int fun, location_t loc)
if (context != 0 && context != current_function_decl)
DECL_NONLOCAL (ref) = 1;
}
+ /* C99 6.7.4p3: An inline definition of a function with external
+ linkage ... shall not contain a reference to an identifier with
+ internal linkage. */
+ else if (current_function_decl != 0
+ && DECL_DECLARED_INLINE_P (current_function_decl)
+ && DECL_EXTERNAL (current_function_decl)
+ && VAR_OR_FUNCTION_DECL_P (ref)
+ && (TREE_CODE (ref) != VAR_DECL || TREE_STATIC (ref))
+ && ! TREE_PUBLIC (ref))
+ pedwarn ("%H%qD is static but used in inline function %qD "
+ "which is not static", &loc, ref, current_function_decl);
return ref;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e5457e0eff2..479113bda1b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,18 @@
+2006-10-31 Geoffrey Keating <geoffk@apple.com>
+
+ * gcc.dg/inline-16.c: New.
+
+ PR 16622
+ * gcc.dg/inline-10.c (main): Don't declare 'main' inline without
+ defining it.
+ * gcc.dg/inline-13.c: New.
+ * gcc.dg/inline-14.c: New.
+ * gcc.dg/inline-15.c: New.
+
+ PR 11377
+ * gcc.dg/inline6.c: New.
+ * gcc.dg/inline7.c: New.
+
2006-10-31 Roger Sayle <roger@eyesopen.com>
PR middle-end/23470
diff --git a/gcc/testsuite/gcc.dg/inline-10.c b/gcc/testsuite/gcc.dg/inline-10.c
index ed6851a615b..f7a7592a6a9 100644
--- a/gcc/testsuite/gcc.dg/inline-10.c
+++ b/gcc/testsuite/gcc.dg/inline-10.c
@@ -3,4 +3,4 @@
/* { dg-do compile } */
/* { dg-options "-std=gnu99 -ffreestanding -pedantic-errors" } */
-inline int main (void);
+inline int main (void) { return 1; }
diff --git a/gcc/testsuite/gcc.dg/inline-13.c b/gcc/testsuite/gcc.dg/inline-13.c
new file mode 100644
index 00000000000..62a898c3c10
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/inline-13.c
@@ -0,0 +1,56 @@
+/* Verify basic C99 inline functionality. */
+/* { dg-do compile } */
+/* { dg-options "-std=c99" } */
+/* { dg-final { scan-assembler-not "dontgenerate" } } */
+/* { dg-final { scan-assembler "func1" } } */
+/* { dg-final { scan-assembler "func2" } } */
+/* { dg-final { scan-assembler "func3" } } */
+/* { dg-final { scan-assembler "func4" } } */
+/* { dg-final { scan-assembler "func5" } } */
+/* { dg-final { scan-assembler "func6" } } */
+/* { dg-final { scan-assembler "func7" } } */
+/* { dg-final { scan-assembler "func8" } } */
+/* { dg-final { scan-assembler "func9" } } */
+
+inline int dontgenerate1 (void)
+{
+ return 1;
+}
+
+inline int dontgenerate2 (void);
+inline int dontgenerate2 (void)
+{
+ return 2;
+}
+
+inline int dontgenerate3 (void)
+{
+ return 3;
+}
+inline int dontgenerate3 (void);
+
+extern inline int func1 (void) { return 1; }
+
+extern inline int func2 (void);
+inline int func2 (void) { return 2; }
+
+inline int func3 (void) { return 3; }
+extern inline int func3 (void);
+
+inline int func4 (void);
+extern inline int func4 (void) { return 4; }
+
+extern inline int func5 (void) { return 5; }
+inline int func5 (void);
+
+extern int func6 (void);
+inline int func6 (void) { return 6; }
+
+inline int func7 (void) { return 7; }
+extern int func7 (void);
+
+inline int func8 (void);
+extern int func8 (void) { return 8; }
+
+extern int func9 (void) { return 9; }
+inline int func9 (void);
diff --git a/gcc/testsuite/gcc.dg/inline-14.c b/gcc/testsuite/gcc.dg/inline-14.c
new file mode 100644
index 00000000000..0987c7cde7b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/inline-14.c
@@ -0,0 +1,23 @@
+/* Check that you can't redefine a C99 inline function. */
+/* { dg-do compile } */
+/* { dg-options "-std=c99" } */
+
+extern inline int func1 (void)
+{ /* { dg-error "previous definition" } */
+ return 1;
+}
+
+inline int func1 (void)
+{ /* { dg-error "redefinition" } */
+ return 1;
+}
+
+inline int func2 (void)
+{ /* { dg-error "previous definition" } */
+ return 2;
+}
+
+inline int func2 (void)
+{ /* { dg-error "redefinition" } */
+ return 2;
+}
diff --git a/gcc/testsuite/gcc.dg/inline-15.c b/gcc/testsuite/gcc.dg/inline-15.c
new file mode 100644
index 00000000000..7df8af1102e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/inline-15.c
@@ -0,0 +1,7 @@
+/* Check that an error message is produced when a C99 inline function
+ is never defined. */
+/* { dg-do compile } */
+/* { dg-options "-std=c99" } */
+
+extern inline int func1 (void); /* { dg-error "never defined" } */
+inline int func2 (void); /* { dg-error "never defined" } */
diff --git a/gcc/testsuite/gcc.dg/inline-16.c b/gcc/testsuite/gcc.dg/inline-16.c
new file mode 100644
index 00000000000..02aa1bf04a1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/inline-16.c
@@ -0,0 +1,21 @@
+/* { dg-do link } */
+/* { dg-options "-std=c99" } */
+
+static inline int
+func1(const volatile void * base, int byteOffset)
+{
+ volatile int *addr = (volatile int *)((int)base + byteOffset);
+ return *addr;
+}
+
+static inline int
+func2(int data)
+{
+ return func1(&data, 0);
+}
+
+int main(int argc, char *argv[]) {
+ int b = func2(argc);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/inline6.c b/gcc/testsuite/gcc.dg/inline6.c
new file mode 100644
index 00000000000..3b9e3e99e95
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/inline6.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+static int i;
+extern int j;
+extern inline int func1 (void) {
+ return i++; /* { dg-warning "static" } */
+}
+extern inline int func2 (void) {
+ return j++;
+}
+inline int func3 (void)
+{
+ return i++;
+}
diff --git a/gcc/testsuite/gcc.dg/inline7.c b/gcc/testsuite/gcc.dg/inline7.c
new file mode 100644
index 00000000000..54f3360b8a7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/inline7.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+extern inline void func1 (void) {
+ static int i; /* { dg-warning "static" } */
+}
+inline void func3 (void)
+{
+ static int i;
+}
OpenPOWER on IntegriCloud