Because attribute weakref introduces a kind of a definition, it can
only be applied to declarations of symbols that are not defined.  GCC
normally issues a warning when the attribute is applied to a defined
symbol, but PR 92799 shows that it misses some cases on which it then
leads to an ICE.

The ICE was introduced in GCC 4.5.  Prior to then, GCC accepted such
invalid definitions and silently dropped the weakref attribute.

The attached patch avoids the ICE while again dropping the invalid
attribute from the definition, except with the (now) usual warning.

Tested on x86_64-linux.

I also looked for code bases that make use of attribute weakref to
rebuild them as another test but couldn't find any.  (There are
a couple of instances in the Linux kernel but they look #ifdef'd
out).  Does anyone know of any that do use it that I could try to
build on Linux?

Martin
PR ipa/92799 - ICE on a weakref function definition followed by a declaration

gcc/testsuite/ChangeLog:

	PR ipa/92799
	* gcc.dg/attr-weakref-5.c: New test.

gcc/ChangeLog:

	PR ipa/92799
	* cgraphunit.c (process_function_and_variable_attributes): Also
	complain about weakref function definitions and drop all effects
	of the attribute.

diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index a9dd288be57..fd586366bb9 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -861,14 +861,23 @@ process_function_and_variable_attributes (cgraph_node *first,
 			" attribute have effect only on public objects");
 	}
       if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
-	  && (node->definition && !node->alias))
+	  && node->definition
+	  && (!node->alias || DECL_INITIAL (decl) != error_mark_node))
 	{
-	  warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes,
+	  /* NODE->DEFINITION && NODE->ALIAS is nonzero for valid weakref
+	     function declarations; DECL_INITIAL is non-null for invalid
+	     weakref functions that are also defined.  */
+	  warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
 		      "%<weakref%> attribute ignored"
 		      " because function is defined");
 	  DECL_WEAK (decl) = 0;
 	  DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
 						     DECL_ATTRIBUTES (decl));
+	  DECL_ATTRIBUTES (decl) = remove_attribute ("alias",
+						     DECL_ATTRIBUTES (decl));
+	  node->alias = false;
+	  node->weakref = false;
+	  node->transparent_alias = false;
 	}
       else if (lookup_attribute ("alias", DECL_ATTRIBUTES (decl))
 	  && node->definition
diff --git a/gcc/testsuite/gcc.dg/attr-weakref-5.c b/gcc/testsuite/gcc.dg/attr-weakref-5.c
new file mode 100644
index 00000000000..e2f04068230
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-weakref-5.c
@@ -0,0 +1,31 @@
+/* PR middle-end/92799 - ICE on a weakref function definition followed
+   by a declaration
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+static __attribute__ ((weakref ("bar"))) void f0 (void) { }   // { dg-warning "'weakref' attribute ignored because function is defined" }
+
+extern void f0 (void);
+
+void* use_f0 (void) { return f0; }
+
+
+static __attribute__ ((weakref ("bar"))) void f1 (void) { }   // { dg-warning "'weakref' attribute ignored because function is defined" }
+
+static void f1 (void);
+
+void* use_f1 (void) { return f1; }
+
+
+static __attribute__ ((weakref ("bar"))) void f2 (void);
+
+static void f2 (void) { }                                     // { dg-error "redefinition" }
+
+void* use_f2 (void) { return f2; }
+
+
+static __attribute__ ((weakref ("bar"))) void f3 (void);
+
+void f3 (void) { }                                            // { dg-error "redefinition" }
+
+void* use_f3 (void) { return f3; }

Reply via email to