diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 9d37d255d8d..7987c01520d 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2761,16 +2761,27 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier rqual,
 {
   cp_cv_quals type_quals = TYPE_QUALS (type);
 
-  if (cp_check_qualified_type (type, type, type_quals, rqual, raises, late))
-    return type;
+  /* Canonicalize the exception specification.  */
+  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
+  /* For a complex exception specification, always create a distinct
+     non-canonical variant for simplicity.  This also prevents noexcept-specs
+     that are in terms of a function parameter from getting shared with an
+     another function.  */
+  bool complex_p = (cr && cr != noexcept_true_spec
+		    && !UNPARSED_NOEXCEPT_SPEC_P (cr));
+  if (!complex_p)
+    {
+      if (cp_check_qualified_type (type, type, type_quals, rqual, raises, late))
+	return type;
 
-  tree v = TYPE_MAIN_VARIANT (type);
-  for (; v; v = TYPE_NEXT_VARIANT (v))
-    if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late))
-      return v;
+      tree v = TYPE_MAIN_VARIANT (type);
+      for (; v; v = TYPE_NEXT_VARIANT (v))
+	if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late))
+	  return v;
+    }
 
   /* Need to build a new variant.  */
-  v = build_variant_type_copy (type);
+  tree v = build_variant_type_copy (type);
   if (!TYPE_DEPENDENT_P (v))
     /* We no longer know that it's not type-dependent.  */
     TYPE_DEPENDENT_P_VALID (v) = false;
@@ -2791,10 +2802,7 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier rqual,
       break;
     }
 
-  /* Canonicalize the exception specification.  */
-  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
-
-  if (TYPE_STRUCTURAL_EQUALITY_P (type))
+  if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_p)
     /* Propagate structural equality. */
     SET_TYPE_STRUCTURAL_EQUALITY (v);
   else if (TYPE_CANONICAL (type) != type || cr != raises || late)
@@ -2812,55 +2820,23 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier rqual,
 /* TYPE is a function or method type with a deferred exception
    specification that has been parsed to RAISES.  Fixup all the type
    variants that are affected in place.  Via decltype &| noexcept
-   tricks, the unparsed spec could have escaped into the type system.
-   The general case is hard to fixup canonical types for.  */
+   tricks, the unparsed spec could have escaped into the type system.  */
 
 void
 fixup_deferred_exception_variants (tree type, tree raises)
 {
   tree original = TYPE_RAISES_EXCEPTIONS (type);
-  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
 
   gcc_checking_assert (UNPARSED_NOEXCEPT_SPEC_P (original));
 
-  /* Though sucky, this walk will process the canonical variants
-     first.  */
-  tree prev = NULL_TREE;
   for (tree variant = TYPE_MAIN_VARIANT (type);
-       variant; prev = variant, variant = TYPE_NEXT_VARIANT (variant))
+       variant; variant = TYPE_NEXT_VARIANT (variant))
     if (TYPE_RAISES_EXCEPTIONS (variant) == original)
       {
 	gcc_checking_assert (variant != TYPE_MAIN_VARIANT (type));
 
-	if (!TYPE_STRUCTURAL_EQUALITY_P (variant))
-	  {
-	    cp_cv_quals var_quals = TYPE_QUALS (variant);
-	    cp_ref_qualifier rqual = type_memfn_rqual (variant);
-
-	    /* If VARIANT would become a dup (cp_check_qualified_type-wise)
-	       of an existing variant in the variant list of TYPE after its
-	       exception specification has been parsed, elide it.  Otherwise,
-	       build_cp_fntype_variant could use it, leading to "canonical
-	       types differ for identical types."  */
-	    tree v = TYPE_MAIN_VARIANT (type);
-	    for (; v; v = TYPE_NEXT_VARIANT (v))
-	      if (cp_check_qualified_type (v, variant, var_quals,
-					   rqual, cr, false))
-		{
-		  /* The main variant will not match V, so PREV will never
-		     be null.  */
-		  TYPE_NEXT_VARIANT (prev) = TYPE_NEXT_VARIANT (variant);
-		  break;
-		}
-	    TYPE_RAISES_EXCEPTIONS (variant) = raises;
-
-	    if (!v)
-	      v = build_cp_fntype_variant (TYPE_CANONICAL (variant),
-					   rqual, cr, false);
-	    TYPE_CANONICAL (variant) = TYPE_CANONICAL (v);
-	  }
-	else
-	  TYPE_RAISES_EXCEPTIONS (variant) = raises;
+	SET_TYPE_STRUCTURAL_EQUALITY (variant);
+	TYPE_RAISES_EXCEPTIONS (variant) = raises;
 
 	if (!TYPE_DEPENDENT_P (variant))
 	  /* We no longer know that it's not type-dependent.  */
diff --git a/gcc/testsuite/g++.dg/modules/noexcept-2_a.H b/gcc/testsuite/g++.dg/modules/noexcept-2_a.H
new file mode 100644
index 00000000000..b7144f42d7e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/noexcept-2_a.H
@@ -0,0 +1,24 @@
+// PR c++/115159
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+struct QDebug;
+
+template<class T> void f(T);
+
+template<class T> struct QList {
+  QDebug g(QList &other) noexcept(noexcept(f(other)));
+  QDebug h(QList &other) noexcept(noexcept(f(other)));
+};
+
+struct QObjectData {
+  QList<int> children;
+};
+
+struct QIODevice {
+  QObjectData d_ptr;
+};
+
+struct QDebug {
+  QDebug(QIODevice);
+};
diff --git a/gcc/testsuite/g++.dg/modules/noexcept-2_b.C b/gcc/testsuite/g++.dg/modules/noexcept-2_b.C
new file mode 100644
index 00000000000..d34c63add10
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/noexcept-2_b.C
@@ -0,0 +1,4 @@
+// PR c++/115159
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+import "noexcept-2_a.H";
