// https://godbolt.org/z/KhiNKJ template<template<class> class A> struct G { template<class T> using B = A<T>; template<B> static int foo(); int x = foo<42>(); }; test.cc:5:21: internal compiler error: in get_class_binding_direct, at cp/name-lookup.c:1221 5 | int x = foo<42>(); | ^ And here's a second ICE in the same general area... // https://godbolt.org/z/W3Fgku template<template<class> class A> struct G { template<class... T> using B = A<T...>; template<B> int foo(); int x = foo<42>(); }; template<class T> struct A { constexpr A(T) {} }; G<A> g; test.cc: In instantiation of 'constexpr G<A>::G()': test.cc:8:6: required from here test.cc:5:20: internal compiler error: in alias_ctad_tweaks, at cp/pt.c:28181 5 | int x = foo<42>(); | ~~~~~~~^~ Both of these are ice-on-valid-code, as far as I'm aware (relative to the C++2a draft). Bug #91365 is related.
Confirmed, is it a valid code or not?
Invalid because it passes (a) type template argument(s) to a template template parameter.
Re comment 2: My original test code was "invalid-code", but here's one I believe to be "valid-code" in C++20. // https://godbolt.org/z/dqcWeq template<template<class> class A> struct G { template<class T> using B = A<T>; template<B> static int foo(); template<int> static int foo(); int x = foo<42>(); // OK }; test.cc:7:21: internal compiler error: in get_class_binding_direct, at cp/name-lookup.c:1238 7 | int x = foo<42>(); // OK | ^ ==== If you change the `<B>` to an `<A>`, the ICE disappears, but GCC still gives a bogus error at template-definition time: // https://godbolt.org/z/Tjrnzv template<template<class> class A> struct G { template<class T> using B = A<T>; template<A> static int foo(); // #1 template<int> static int foo(); // #2 int x = foo<42>(); // OK }; test.cc:7:21: error: call of overloaded 'foo()' is ambiguous 7 | int x = foo<42>(); // OK | ^ GCC shouldn't even be trying to resolve `foo<42>()` until `G` has been instantiated; and once `G` has been instantiated with some specific `A`, this call may or may not be ambiguous (depending on whether it's possible to deduce the template arguments to foo #1 or not).
> GCC shouldn't even be trying to resolve `foo<42>()` until `G` has been instantiated. That's right. I came across this bug report when reporting such an issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97476.
The ICEs are fixed, I want to address the second testcase in comment #3.
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:84081e2c6bd43a6790f751755865cf4227adac7c commit r11-8137-g84081e2c6bd43a6790f751755865cf4227adac7c Author: Jason Merrill <jason@redhat.com> Date: Sat Apr 10 02:10:32 2021 -0400 c++: premature overload resolution [PR93085] We can't resolve the call to foo<42> before instantiation of G, because the template parameter of #1 has dependent type. But we were missing that in our dependency check, because the tree walk of DECL_TEMPLATE_PARMS doesn't look into the types of template parameters. So look at them directly. gcc/cp/ChangeLog: PR c++/93085 * pt.c (uses_outer_template_parms): Handle non-type and template template parameters specifically. gcc/testsuite/ChangeLog: PR c++/93085 * g++.dg/template/dependent-tmpl1.C: New test.
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:00a2774923c1dc5666cd26bb9b8c37b1b7dd689d commit r11-8182-g00a2774923c1dc5666cd26bb9b8c37b1b7dd689d Author: Jason Merrill <jason@redhat.com> Date: Wed Apr 14 14:14:31 2021 -0400 c++: premature overload resolution redux [PR100078] My patch for PR93085 didn't consider that a default template argument can also make a template dependent. gcc/cp/ChangeLog: PR c++/100078 PR c++/93085 * pt.c (uses_outer_template_parms): Also look at default template argument. gcc/testsuite/ChangeLog: PR c++/100078 * g++.dg/template/dependent-tmpl2.C: New test.