https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61825
--- Comment #7 from Jan Hubicka <hubicka at ucw dot cz> --- Hi, this patch implements necessary bits to record what symbols was declared nonzero and refuse visibility changes that would change the difference (i.e. turn it into alias, weakref or weak). Possibly we will want to check more but those are ones I can think of. Index: c-family/c-common.c =================================================================== --- c-family/c-common.c (revision 215401) +++ c-family/c-common.c (working copy) @@ -7694,6 +7694,15 @@ handle_alias_ifunc_attribute (bool is_al { tree decl = *node; + struct symtab_node *n = symtab_node::get (decl); + if (n && n->refuse_visibility_changes) + { + if (is_alias) + error ("%+D declared alias after being used", decl); + else + error ("%+D declared ifunc after being used", decl); + } + if (TREE_CODE (decl) != FUNCTION_DECL && (!is_alias || TREE_CODE (decl) != VAR_DECL)) { @@ -7808,6 +7817,10 @@ handle_weakref_attribute (tree *node, tr return NULL_TREE; } + struct symtab_node *n = symtab_node::get (*node); + if (n && n->refuse_visibility_changes) + error ("%+D declared weakref after being used", *node); + /* The idea here is that `weakref("name")' mutates into `weakref, alias("name")', and weakref without arguments, in turn, implicitly adds weak. */ Index: cgraph.h =================================================================== --- cgraph.h (revision 215401) +++ cgraph.h (working copy) @@ -346,6 +346,10 @@ public: return decl->decl_with_vis.symtab_node; } + /* Try to find a symtab node for declaration DECL and if it does not + exist or if it corresponds to an inline clone, create a new one. */ + static inline symtab_node * get_create (tree node); + /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. Return NULL if there's no such node. */ static symtab_node *get_for_asmname (const_tree asmname); @@ -394,7 +398,9 @@ public: unsigned analyzed : 1; /* Set for write-only variables. */ unsigned writeonly : 1; - + /* Visibility of symbol was used for further optimization; do not + permit further changes. */ + unsigned refuse_visibility_changes : 1; /*** Visibility and linkage flags. ***/ @@ -2519,4 +2525,12 @@ cgraph_node::mark_force_output (void) gcc_checking_assert (!global.inlined_to); } +inline symtab_node * symtab_node::get_create (tree node) +{ + if (TREE_CODE (node) == VAR_DECL) + return varpool_node::get_create (node); + else + return cgraph_node::get_create (node); +} + #endif /* GCC_CGRAPH_H */ Index: fold-const.c =================================================================== --- fold-const.c (revision 215401) +++ fold-const.c (working copy) @@ -15850,7 +15850,7 @@ tree_single_nonzero_warnv_p (tree t, boo { struct symtab_node *symbol; - symbol = symtab_node::get (base); + symbol = symtab_node::get_create (base); if (symbol) return symbol->nonzero_address (); else Index: varasm.c =================================================================== --- varasm.c (revision 215401) +++ varasm.c (working copy) @@ -5230,6 +5230,12 @@ output_constructor (tree exp, unsigned H static void mark_weak (tree decl) { + if (DECL_WEAK (decl)) + return; + + struct symtab_node *n = symtab_node::get (decl); + if (n && n->refuse_visibility_changes) + error ("%+D declared weak after being used", decl); DECL_WEAK (decl) = 1; if (DECL_RTL_SET_P (decl) Index: symtab.c =================================================================== --- symtab.c (revision 215401) +++ symtab.c (working copy) @@ -1811,9 +1811,9 @@ bool symtab_node::nonzero_address () { /* Weakrefs may be NULL when their target is not defined. */ - if (this->alias && this->weakref) + if (alias && weakref) { - if (this->analyzed) + if (analyzed) { symtab_node *target = ultimate_alias_target (); @@ -1828,7 +1828,7 @@ symtab_node::nonzero_address () could be useful to eliminate the NULL pointer checks in LTO programs. */ if (target->definition && !DECL_EXTERNAL (target->decl)) - return true; + return true; if (target->resolution != LDPR_UNKNOWN && target->resolution != LDPR_UNDEF && flag_delete_null_pointer_checks) @@ -1847,22 +1847,28 @@ symtab_node::nonzero_address () Those are handled by later check for definition. When parsing, beware the cases when WEAK attribute is added later. */ - if (!DECL_WEAK (this->decl) - && flag_delete_null_pointer_checks - && symtab->state > PARSING) - return true; + if (!DECL_WEAK (decl) + && flag_delete_null_pointer_checks) + { + refuse_visibility_changes = true; + return true; + } /* If target is defined and not extern, we know it will be output and thus it will bind to non-NULL. Play safe for flag_delete_null_pointer_checks where weak definition maye be re-defined by NULL. */ - if (this->definition && !DECL_EXTERNAL (this->decl) - && (flag_delete_null_pointer_checks || !DECL_WEAK (this->decl))) - return true; + if (definition && !DECL_EXTERNAL (decl) + && (flag_delete_null_pointer_checks || !DECL_WEAK (decl))) + { + if (!DECL_WEAK (decl)) + refuse_visibility_changes = true; + return true; + } /* As the last resort, check the resolution info. */ - if (this->resolution != LDPR_UNKNOWN - && this->resolution != LDPR_UNDEF + if (resolution != LDPR_UNKNOWN + && resolution != LDPR_UNDEF && flag_delete_null_pointer_checks) return true; return false;