c++/modules: Handle importing an undeduced auto over a deduced auto [PR124735]

Message ID adEOglkPuoWDPemf@Thaum.localdomain
State Committed
Commit ab169d27ea39bf828378d2bf08ebd27712842caf
Headers
Series c++/modules: Handle importing an undeduced auto over a deduced auto [PR124735] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed

Commit Message

Nathaniel Shead April 4, 2026, 1:13 p.m. UTC
  Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/15?

-- >8 --

Like with implicit constexpr, we need to handle cases where we import an
function declaration with undeduced auto, but we already have a
definition available with deduced auto.  In this case we can just keep
the existing declaration's type.

	PR c++/124735

gcc/cp/ChangeLog:

	* module.cc (trees_in::is_matching_decl): Handle importing
	undeduced auto when existing is already deduced.

gcc/testsuite/ChangeLog:

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

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/module.cc                        |  6 +++++-
 gcc/testsuite/g++.dg/modules/auto-8_a.H |  7 +++++++
 gcc/testsuite/g++.dg/modules/auto-8_b.C | 15 +++++++++++++++
 3 files changed, 27 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/auto-8_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/auto-8_b.C
  

Comments

Jason Merrill April 6, 2026, 4:45 p.m. UTC | #1
On 4/4/26 9:13 AM, Nathaniel Shead wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/15?

OK.

> -- >8 --
> 
> Like with implicit constexpr, we need to handle cases where we import an
> function declaration with undeduced auto, but we already have a
> definition available with deduced auto.  In this case we can just keep
> the existing declaration's type.
> 
> 	PR c++/124735
> 
> gcc/cp/ChangeLog:
> 
> 	* module.cc (trees_in::is_matching_decl): Handle importing
> 	undeduced auto when existing is already deduced.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/modules/auto-8_a.H: New test.
> 	* g++.dg/modules/auto-8_b.C: New test.
> 
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
>   gcc/cp/module.cc                        |  6 +++++-
>   gcc/testsuite/g++.dg/modules/auto-8_a.H |  7 +++++++
>   gcc/testsuite/g++.dg/modules/auto-8_b.C | 15 +++++++++++++++
>   3 files changed, 27 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/modules/auto-8_a.H
>   create mode 100644 gcc/testsuite/g++.dg/modules/auto-8_b.C
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 6958388e454..25ffbd9eb5a 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -12650,7 +12650,9 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
>   
>         /* Similarly if EXISTING has an undeduced return type, but DECL's
>   	 is already deduced.  */
> -      if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
> +      bool e_undeduced = undeduced_auto_decl (existing);
> +      bool d_undeduced = undeduced_auto_decl (decl);
> +      if (e_undeduced && !d_undeduced)
>   	{
>   	  dump (dumper::MERGE)
>   	    && dump ("Propagating deduced return type to %N", existing);
> @@ -12659,6 +12661,8 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
>   	  DECL_SAVED_AUTO_RETURN_TYPE (existing) = TREE_TYPE (e_type);
>   	  TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
>   	}
> +      else if (d_undeduced && !e_undeduced)
> +	/* EXISTING was deduced, leave it alone.  */;
>         else if (type_uses_auto (d_ret)
>   	       && !same_type_p (TREE_TYPE (d_type), TREE_TYPE (e_type)))
>   	{
> diff --git a/gcc/testsuite/g++.dg/modules/auto-8_a.H b/gcc/testsuite/g++.dg/modules/auto-8_a.H
> new file mode 100644
> index 00000000000..a0a5cacd995
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/auto-8_a.H
> @@ -0,0 +1,7 @@
> +// PR c++/124735
> +// { dg-additional-options "-fmodule-header" }
> +// { dg-module-cmi {} }
> +
> +struct S {
> +  auto foo();
> +};
> diff --git a/gcc/testsuite/g++.dg/modules/auto-8_b.C b/gcc/testsuite/g++.dg/modules/auto-8_b.C
> new file mode 100644
> index 00000000000..bd749228a04
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/auto-8_b.C
> @@ -0,0 +1,15 @@
> +// PR c++/124735
> +// { dg-additional-options "-fmodules" }
> +
> +struct S {
> +  auto foo();
> +};
> +
> +auto S::foo() { return 123; }
> +auto pfn = &S::foo;
> +
> +import "auto-8_a.H";
> +
> +int main() {
> +  return S{}.foo() != 123;
> +}
  

Patch

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 6958388e454..25ffbd9eb5a 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12650,7 +12650,9 @@  trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
 
       /* Similarly if EXISTING has an undeduced return type, but DECL's
 	 is already deduced.  */
-      if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
+      bool e_undeduced = undeduced_auto_decl (existing);
+      bool d_undeduced = undeduced_auto_decl (decl);
+      if (e_undeduced && !d_undeduced)
 	{
 	  dump (dumper::MERGE)
 	    && dump ("Propagating deduced return type to %N", existing);
@@ -12659,6 +12661,8 @@  trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
 	  DECL_SAVED_AUTO_RETURN_TYPE (existing) = TREE_TYPE (e_type);
 	  TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
 	}
+      else if (d_undeduced && !e_undeduced)
+	/* EXISTING was deduced, leave it alone.  */;
       else if (type_uses_auto (d_ret)
 	       && !same_type_p (TREE_TYPE (d_type), TREE_TYPE (e_type)))
 	{
diff --git a/gcc/testsuite/g++.dg/modules/auto-8_a.H b/gcc/testsuite/g++.dg/modules/auto-8_a.H
new file mode 100644
index 00000000000..a0a5cacd995
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-8_a.H
@@ -0,0 +1,7 @@ 
+// PR c++/124735
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+struct S {
+  auto foo();
+};
diff --git a/gcc/testsuite/g++.dg/modules/auto-8_b.C b/gcc/testsuite/g++.dg/modules/auto-8_b.C
new file mode 100644
index 00000000000..bd749228a04
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-8_b.C
@@ -0,0 +1,15 @@ 
+// PR c++/124735
+// { dg-additional-options "-fmodules" }
+
+struct S {
+  auto foo();
+};
+
+auto S::foo() { return 123; }
+auto pfn = &S::foo;
+
+import "auto-8_a.H";
+
+int main() {
+  return S{}.foo() != 123;
+}