From: jsm28 Date: Sun, 26 Apr 2009 13:40:19 +0000 (+0000) Subject: PR c/39556 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=551ed71acf2df41550eab28d484fbcc7fca8d5c6;p=thirdparty%2Fgcc.git PR c/39556 * c-tree.h (enum c_inline_static_type): New. (record_inline_static): Declare. * c-decl.c (struct c_inline_static, c_inline_statics, record_inline_static, check_inline_statics): New. (pop_file_scope): Call check_inline_statics. (start_decl): Call record_inline_static instead of pedwarning directly for static in inline function. * c-typeck.c (build_external_ref): Call record_inline_static instead of pedwarning directly for static referenced in inline function. testsuite: * gcc.dg/inline-34.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@146800 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b5887e8d48b2..26e6d31fb990 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2009-04-26 Joseph Myers + + PR c/39556 + * c-tree.h (enum c_inline_static_type): New. + (record_inline_static): Declare. + * c-decl.c (struct c_inline_static, c_inline_statics, + record_inline_static, check_inline_statics): New. + (pop_file_scope): Call check_inline_statics. + (start_decl): Call record_inline_static instead of pedwarning + directly for static in inline function. + * c-typeck.c (build_external_ref): Call record_inline_static + instead of pedwarning directly for static referenced in inline + function. + 2009-04-26 Steven Bosscher * df-scan.c (df_insn_rescan): Salvage insn's LUID if the insn is diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 7732d5aba1d3..b87fee543425 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -393,6 +393,32 @@ static GTY((deletable)) struct c_binding *binding_freelist; t_->to##_last = f_->from##_last; \ } while (0) +/* A c_inline_static structure stores details of a static identifier + referenced in a definition of a function that may be an inline + definition if no subsequent declaration of that function uses + "extern" or does not use "inline". */ + +struct GTY((chain_next ("%h.next"))) c_inline_static { + /* The location for a diagnostic. */ + location_t location; + + /* The function that may be an inline definition. */ + tree function; + + /* The object or function referenced. */ + tree static_decl; + + /* What sort of reference this is. */ + enum c_inline_static_type type; + + /* The next such structure or NULL. */ + struct c_inline_static *next; +}; + +/* List of static identifiers used or referenced in functions that may + be inline definitions. */ +static GTY(()) struct c_inline_static *c_inline_statics; + /* True means unconditionally make a BLOCK for the next scope pushed. */ static bool keep_next_level_flag; @@ -555,6 +581,53 @@ c_finish_incomplete_decl (tree decl) } } +/* Record that inline function FUNC contains a reference (location + LOC) to static DECL (file-scope or function-local according to + TYPE). */ + +void +record_inline_static (location_t loc, tree func, tree decl, + enum c_inline_static_type type) +{ + struct c_inline_static *csi = GGC_NEW (struct c_inline_static); + csi->location = loc; + csi->function = func; + csi->static_decl = decl; + csi->type = type; + csi->next = c_inline_statics; + c_inline_statics = csi; +} + +/* Check for references to static declarations in inline functions at + the end of the translation unit and diagnose them if the functions + are still inline definitions. */ + +static void +check_inline_statics (void) +{ + struct c_inline_static *csi; + for (csi = c_inline_statics; csi; csi = csi->next) + { + if (DECL_EXTERNAL (csi->function)) + switch (csi->type) + { + case csi_internal: + pedwarn (csi->location, 0, + "%qD is static but used in inline function %qD " + "which is not static", csi->static_decl, csi->function); + break; + case csi_modifiable: + pedwarn (csi->location, 0, + "%q+D is static but declared in inline function %qD " + "which is not static", csi->static_decl, csi->function); + break; + default: + gcc_unreachable (); + } + } + c_inline_statics = NULL; +} + /* The Objective-C front-end often needs to determine the current scope. */ void * @@ -944,6 +1017,8 @@ pop_file_scope (void) still works without it. */ finish_fname_decls (); + check_inline_statics (); + /* This is the point to write out a PCH if we're doing that. In that case we do not want to do anything else. */ if (pch_file) @@ -3324,9 +3399,8 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, && !TREE_READONLY (decl) && DECL_DECLARED_INLINE_P (current_function_decl) && DECL_EXTERNAL (current_function_decl)) - pedwarn (input_location, 0, - "%q+D is static but declared in inline function %qD " - "which is not static", decl, current_function_decl); + record_inline_static (input_location, current_function_decl, + decl, csi_modifiable); /* Add this decl to the current scope. TEM may equal DECL or it may be a previous decl of the same name. */ diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 64e491e1e33a..0bfcdfe387ae 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -467,6 +467,18 @@ struct c_enum_contents int enum_overflow; }; +/* A type of reference to a static identifier in an inline + function. */ +enum c_inline_static_type { + /* Identifier with internal linkage used in function that may be an + inline definition (i.e., file-scope static). */ + csi_internal, + /* Modifiable object with static storage duration defined in + function that may be an inline definition (i.e., local + static). */ + csi_modifiable +}; + /* in c-parser.c */ extern void c_parse_init (void); @@ -483,6 +495,8 @@ extern int global_bindings_p (void); extern void push_scope (void); extern tree pop_scope (void); +extern void record_inline_static (location_t, tree, tree, + enum c_inline_static_type); extern void c_init_decl_processing (void); extern void c_dup_lang_specific_decl (tree); extern void c_print_identifier (FILE *, tree, int); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index dc7d731ee02e..b2d210954070 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -2285,8 +2285,8 @@ build_external_ref (tree id, int fun, location_t loc, tree *type) && (TREE_CODE (ref) != VAR_DECL || TREE_STATIC (ref)) && ! TREE_PUBLIC (ref) && DECL_CONTEXT (ref) != current_function_decl) - pedwarn (loc, 0, "%qD is static but used in inline function %qD " - "which is not static", ref, current_function_decl); + record_inline_static (loc, current_function_decl, ref, + csi_internal); return ref; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 36b1a49511fb..79f0ff7d212a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-04-26 Joseph Myers + + PR c/39556 + * gcc.dg/inline-34.c: New test. + 2009-04-25 Joseph Myers * gcc.dg/enum-const-1.c, gcc.dg/enum-const-2.c, diff --git a/gcc/testsuite/gcc.dg/inline-34.c b/gcc/testsuite/gcc.dg/inline-34.c new file mode 100644 index 000000000000..f257792c73cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/inline-34.c @@ -0,0 +1,19 @@ +/* Diagnostics for bad references to static objects and functions from + inline definitions must take account of declarations after the + definition which make it not an inline definition. PR 39556. */ +/* { dg-do compile } */ +/* { dg-options "-std=c99 -pedantic-errors" } */ + +static int a1; +inline int f1 (void) { return a1; } +int f1 (void); + +static int a2; +inline int f2 (void) { return a2; } +extern inline int f2 (void); + +inline void f3 (void) { static int a3; } +void f3 (void); + +inline void f4 (void) { static int a4; } +extern inline void f4 (void);