]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++/modules: merging fn w/ inst noexcept + deduced auto [PR125115]
authorPatrick Palka <ppalka@redhat.com>
Fri, 1 May 2026 16:38:25 +0000 (12:38 -0400)
committerPatrick Palka <ppalka@redhat.com>
Fri, 1 May 2026 16:38:25 +0000 (12:38 -0400)
Here when streaming in view_interface<int>::data() and merging it with
the in-TU version, we find that the streamed-in version already has its
noexcept instantiated _and_ its return type deduced.  is_matching_decl
has logic to update the in-TU version when that is the case, first by
propagating the instantiated noexcept.  But this is done by overwriting
the entire function type with the streamed-in one, which simultaneously
updates the return type as well.  This premature return type updating
breaks the later deduced return type checks which are partially in terms
of the original function type.

This patch fixes this by propagating the instantiated noexcept more
narrowly via build_exception_variant.  Also turn e_type into a
reference so that it's not stale after updating e_inner's TREE_TYPE.

PR c++/125115

gcc/cp/ChangeLog:

* module.cc (trees_in::is_matching_decl): Turn e_type into a
reference and use it instead of TREE_TYPE (e_inner).  Always
use build_exception_variant to propagate an already-instantiated
noexcept.

gcc/testsuite/ChangeLog:

* g++.dg/modules/auto-9.h: New test.
* g++.dg/modules/auto-9_a.H: New test.
* g++.dg/modules/auto-9_b.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/module.cc
gcc/testsuite/g++.dg/modules/auto-9.h [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/auto-9_a.H [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/auto-9_b.C [new file with mode: 0644]

index 49330312520ecf8905894dad5d7b6c780337ef48..65307628b7bab8f91ff0754bb889a0f6d9646aa9 100644 (file)
@@ -12621,7 +12621,7 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
          goto mismatch;
        }
 
-      tree e_type = TREE_TYPE (e_inner);
+      tree& e_type = TREE_TYPE (e_inner);
       tree d_type = TREE_TYPE (d_inner);
 
       for (tree e_args = TYPE_ARG_TYPES (e_type),
@@ -12660,18 +12660,13 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
              dump (dumper::MERGE)
                && dump ("Propagating instantiated noexcept to %N", existing);
              gcc_checking_assert (existing == e_inner);
-             TREE_TYPE (existing) = d_type;
+             e_type = build_exception_variant (e_type, d_spec);
 
              /* Propagate to existing clones.  */
              tree clone;
              FOR_EACH_CLONE (clone, existing)
-               {
-                 if (TREE_TYPE (clone) == e_type)
-                   TREE_TYPE (clone) = d_type;
-                 else
-                   TREE_TYPE (clone)
-                     = build_exception_variant (TREE_TYPE (clone), d_spec);
-               }
+               TREE_TYPE (clone)
+                 = build_exception_variant (TREE_TYPE (clone), d_spec);
            }
        }
       else if (!DECL_MAYBE_DELETED (d_inner)
@@ -12694,7 +12689,7 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
          gcc_checking_assert (existing == e_inner);
          FNDECL_USED_AUTO (existing) = true;
          DECL_SAVED_AUTO_RETURN_TYPE (existing) = TREE_TYPE (e_type);
-         TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
+         e_type = change_return_type (TREE_TYPE (d_type), e_type);
        }
       else if (d_undeduced && !e_undeduced)
        /* EXISTING was deduced, leave it alone.  */;
diff --git a/gcc/testsuite/g++.dg/modules/auto-9.h b/gcc/testsuite/g++.dg/modules/auto-9.h
new file mode 100644 (file)
index 0000000..ff9830a
--- /dev/null
@@ -0,0 +1,42 @@
+namespace ranges {
+struct _Begin {
+  template <typename _Tp> auto operator()(_Tp __t) { return __t.begin(); }
+};
+struct _Data {
+  template <typename _Tp> auto operator()(_Tp __t) { return __t.data(); }
+};
+inline _Begin begin;
+inline _Data data;
+struct subrange;
+template <typename _Tp> struct view_interface {
+  subrange _M_derived();
+  auto data() noexcept(noexcept(begin(_M_derived()))) { return begin(_M_derived()); }
+};
+} // namespace ranges
+struct basic_string_view {
+  basic_string_view(const char *);
+  template <typename _Range>
+  basic_string_view(_Range __r) : _M_str(ranges::data(__r)) {}
+  char *_M_str;
+} typedef string_view;
+namespace ranges {
+struct subrange : view_interface<int> {
+  char *begin();
+};
+struct split_view {
+  struct _Iterator {
+    subrange operator*();
+  };
+  template <typename _Range> split_view(_Range, _Range);
+  _Iterator begin();
+};
+namespace views {
+inline
+struct _Split {
+  template <typename _Range, typename _Pattern>
+  auto operator()(_Range, _Pattern) {
+    return split_view(0, 0);
+  }
+} split;
+} // namespace views
+} // namespace ranges
diff --git a/gcc/testsuite/g++.dg/modules/auto-9_a.H b/gcc/testsuite/g++.dg/modules/auto-9_a.H
new file mode 100644 (file)
index 0000000..bc559e8
--- /dev/null
@@ -0,0 +1,9 @@
+// PR c++/125115
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-fmodule-header" }
+
+#include "auto-9.h"
+
+inline void foo() {
+  auto x = string_view(*ranges::views::split(string_view("1.2"), '.').begin());
+}
diff --git a/gcc/testsuite/g++.dg/modules/auto-9_b.C b/gcc/testsuite/g++.dg/modules/auto-9_b.C
new file mode 100644 (file)
index 0000000..716f2b4
--- /dev/null
@@ -0,0 +1,6 @@
+// PR c++/125115
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-fmodules -fno-module-lazy" }
+
+#include "auto-9.h"
+import "auto-9_a.H";