In C++14 and below, the exception-specification is not part of a
function type, so we need to drop it from template arguments;
otherwise, all uses of a particular template instantiation get the
exception specification that the first use happened to have.

This patch regresses the -Wnoexcept-type warning, as in this case we
discard the exception-specification long before we get to mangling.  I
explored fixing this for a while, but it seems to require a whole new
mechanism for propagating warnings through overload resolution.  And
this warning doesn't seem to be as important as I initially thought.

Tested x86_64-pc-linux-gnu, applying to trunk.

Jason
commit 30c1bda3bd426be189e7b61844d9801605a04d49
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Oct 17 10:38:03 2017 -0400

            PR c++/77369 - wrong noexcept handling in C++14 and below
    
            * tree.c (strip_typedefs): Canonicalize TYPE_RAISES_EXCEPTIONS.

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 366f46f1506..48d40945af3 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1439,7 +1439,11 @@ strip_typedefs (tree t, bool *remove_attributes)
          is_variant = true;
 
        type = strip_typedefs (TREE_TYPE (t), remove_attributes);
-       changed = type != TREE_TYPE (t) || is_variant;
+       tree canon_spec = (flag_noexcept_type
+                          ? canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (t))
+                          : NULL_TREE);
+       changed = (type != TREE_TYPE (t) || is_variant
+                  || TYPE_RAISES_EXCEPTIONS (t) != canon_spec);
 
        for (arg_node = TYPE_ARG_TYPES (t);
             arg_node;
@@ -1498,9 +1502,8 @@ strip_typedefs (tree t, bool *remove_attributes)
                                        type_memfn_rqual (t));
          }
 
-       if (TYPE_RAISES_EXCEPTIONS (t))
-         result = build_exception_variant (result,
-                                           TYPE_RAISES_EXCEPTIONS (t));
+       if (canon_spec)
+         result = build_exception_variant (result, canon_spec);
        if (TYPE_HAS_LATE_RETURN_TYPE (t))
          TYPE_HAS_LATE_RETURN_TYPE (result) = 1;
       }
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept31.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept31.C
new file mode 100644
index 00000000000..c4c0e7dd466
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept31.C
@@ -0,0 +1,12 @@
+// PR c++/77369
+// { dg-do compile { target c++11 } }
+
+template<typename F> int caller(F f) noexcept(noexcept(f())) { f(); return 0; }
+
+void func1() noexcept { }
+
+void func2() { throw 1; }
+
+int instantiate_caller_with_func1 = caller(func1);
+
+static_assert( !noexcept(caller(func2)), "" );
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C 
b/gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C
index 8eb3be0bd61..b51d7af2b11 100644
--- a/gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C
@@ -5,7 +5,7 @@
 void foo () throw () {}                // { dg-bogus "mangled name" }
 
 template <class T>
-T bar (T x) { return x; }      // { dg-warning "mangled name" "" { target 
c++14_down } }
+T bar (T x) { return x; }
 
 void baz () {                  // { dg-bogus "mangled name" }
   return (bar (foo)) ();

Reply via email to