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

I tried to implement a remapping of the slots for TARGET_EXPRs for the
FIXME but I wasn't able to work out how to do so effectively.  Given
that I doubt this will be a common issue I felt probably easiest to
leave it for now and focus on other issues in the meantime; thoughts?

The other thing to note is that most of this function just has a single
error message always indicated by a 'goto mismatch;' but I felt that it
seemed reasonable to provide more specific error messages where we can.
But given that in the long term we probably want to replace this
function with an appropriately enhanced 'duplicate_decls' anyway maybe
it's not worth worrying about; this patch is still useful in the
meantime if only for the testcases, I hope.

-- >8 --

When merging a newly imported declaration with an existing declaration
we don't currently propagate new default arguments, which causes issues
when modularising header units.  This patch adds logic to propagate
default arguments to existing declarations on import, and error if the
defaults do not match.

        PR c++/99274

gcc/cp/ChangeLog:

        * module.cc (trees_in::is_matching_decl): Merge default
        arguments.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/default-arg-1_a.H: New test.
        * g++.dg/modules/default-arg-1_b.C: New test.
        * g++.dg/modules/default-arg-2_a.H: New test.
        * g++.dg/modules/default-arg-2_b.C: New test.
        * g++.dg/modules/default-arg-3.h: New test.
        * g++.dg/modules/default-arg-3_a.H: New test.
        * g++.dg/modules/default-arg-3_b.C: New test.

Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
---
 gcc/cp/module.cc                              | 62 ++++++++++++++++++-
 .../g++.dg/modules/default-arg-1_a.H          | 17 +++++
 .../g++.dg/modules/default-arg-1_b.C          | 26 ++++++++
 .../g++.dg/modules/default-arg-2_a.H          | 17 +++++
 .../g++.dg/modules/default-arg-2_b.C          | 28 +++++++++
 gcc/testsuite/g++.dg/modules/default-arg-3.h  | 13 ++++
 .../g++.dg/modules/default-arg-3_a.H          |  5 ++
 .../g++.dg/modules/default-arg-3_b.C          |  6 ++
 8 files changed, 171 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/default-arg-1_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/default-arg-1_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/default-arg-2_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/default-arg-2_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/default-arg-3.h
 create mode 100644 gcc/testsuite/g++.dg/modules/default-arg-3_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/default-arg-3_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f4d137b13a1..87f34bac578 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11551,8 +11551,6 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
 
          if (!same_type_p (TREE_VALUE (d_args), TREE_VALUE (e_args)))
            goto mismatch;
-
-         // FIXME: Check default values
        }
 
       /* If EXISTING has an undeduced or uninstantiated exception
@@ -11690,7 +11688,65 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
   if (!DECL_EXTERNAL (d_inner))
     DECL_EXTERNAL (e_inner) = false;
 
-  // FIXME: Check default tmpl and fn parms here
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
+    {
+      /* Merge default template arguments.  */
+      tree d_parms = DECL_INNERMOST_TEMPLATE_PARMS (decl);
+      tree e_parms = DECL_INNERMOST_TEMPLATE_PARMS (existing);
+      gcc_checking_assert (TREE_VEC_LENGTH (d_parms)
+                          == TREE_VEC_LENGTH (e_parms));
+      for (int i = 0; i < TREE_VEC_LENGTH (d_parms); ++i)
+       {
+         tree d_default = TREE_PURPOSE (TREE_VEC_ELT (d_parms, i));
+         tree& e_default = TREE_PURPOSE (TREE_VEC_ELT (e_parms, i));
+         if (e_default == NULL_TREE)
+           e_default = d_default;
+         else if (d_default != NULL_TREE
+                  && !cp_tree_equal (d_default, e_default))
+           {
+             auto_diagnostic_group d;
+             tree d_parm = TREE_VALUE (TREE_VEC_ELT (d_parms, i));
+             tree e_parm = TREE_VALUE (TREE_VEC_ELT (e_parms, i));
+             error_at (DECL_SOURCE_LOCATION (d_parm),
+                       "conflicting default argument for %#qD", d_parm);
+             inform (DECL_SOURCE_LOCATION (e_parm),
+                     "existing default declared here");
+             return false;
+           }
+       }
+    }
+
+  if (TREE_CODE (d_inner) == FUNCTION_DECL)
+    {
+      /* Merge default function arguments.  */
+      tree d_parm = FUNCTION_FIRST_USER_PARMTYPE (d_inner);
+      tree e_parm = FUNCTION_FIRST_USER_PARMTYPE (e_inner);
+      int i = 0;
+      for (; d_parm && d_parm != void_list_node;
+          d_parm = TREE_CHAIN (d_parm), e_parm = TREE_CHAIN (e_parm), ++i)
+       {
+         tree d_default = TREE_PURPOSE (d_parm);
+         tree& e_default = TREE_PURPOSE (e_parm);
+         if (e_default == NULL_TREE)
+           e_default = d_default;
+         else if (d_default != NULL_TREE
+                  && !cp_tree_equal (d_default, e_default)
+                  /* FIXME: We need to remap the target to match the existing
+                     parms so that cp_tree_equal works correctly, as with
+                     break_out_target_exprs.  */
+                  && !(TREE_CODE (d_default) == TARGET_EXPR
+                       && TREE_CODE (e_default) == TARGET_EXPR))
+           {
+             auto_diagnostic_group d;
+             error_at (get_fndecl_argument_location (d_inner, i),
+                       "conflicting default argument for parameter %P of %#qD",
+                       i, decl);
+             inform (get_fndecl_argument_location (e_inner, i),
+                     "existing default declared here");
+             return false;
+           }
+       }
+    }
 
   return true;
 }
