Hi, this patch implements the idea. It uses "<anon>" for anonymous namespace types and updates ipa-devirt to rely on it (and also sanity check that). The patch has bootstrapped/regtested powerpc64le-linux, will commit it tomorrow if there are no complains to unbreak the Ada LTO bootstrap.
Honza PR lto/66180 * mangle.c (mangle_decl): Mangle anonymous namespace types as "<anon>" * ipa-devirt.c (type_with_linkage): CHeck that TYPE_STUB_DECL is set; check for assembler name at LTO time. (type_in_anonymous_namespace): Remove hacks, check that all anonymous types are called "<anon>" (odr_type_p): Simplify; add check for "<anon>" (odr_subtypes_equivalent): Add odr_type_p check. * tree.c (need_assembler_name_p): Even anonymous namespace needs assembler name. * g++.dg/lto/pr66180_0.C: New testcase. * g++.dg/lto/pr66180_1.C: New testcase. Index: cp/mangle.c =================================================================== --- cp/mangle.c (revision 223628) +++ cp/mangle.c (working copy) @@ -3511,7 +3511,20 @@ if (dep) return; - id = get_mangled_id (decl); + /* During LTO we keep mangled names of TYPE_DECLs for ODR type merging. + It is not needed to assign names to anonymous namespace, but we use the + "<anon>" marker to be able to tell if type is C++ ODR type or type + produced by other language. */ + if (TREE_CODE (decl) == TYPE_DECL + && TYPE_STUB_DECL (TREE_TYPE (decl)) + && !TREE_PUBLIC (TYPE_STUB_DECL (TREE_TYPE (decl)))) + id = get_identifier ("<anon>"); + else + { + gcc_assert (TREE_CODE (decl) != TYPE_DECL + || !no_linkage_check (TREE_TYPE (decl), true)); + id = get_mangled_id (decl); + } SET_DECL_ASSEMBLER_NAME (decl, id); if (G.need_abi_warning Index: ipa-devirt.c =================================================================== --- ipa-devirt.c (revision 223629) +++ ipa-devirt.c (working copy) @@ -252,9 +252,15 @@ { /* Builtin types do not define linkage, their TYPE_CONTEXT is NULL. */ if (!TYPE_CONTEXT (t) - || !TYPE_NAME (t) || TREE_CODE (TYPE_NAME (t)) != TYPE_DECL) + || !TYPE_NAME (t) || TREE_CODE (TYPE_NAME (t)) != TYPE_DECL + || !TYPE_STUB_DECL (t)) return false; + /* In LTO do not get confused by non-C++ produced types or types built + with -fno-lto-odr-type-merigng. */ + if (in_lto_p && !DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))) + return false; + return (RECORD_OR_UNION_TYPE_P (t) || TREE_CODE (t) == ENUMERAL_TYPE); } @@ -269,18 +275,14 @@ if (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t))) { - if (DECL_ARTIFICIAL (TYPE_NAME (t))) - return true; - tree ctx = DECL_CONTEXT (TYPE_NAME (t)); - while (ctx) - { - if (TREE_CODE (ctx) == NAMESPACE_DECL) - return !TREE_PUBLIC (ctx); - if (TREE_CODE (ctx) == BLOCK) - ctx = BLOCK_SUPERCONTEXT (ctx); - else - ctx = get_containing_scope (ctx); - } + /* C++ FE uses magic <anon> as assembler names of anonymous types. + verify that this match with type_in_anonymous_namespace_p. */ +#ifdef ENABLE_CHECKING + if (in_lto_p) + gcc_assert (!strcmp ("<anon>", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (t))))); +#endif + return true; } return false; } @@ -292,14 +294,25 @@ bool odr_type_p (const_tree t) { - if (type_with_linkage_p (t) && type_in_anonymous_namespace_p (t)) - return true; /* We do not have this information when not in LTO, but we do not need to care, since it is used only for type merging. */ gcc_checking_assert (in_lto_p || flag_lto); - return (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL - && (DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))); + if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL + && (DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))) + { +#ifdef ENABLE_CHECKING + /* C++ FE uses magic <anon> as assembler names of anonymous types. + verify that this match with type_in_anonymous_namespace_p. */ + gcc_assert (!type_with_linkage_p (t) + || strcmp ("<anon>", + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))) + || type_in_anonymous_namespace_p (t)); +#endif + return true; + } + return false; } /* Return TRUE if all derived types of T are known and thus @@ -774,7 +787,7 @@ return false; /* Limit recursion: If subtypes are ODR types and we know that they are same, be happy. */ - if (!get_odr_type (t1, true)->odr_violated) + if (!odr_type_p (t1) || !get_odr_type (t1, true)->odr_violated) return true; } Index: testsuite/g++.dg/lto/pr66180_0.C =================================================================== --- testsuite/g++.dg/lto/pr66180_0.C (revision 0) +++ testsuite/g++.dg/lto/pr66180_0.C (working copy) @@ -0,0 +1,13 @@ +// { dg-lto-do link } +// { dg-lto-options { { -flto -std=c++14 -r -nostdlib } } } +#include <memory> +namespace { +class A { + int i; +}; +} +class G { + std::unique_ptr<A> foo() const; +}; +std::unique_ptr<A> G::foo() const { return std::make_unique<A>(); } + Index: testsuite/g++.dg/lto/pr66180_1.C =================================================================== --- testsuite/g++.dg/lto/pr66180_1.C (revision 0) +++ testsuite/g++.dg/lto/pr66180_1.C (working copy) @@ -0,0 +1,11 @@ +#include <memory> +namespace { +class A { + bool a; +}; +} +class H { + std::unique_ptr<A> bar() const; +}; +std::unique_ptr<A> H::bar() const { return std::make_unique<A>(); } + Index: tree.c =================================================================== --- tree.c (revision 223629) +++ tree.c (working copy) @@ -5182,8 +5182,7 @@ && DECL_NAME (decl) && decl == TYPE_NAME (TREE_TYPE (decl)) && !TYPE_ARTIFICIAL (TREE_TYPE (decl)) - && ((type_with_linkage_p (TREE_TYPE (decl)) - && !type_in_anonymous_namespace_p (TREE_TYPE (decl))) + && (type_with_linkage_p (TREE_TYPE (decl)) || TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE) && !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) return !DECL_ASSEMBLER_NAME_SET_P (decl);