diff options
author | Nathaniel Shead <nathanieloshead@gmail.com> | 2024-08-19 16:38:41 +1000 |
---|---|---|
committer | Nathaniel Shead <nathanieloshead@gmail.com> | 2024-09-27 13:49:23 +1000 |
commit | af4471cb422a867f1877c7c08bb63fa75a8888fe (patch) | |
tree | 6b4ede63935b0d3ead4083163a26e0a4b6ce460f /gcc | |
parent | 3471ae37200bd8154084334204a6f72a5bbae974 (diff) | |
download | gcc-af4471cb422a867f1877c7c08bb63fa75a8888fe.zip gcc-af4471cb422a867f1877c7c08bb63fa75a8888fe.tar.gz gcc-af4471cb422a867f1877c7c08bb63fa75a8888fe.tar.bz2 |
c++: Update decl_linkage for C++11
Currently modules code uses a variety of ad-hoc methods to attempt to
determine whether an entity has internal linkage, which leads to
inconsistencies and some correctness issues as different edge cases are
neglected. While investigating this I discovered 'decl_linkage', but it
doesn't seem to have been updated to account for the C++11 clarification
that all entities declared in an anonymous namespace are internal.
I'm not convinced that even in C++98 it was intended that e.g. types in
anonymous namespaces should be external, but some tests in the testsuite
rely on this, so for compatibility I restricted those modifications to
C++11 and later.
This should have relatively minimal impact as not much seems to actually
rely on decl_linkage, but does change the mangling of symbols in
anonymous namespaces slightly. Previously, we had
namespace {
int x; // mangled as '_ZN12_GLOBAL__N_11xE'
static int y; // mangled as '_ZN12_GLOBAL__N_1L1yE'
}
but with this patch the x is now mangled like y (with the extra 'L').
For contrast, Clang currently mangles neither x nor y with the 'L'.
Since this only affects internal-linkage entities I don't believe this
should break ABI in any observable fashion.
gcc/cp/ChangeLog:
* name-lookup.cc (do_namespace_alias): Propagate TREE_PUBLIC for
namespace aliases.
* tree.cc (decl_linkage): Update rules for C++11.
gcc/testsuite/ChangeLog:
* g++.dg/modules/mod-sym-4.C: Update test to account for
non-static internal-linkage variables new mangling.
Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/name-lookup.cc | 1 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 92 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/mod-sym-4.C | 4 |
3 files changed, 60 insertions, 37 deletions
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index c7a693e..50e169e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -6610,6 +6610,7 @@ do_namespace_alias (tree alias, tree name_space) DECL_NAMESPACE_ALIAS (alias) = name_space; DECL_EXTERNAL (alias) = 1; DECL_CONTEXT (alias) = FROB_CONTEXT (current_scope ()); + TREE_PUBLIC (alias) = TREE_PUBLIC (DECL_CONTEXT (alias)); set_originating_module (alias); pushdecl (alias); diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index e8d8b2a..0a7a56c 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -5841,7 +5841,7 @@ char_type_p (tree type) || same_type_p (type, wchar_type_node)); } -/* Returns the kind of linkage associated with the indicated DECL. Th +/* Returns the kind of linkage associated with the indicated DECL. The value returned is as specified by the language standard; it is independent of implementation details regarding template instantiation, etc. For example, it is possible that a declaration @@ -5858,53 +5858,75 @@ decl_linkage (tree decl) linkage first, and then transform that into a concrete implementation. */ - /* Things that don't have names have no linkage. */ - if (!DECL_NAME (decl)) - return lk_none; + /* An explicit type alias has no linkage. */ + if (TREE_CODE (decl) == TYPE_DECL + && !DECL_IMPLICIT_TYPEDEF_P (decl) + && !DECL_SELF_REFERENCE_P (decl)) + { + /* But this could be a typedef name for linkage purposes, in which + case we're interested in the linkage of the main decl. */ + if (decl == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl)))) + decl = TYPE_MAIN_DECL (TREE_TYPE (decl)); + else + return lk_none; + } - /* Fields have no linkage. */ - if (TREE_CODE (decl) == FIELD_DECL) + /* Namespace-scope entities with no name usually have no linkage. */ + if (NAMESPACE_SCOPE_P (decl) + && (!DECL_NAME (decl) || IDENTIFIER_ANON_P (DECL_NAME (decl)))) + { + if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl))) + /* This entity has a typedef name for linkage purposes. */; + else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11) + /* An anonymous namespace has internal linkage since C++11. */ + return lk_internal; + else + return lk_none; + } + + /* Fields and parameters have no linkage. */ + if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == PARM_DECL) return lk_none; - /* Things in local scope do not have linkage. */ + /* Things in block scope do not have linkage. */ if (decl_function_context (decl)) return lk_none; + /* Things in class scope have the linkage of their owning class. */ + if (tree ctype = DECL_CLASS_CONTEXT (decl)) + return decl_linkage (TYPE_NAME (ctype)); + + /* Anonymous namespaces don't provide internal linkage in C++98, + but otherwise consider such declarations to be internal. */ + if (cxx_dialect >= cxx11 && decl_internal_context_p (decl)) + return lk_internal; + + /* Templates don't properly propagate TREE_PUBLIC, consider the + template result instead. Any template that isn't a variable + or function must be external linkage by this point. */ + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + decl = DECL_TEMPLATE_RESULT (decl); + if (!decl || !VAR_OR_FUNCTION_DECL_P (decl)) + return lk_external; + } + /* Things that are TREE_PUBLIC have external linkage. */ if (TREE_PUBLIC (decl)) return lk_external; - /* maybe_thunk_body clears TREE_PUBLIC on the maybe-in-charge 'tor variants, - check one of the "clones" for the real linkage. */ - if (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl) - && DECL_CHAIN (decl) - && DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl))) - return decl_linkage (DECL_CHAIN (decl)); - - if (TREE_CODE (decl) == NAMESPACE_DECL) + /* All types have external linkage in C++98, since anonymous namespaces + didn't explicitly confer internal linkage. */ + if (TREE_CODE (decl) == TYPE_DECL && cxx_dialect < cxx11) return lk_external; - /* Linkage of a CONST_DECL depends on the linkage of the enumeration - type. */ - if (TREE_CODE (decl) == CONST_DECL) - return decl_linkage (TYPE_NAME (DECL_CONTEXT (decl))); - - /* Members of the anonymous namespace also have TREE_PUBLIC unset, but - are considered to have external linkage for language purposes, as do - template instantiations on targets without weak symbols. DECLs really - meant to have internal linkage have DECL_THIS_STATIC set. */ - if (TREE_CODE (decl) == TYPE_DECL) + /* Variables or function decls not marked as TREE_PUBLIC might still + be external linkage, such as for template instantiations on targets + without weak symbols, decls referring to internal-linkage entities, + or compiler-generated entities; in such cases, decls really meant to + have internal linkage will have DECL_THIS_STATIC set. */ + if (VAR_OR_FUNCTION_DECL_P (decl) && !DECL_THIS_STATIC (decl)) return lk_external; - if (VAR_OR_FUNCTION_DECL_P (decl)) - { - if (!DECL_THIS_STATIC (decl)) - return lk_external; - - /* Static data members and static member functions from classes - in anonymous namespace also don't have TREE_PUBLIC set. */ - if (DECL_CLASS_CONTEXT (decl)) - return lk_external; - } /* Everything else has internal linkage. */ return lk_internal; diff --git a/gcc/testsuite/g++.dg/modules/mod-sym-4.C b/gcc/testsuite/g++.dg/modules/mod-sym-4.C index fbf54d0..14fef4f 100644 --- a/gcc/testsuite/g++.dg/modules/mod-sym-4.C +++ b/gcc/testsuite/g++.dg/modules/mod-sym-4.C @@ -12,9 +12,9 @@ static void addone () {} static int x = 5; namespace { -// { dg-final { scan-assembler {_ZN12_GLOBAL__N_14frobEv:} } } +// { dg-final { scan-assembler {_ZN12_GLOBAL__N_1L4frobEv:} } } void frob () {} -// { dg-final { scan-assembler {_ZN12_GLOBAL__N_11yE:} } } +// { dg-final { scan-assembler {_ZN12_GLOBAL__N_1L1yE:} } } int y = 2; struct Bill { |