This bug is a throwback to 50852 and such, where we treated a typedef variant from dependent scope as equivalent to the underlying type, which leads to crashes when we later try to instantiate that typedef outside its scope. To deal with that, I introduced strip_typedefs to remove such offending typedefs from template arguments; it seems we need to do the same things for exception-specifications.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit f98a61af4fc4d981b40eba7000bd3585003bf226 Author: Jason Merrill <ja...@redhat.com> Date: Thu Feb 15 16:06:02 2018 -0500 PR c++/84045 - ICE with typedef and noexcept. * except.c (build_noexcept_spec): Use strip_typedefs_expr. diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 669bf9f6eaf..0b46698b974 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1217,6 +1217,10 @@ build_noexcept_spec (tree expr, int complain) { gcc_assert (processing_template_decl || TREE_CODE (expr) == DEFERRED_NOEXCEPT); + if (TREE_CODE (expr) != DEFERRED_NOEXCEPT) + /* Avoid problems with a function type built with a dependent typedef + being reused in another scope (c++/84045). */ + expr = strip_typedefs_expr (expr); return build_tree_list (expr, NULL_TREE); } } diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept32.C b/gcc/testsuite/g++.dg/cpp0x/noexcept32.C new file mode 100644 index 00000000000..9a435049599 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept32.C @@ -0,0 +1,14 @@ +// PR c++/84045 +// { dg-do compile { target c++11 } } + +template <typename T> struct K { + static const bool d = true; +}; +template <typename T, typename> struct B { + typedef K<T> D; + void foo () noexcept (D::d); +}; +template <typename T> struct P { + P () noexcept (K<T>::d); +}; +P<int> p;