On 3/10/25 9:52 AM, Nathaniel Shead wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
Or should this wait for GCC16?

-- >8 --

While looking at PR c++/119154 I noticed some more properties that we
don't stream or check properly.  This patch adds the ones we were
missing, and adds checks that the values don't clash with existing
decls.

These seem to me like properties that should be recomputed rather than streamed; aren't we already streaming the section attribute?

This comment also applies to the existing streaming of tls_model.

There's probably a lot more duplicate_decls-like work that should be
done in is_matching_decl (notably decl attributes?) but this is at least
a slight improvement to the status-quo.

gcc/cp/ChangeLog:

        * module.cc (trees_out::core_vals): Stream TLS model, section
        name, and comdat group.
        (trees_in::core_vals): Read them.
        (trees_out::decl_value): No longer need to stream TLS model.
        (trees_in::decl_value): Likewise; free symtab node of discarded
        decls when we're done with them.
        (trees_in::is_matching_decl): Add checks for corresponding TLS
        model and section name.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/attrib-3_a.C: New test.
        * g++.dg/modules/attrib-3_b.C: New test.

Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
---
  gcc/cp/module.cc                          | 104 +++++++++++++++++++---
  gcc/testsuite/g++.dg/modules/attrib-3_a.C |   9 ++
  gcc/testsuite/g++.dg/modules/attrib-3_b.C |  14 +++
  3 files changed, 117 insertions(+), 10 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/modules/attrib-3_a.C
  create mode 100644 gcc/testsuite/g++.dg/modules/attrib-3_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 8e0fa3c5bfc..9aa86c939f6 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6399,6 +6399,9 @@ trees_out::core_vals (tree t)
/* Decls. */
      case VAR_DECL:
+      if (streaming_p ())
+       if (CP_DECL_THREAD_LOCAL_P (t))
+         u (decl_tls_model (t));
        if (DECL_CONTEXT (t)
          && TREE_CODE (DECL_CONTEXT (t)) != FUNCTION_DECL)
        {
@@ -6691,6 +6694,22 @@ trees_out::core_vals (tree t)
        break;
      }
+ if (VAR_OR_FUNCTION_DECL_P (t)
+      && (DECL_EXTERNAL (t) || TREE_PUBLIC (t) || TREE_STATIC (t)))
+    {
+      if (streaming_p ())
+       {
+         const char *name = DECL_SECTION_NAME (t);
+         size_t len = name ? strlen (name) : 0;
+         str (name, len);
+       }
+
+      tree comdat_group = NULL_TREE;
+      if (DECL_ONE_ONLY (t))
+       comdat_group = symtab_node::get (t)->get_comdat_group ();
+      WT (comdat_group);
+    }
+
    if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
      {
        /* We want to stream the type of a expression-like nodes /after/
@@ -6933,6 +6952,11 @@ trees_in::core_vals (tree t)
/* Decls. */
      case VAR_DECL:
+      if (CP_DECL_THREAD_LOCAL_P (t))
+       {
+         enum tls_model model = tls_model (u());
+         set_decl_tls_model (t, model);
+       }
        if (DECL_CONTEXT (t)
          && TREE_CODE (DECL_CONTEXT (t)) != FUNCTION_DECL)
        {
@@ -7227,6 +7251,23 @@ trees_in::core_vals (tree t)
        break;
      }
+ if (VAR_OR_FUNCTION_DECL_P (t)
+      && (DECL_EXTERNAL (t) || TREE_PUBLIC (t) || TREE_STATIC (t)))
+    {
+      size_t section_len = 0;
+      const char *section_name = str (&section_len);
+      if (section_len)
+       set_decl_section_name (t, section_name);
+
+      if (tree comdat_group = tree_node ())
+       {
+         if (TREE_CODE (t) == FUNCTION_DECL)
+           cgraph_node::get_create (t)->set_comdat_group (comdat_group);
+         else
+           varpool_node::get_create (t)->set_comdat_group (comdat_group);
+       }
+    }
+
    if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
      {
        tree type = tree_node ();
@@ -8316,9 +8357,6 @@ trees_out::decl_value (tree decl, depset *dep)
                                   decl, cloned_p ? "" : "not ");
      }
- if (streaming_p () && VAR_P (decl) && CP_DECL_THREAD_LOCAL_P (decl))
-    u (decl_tls_model (decl));
-
    if (streaming_p ())
      dump (dumper::TREE) && dump ("Written decl:%d %C:%N", tag,
                                 TREE_CODE (decl), decl);
