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; }