diff --git a/gcc/testsuite/g++.dg/modules/default-arg-1_a.H 
b/gcc/testsuite/g++.dg/modules/default-arg-1_a.H
new file mode 100644
index 00000000000..65334930f74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/default-arg-1_a.H
@@ -0,0 +1,17 @@
+// PR c++/99274
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+void f(int a, int b = 123);
+template <typename T> void g(T a, T b = {});
+
+template <typename T, typename U = int> struct A;
+template <typename T, int N = 5> struct B;
+
+struct S {
+  template <typename T = int> void x();
+  void y(int n = 123);
+};
+
+struct nontrivial { nontrivial(int); };
+void h(nontrivial p = nontrivial(123));
diff --git a/gcc/testsuite/g++.dg/modules/default-arg-1_b.C 
b/gcc/testsuite/g++.dg/modules/default-arg-1_b.C
new file mode 100644
index 00000000000..80822896de1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/default-arg-1_b.C
@@ -0,0 +1,26 @@
+// PR c++/99274
+// { dg-additional-options "-fmodules-ts" }
+// Propagate default args from import to existing decls
+
+void f(int a, int b);
+template <typename T> void g(T a, T b);
+template <typename T, typename U> struct A;
+template <typename T, int N> struct B;
+struct S {
+  template <typename T = int> void x();
+  void y(int n = 123);
+};
+struct nontrivial { nontrivial(int); };
+void h(nontrivial p);
+
+import "default-arg-1_a.H";
+
+template <typename = A<int>, typename = B<int>> struct Q;
+
+int main() {
+  f(1);
+  g(2);
+  h();
+  S{}.x();
+  S{}.y();
+}
diff --git a/gcc/testsuite/g++.dg/modules/default-arg-2_a.H 
b/gcc/testsuite/g++.dg/modules/default-arg-2_a.H
new file mode 100644
index 00000000000..085d4c7f792
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/default-arg-2_a.H
@@ -0,0 +1,17 @@
+// PR c++/99274
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+void f(int a, int b = 123);
+template <typename T> void g(T a, T b = 123);
+
+template <typename U = int> struct A;
+template <int N = 123> struct B;
+
+struct S {
+  template <typename T = int> void x();
+  void y(int n = 123);
+};
+
+struct nontrivial { nontrivial(int); };
+void h(nontrivial p = nontrivial(123));
diff --git a/gcc/testsuite/g++.dg/modules/default-arg-2_b.C 
b/gcc/testsuite/g++.dg/modules/default-arg-2_b.C
new file mode 100644
index 00000000000..a6cc58738c2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/default-arg-2_b.C
@@ -0,0 +1,28 @@
+// PR c++/99274
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+// Check for conflicting defaults.
+
+void f(int a, int b = 456);  // { dg-message "existing default declared here" }
+
+template <typename T>
+void g(T a, T b = {});  // { dg-message "existing default declared here" }
+
+template <typename U = double>  // { dg-message "existing default declared 
here" }
+struct A;
+
+template <int N = 456>  // { dg-message "existing default declared here" }
+struct B;
+
+struct S {
+  template <typename T = double>  // { dg-message "existing default declared 
here" }
+  void x();
+
+  void y(int n = 456);  // { dg-message "existing default declared here" }
+};
+
+struct nontrivial { nontrivial(int); };
+void h(nontrivial p = nontrivial(456));  // { dg-message "existing default 
declared here" "" { xfail *-*-* } }
+
+import "default-arg-2_a.H";
+
+// { dg-error "conflicting default argument" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/modules/default-arg-3.h 
b/gcc/testsuite/g++.dg/modules/default-arg-3.h
new file mode 100644
index 00000000000..b55a6690f4a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/default-arg-3.h
@@ -0,0 +1,13 @@
+void f(int a, int b = 123);
+template <typename T> void g(T a, T b = 123);
+
+template <typename U = int> struct A;
+template <int N = 123> struct B;
+
+struct S {
+  template <typename T = int> void x();
+  void y(int n = 123);
+};
+
+struct nontrivial { nontrivial(int); };
+void h(nontrivial p = nontrivial(123));
diff --git a/gcc/testsuite/g++.dg/modules/default-arg-3_a.H 
b/gcc/testsuite/g++.dg/modules/default-arg-3_a.H
new file mode 100644
index 00000000000..879bedce67f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/default-arg-3_a.H
@@ -0,0 +1,5 @@
+// PR c++/99274
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#include "default-arg-3.h"
diff --git a/gcc/testsuite/g++.dg/modules/default-arg-3_b.C 
b/gcc/testsuite/g++.dg/modules/default-arg-3_b.C
new file mode 100644
index 00000000000..402dca6ff76
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/default-arg-3_b.C
@@ -0,0 +1,6 @@
+// PR c++/99274
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+// Don't complain about matching defaults.
+
+#include "default-arg-3.h"
+import "default-arg-3_a.H";
-- 
2.43.2

Reply via email to