This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix premature diagnostics for statics in inline functions (PR 39556)


This patch fixes PR 39556, where certain declarations of and
references to static objects and functions were diagnosed in inline
functions at the point of declaration or reference, even though a
subsequent redeclaration might make the definition no longer an
"inline definition" in C99 terms and so the references no longer
constraint violations.

Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  Applied
to mainline.

2009-04-26  Joseph Myers  <joseph@codesourcery.com>

	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:
2009-04-26  Joseph Myers  <joseph@codesourcery.com>

	PR c/39556
	* gcc.dg/inline-34.c: New test.

Index: gcc/testsuite/gcc.dg/inline-34.c
===================================================================
--- gcc/testsuite/gcc.dg/inline-34.c	(revision 0)
+++ gcc/testsuite/gcc.dg/inline-34.c	(revision 0)
@@ -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);
Index: gcc/c-tree.h
===================================================================
--- gcc/c-tree.h	(revision 146789)
+++ gcc/c-tree.h	(working copy)
@@ -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);
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(revision 146789)
+++ gcc/c-decl.c	(working copy)
@@ -393,6 +393,32 @@ static GTY((deletable)) struct c_binding
   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 *declara
       && !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.  */
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 146789)
+++ gcc/c-typeck.c	(working copy)
@@ -2285,8 +2285,8 @@ build_external_ref (tree id, int fun, lo
 	   && (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;
 }

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]