Hi! On the following testcase we ICE in modified_type_die, because the search for a non-qualified variant type with the same rvalue quals etc. finds pretty randomly qualified type, while modified_type_die expects that it is either an unqualified type or (if there is no such a type) type itself. When we are looking for const qualified FUNCTION_TYPE and find instead volatile qualified FUNCTION_TYPE, then we die on an assertion that we can't subtract qualifiers from the chosen type to get to the desired type (only can add them).
The following patch makes sure we pick only the unqualified types. Bootstrapped/regtested on x86_64-linux and i686-linux with additional statistics collection which found that both the loops found such an unqualified type in all cases except for a single fntype in each of the following testcases: libstdc++-v3/testsuite/20_util/add_lvalue_reference/value.cc libstdc++-v3/testsuite/20_util/add_rvalue_reference/value.cc libstdc++-v3/testsuite/20_util/is_assignable/value.cc where we didn't find any unqualified types among the variants; previously we found type itself that way, which is what the patched compiler does too in that case (see the return lookup_type_die (type) after it or that type remains the old type). Ok for trunk? 2017-04-19 Jakub Jelinek <ja...@redhat.com> PR debug/80461 * dwarf2out.c (modified_type_die, gen_type_die_with_usage): Check for t with zero TYPE_QUALS_NO_ADDR_SPACE. * g++.dg/debug/pr80461.C: New test. --- gcc/dwarf2out.c.jj 2017-04-18 18:58:13.000000000 +0200 +++ gcc/dwarf2out.c 2017-04-19 13:05:31.109271480 +0200 @@ -12690,7 +12690,9 @@ modified_type_die (tree type, int cv_qua but try to canonicalize. */ tree main = TYPE_MAIN_VARIANT (type); for (tree t = main; t; t = TYPE_NEXT_VARIANT (t)) - if (check_base_type (t, main) && check_lang_type (t, type)) + if (TYPE_QUALS_NO_ADDR_SPACE (t) == 0 + && check_base_type (t, main) + && check_lang_type (t, type)) return lookup_type_die (t); return lookup_type_die (type); } @@ -24580,13 +24582,13 @@ gen_type_die_with_usage (tree type, dw_d but try to canonicalize. */ tree main = TYPE_MAIN_VARIANT (type); for (tree t = main; t; t = TYPE_NEXT_VARIANT (t)) - { - if (check_base_type (t, main) && check_lang_type (t, type)) - { - type = t; - break; - } - } + if (TYPE_QUALS_NO_ADDR_SPACE (t) == 0 + && check_base_type (t, main) + && check_lang_type (t, type)) + { + type = t; + break; + } } else if (TREE_CODE (type) != VECTOR_TYPE && TREE_CODE (type) != ARRAY_TYPE) --- gcc/testsuite/g++.dg/debug/pr80461.C.jj 2017-04-19 13:27:36.101829399 +0200 +++ gcc/testsuite/g++.dg/debug/pr80461.C 2017-04-19 13:27:46.618690922 +0200 @@ -0,0 +1,42 @@ +// PR debug/80461 +// { dg-do compile } +// { dg-options "-g -O" } + +template <typename> class A; +struct B +{ + template <typename T, typename U> + static bool foo (U T::*) {} +}; +template <typename, typename> class J; +template <typename T, typename U, typename V, typename... W> +class J<V (W...), U T::*> : public J<void(), U T::*> {}; +template <typename T, typename U, typename... W> +class J<void(W...), U T::*> : public B {}; +template <typename V, typename... W> struct A<V (W...)> +{ + template <typename, typename> using K = int; + template <typename L, typename = K<int, void>, typename = K<int, void>> A (L); +}; +template <typename V, typename... W> +template <typename L, typename, typename> +A<V (W...)>::A (L x) { J<V (), L>::foo (x); } +struct N; +volatile int v; + +template <class O, class P> +void +bar () +{ + O q; + A<P> f = q; + v++; +} + +void +baz () +{ + bar<int (N::*) (...) &, int()> (); + bar<int (N::*) (...) const &, int()> (); + bar<int (N::*) (...) volatile &, int()> (); +} Jakub