@@ -8757,6 +8795,12 @@ trees_in::decl_value ()
            DECL_CONTEXT (parm) = e_inner;
        }
+ /* We will not need to track the comdat group etc of the
+        to-be-discarded decl, so remove it from the symbol table.  */
+      if (VAR_OR_FUNCTION_DECL_P (inner))
+       if (struct symtab_node *snode = symtab_node::get (inner))
+         snode->remove ();
+
        /* And our result is the existing node.  */
        decl = existing;
      }
@@ -8802,13 +8846,6 @@ trees_in::decl_value ()
        }
      }
- if (VAR_P (decl) && CP_DECL_THREAD_LOCAL_P (decl))
-    {
-      enum tls_model model = tls_model (u ());
-      if (is_new)
-       set_decl_tls_model (decl, model);
-    }
-
    if (!NAMESPACE_SCOPE_P (inner)
        && ((TREE_CODE (inner) == TYPE_DECL
           && !is_typedef
@@ -12098,6 +12135,53 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
    if (!DECL_EXTERNAL (d_inner))
      DECL_EXTERNAL (e_inner) = false;
+ if (VAR_P (d_inner))
+    {
+      if (CP_DECL_THREAD_LOCAL_P (d_inner) != CP_DECL_THREAD_LOCAL_P (e_inner))
+       {
+         auto_diagnostic_group d;
+         error_at (DECL_SOURCE_LOCATION (decl),
+                   "conflicting %<thread_local%> for %#qD", decl);
+         inform (DECL_SOURCE_LOCATION (existing), "existing declaration here");
+         return false;
+       }
+      if (CP_DECL_THREAD_LOCAL_P (d_inner)
+         && decl_tls_model (d_inner) != decl_tls_model (e_inner))
+       {
+         auto_diagnostic_group d;
+         error_at (DECL_SOURCE_LOCATION (decl),
+                   "conflicting TLS model %qs for %q#D",
+                   tls_model_names[decl_tls_model (d_inner)], decl);
+         inform (DECL_SOURCE_LOCATION (existing),
+                 "existing declaration here as %qs",
+                 tls_model_names[decl_tls_model (e_inner)]);
+         return false;
+       }
+    }
+
+  if (VAR_OR_FUNCTION_DECL_P (d_inner))
+    {
+      if (DECL_SECTION_NAME (d_inner) != DECL_SECTION_NAME (e_inner))
+       {
+         auto_diagnostic_group d;
+         if (DECL_SECTION_NAME (d_inner))
+           error_at (DECL_SOURCE_LOCATION (decl),
+                     "conflicting section %qs for %q#D",
+                     DECL_SECTION_NAME (d_inner), decl);
+         else
+           error_at (DECL_SOURCE_LOCATION (decl),
+                     "conflicting section for %q#D", decl);
+         if (DECL_SECTION_NAME (e_inner))
+           inform (DECL_SOURCE_LOCATION (existing),
+                   "existing declaration here in section %qs",
+                   DECL_SECTION_NAME (e_inner));
+         else
+           inform (DECL_SOURCE_LOCATION (existing),
+                   "existing declaration here with no section");
+         return false;
+       }
+    }
+
    if (TREE_CODE (decl) == TEMPLATE_DECL)
      {
        /* Merge default template arguments.  */
diff --git a/gcc/testsuite/g++.dg/modules/attrib-3_a.C 
b/gcc/testsuite/g++.dg/modules/attrib-3_a.C
new file mode 100644
index 00000000000..ea265762cbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/attrib-3_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules" }
+
+export module M;
+export extern "C++" {
+  inline void a() __attribute__((section("bar")));
+  inline void a() {}
+
+  inline void b() {}
+}
diff --git a/gcc/testsuite/g++.dg/modules/attrib-3_b.C 
b/gcc/testsuite/g++.dg/modules/attrib-3_b.C
new file mode 100644
index 00000000000..67c78567883
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/attrib-3_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules" }
+// { dg-error "conflicting section" "" { target *-*-* } 0 }
+
+inline void a() {}  // { dg-message "here" }
+
+inline void b() __attribute__((section("qux")));
+inline void b() {}  // { dg-message "here" }
+
+import M;
+
+int main() {
+  a();
+  b();
+}

Reply via email to