Repository navigation
Spurious "unexpected function type": the enclosing class's pack reverts to its first element in a member function template declaration #172
stevensudit-corvid
started this conversation in
Issue Triage - Compilation
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Issue Summary
In the declaration of a member function template of a variadic class template, a pack expansion over the class's pack can use the first pack element in every position. Instantiating the member then fails with "template instantiation resulted in unexpected function type".
gcc and clang accept the code. I ran into it in a helper that removes duplicate types from a
std::tuple, where the pattern callsfirst_index_of<Ss, Ss...>()before it namesstd::tuple<Ss>.Reproducing Source Code
Command-line Options
cpfe --c++23 repro.cpp
Type of Issue
[Front End] This code SHOULD compile with these options.
Additional Details
The diagnostic, at 158320e (version 7.0):
The second type in the message is the declared type of
keepinsided<int, char>. It hasintwherecharbelongs.Every level from
--c++11to--c++26gives the same error, and so do the GNU, Clang and Microsoft modes.The trigger is a construct with its own potential pack-expansion context that comes before the use of
Ssin the pattern. I found three, all with the same result:tup<tup<one<>, Ss>...>withtemplate<class = int> struct one {};.tup<tup<tup<Ss...>, Ss>...>. Here the declared type istup<tup<tup<int, char>, int>, tup<tup<int, char>, int>>.--c++17and later:tup<q<(1), Ss>...>withtemplate<int, class> struct q {};.Any one of these changes makes the example compile:
tup<tup<Ss, tup<>>...>.tup<tup<tup<int>, Ss>...>.tup<>is named through an alias declared outside the class.keepis a non-template member function.keepis a member alias template or a member class template with the same pattern.keepis a free function template that expands its own pack.d<int, int>also compiles, since the two types then coincide.When the pattern is in a function parameter pack, the same wrong type shows up as a failed call:
What I saw in a
linux-gcc-debugbuild: whenscan_template_argument_listreaches the empty list, it callsabandon_potential_pack_expansion_context(lexical.c:21660), which pops the pack-expansion stack and reachesrestore_enclosing_pack_values(scope_stk.c:2276). That routine rebinds the instantiation scope's template parameters to the scope's argument list (line 2296), which pointsSsback atint. It then callsupdate_parameter_pack_symbol_valuesonly if the entry now on top of the stack has aninstantiation_descr(line 2307). At that point the top entry has none and the entry below it has one, soSsstays on the first element for the rest of the pattern. The nested expansion gets there throughadvance_to_next_pack_element, with the stack in the same state. I have not traced why a non-template member function in the same position is unaffected.Two earlier entries in Changes are in the same area: EDGcpfe/13643 (5/17/13, "Variadic template issue with member function templates and enclosing packs") and EDGcpfe/17028 (4/14/16, "Incorrect expansion of nested pack expansion"). The example from 13643 compiles.
nvcc 13.3, which embeds EDG 6.8, rejects the five-line file with the same message, so this is not new in 7.0.
Reproducing (Standard) Configuration(s)
linux-gcc-release
Reproducing (Non-standard) Configuration
No response
I acknowledge that:
LICENSE.txtfile in my.zipor.tar.gzupload. If I included aLICENSE.txtfile, any tests created using the reproducing source code will be governed by the terms of the license I provided instead.All reactions