diff mbox series

[02/10] c++: Update decl_linkage for C++11

Message ID 66f1fd3f.a70a0220.10bbdd.083b@mx.google.com
State New
Headers show
Series c++/modules: Implement P1815 "Translation-unit-local entities" | expand

Commit Message

Nathaniel Shead Sept. 23, 2024, 11:43 p.m. UTC
This patch intends no change in functionality apart from the mangling
difference noted; more tests are in patch 4 of this series, which adds a
way to actually check what the linkage of decl_linkage provides more
directly.

Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

-- >8 --

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>
---
 gcc/cp/name-lookup.cc                    |  1 +
 gcc/cp/tree.cc                           | 92 +++++++++++++++---------
 gcc/testsuite/g++.dg/modules/mod-sym-4.C |  4 +-
 3 files changed, 60 insertions(+), 37 deletions(-)

Comments

Jason Merrill Sept. 24, 2024, 5:36 p.m. UTC | #1
On 9/23/24 7:43 PM, Nathaniel Shead wrote:
> This patch intends no change in functionality apart from the mangling
> difference noted; more tests are in patch 4 of this series, which adds a
> way to actually check what the linkage of decl_linkage provides more
> directly.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> 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>
> ---
>   gcc/cp/name-lookup.cc                    |  1 +
>   gcc/cp/tree.cc                           | 92 +++++++++++++++---------
>   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 c7a693e02d5..50e169eca43 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 f43febed124..28e14295de4 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -5840,7 +5840,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
> @@ -5857,53 +5857,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.  */

Perhaps we should move is_naming_typedef_decl out of dwarf2out.cc...

Anyway, the patch is OK.

Jason
diff mbox series

Patch

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index c7a693e02d5..50e169eca43 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 f43febed124..28e14295de4 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5840,7 +5840,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
@@ -5857,53 +5857,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 fbf54d00171..14fef4fe253 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
 {