Created attachment 27185 [details] test code #include <functional> in the following code causes compile failure. Without the include, it compiles fine: #include <type_traits> #include <functional> // without this include, it compiles template <bool... Bs_> struct Bools { static const bool value = true; }; template <typename... Ts_> struct Types { template <typename... Us, typename std::enable_if< Bools<std::is_convertible<Us, Ts_>::value...>::value, bool>::type = false> int foo(Us&&...) { return sizeof...(Us); } }; int main() { Types<int, int> t; return t.foo(1, 1); } Output: $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: /build/src/gcc-4.7-20120324/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --enable-libstdcxx-time --enable-gnu-unique-object --enable-linker-build-id --with-ppl --enable-cloog-backend=isl --enable-lto --enable-gold --enable-ld=default --enable-plugin --with-plugin-ld=ld.gold --with-linker-hash-style=gnu --disable-multilib --disable-libssp --disable-build-with-cxx --disable-build-poststage1-with-cxx --enable-checking=release Thread model: posix gcc version 4.8.0 20120407 (experimental) [trunk revision 186212] (Debian 20120407-1) $ /usr/lib/gcc-snapshot/bin/g++ -std=c++11 functional_bug.cpp functional_bug.cpp: In instantiation of 'struct Types<int, int>': functional_bug.cpp:21:21: required from here functional_bug.cpp:15:9: error: wrong number of template arguments (3, should be 2) In file included from functional_bug.cpp:1:0: /usr/lib/gcc-snapshot/lib/gcc/i486-linux-gnu/4.8.0/../../../../include/c++/4.8.0/type_traits:1264:12: error: provided for 'template<class _From, class _To> struct std::is_convertible' functional_bug.cpp: In function 'int main()': functional_bug.cpp:22:14: error: 'struct Types<int, int>' has no member named 'foo'
Created attachment 27186 [details] 4.8.0 output test run by sam of #c++ on freenode
Created attachment 27187 [details] 4.7.0 output test run on arch linux
Very strange. Confirmed.
Looks like a regression. I wonder if isn't some sort of weird side-effect of the fix for PR48322: we should at least compare pre and post Rev 181547. Then do a binary search. HJ, can you help with the search? (mind the -std=c++11)
(In reply to comment #4) > HJ, can you help with the search? (mind the -std=c++11) My regression hunt machine is down. It will take a while to get it back.
Too bad, didn't know that. Then I'll do something myself ASAP. In the meanwhile, at the risk of appearing a bit boring, let me add Jason in CC for this one too, the issue seems quite "interesting" ;)
I'm pretty sure that this is not related with <functional>, but instead with some interaction between the <tuple> header and std::is_convertible. The following variant still demonstrates the problem (I deliberately changed some of the original names used in the code to be sure that they are not cause of the problem): #include <tuple> template<bool, class T> struct enable_if { typedef T type; }; template <bool...> struct Bs { static const bool value = true; }; template <typename... Ts> struct AType { template <typename... Us, typename enable_if< Bs<std::is_convertible<Us, Ts>::value...>::value, bool>::type = false > int foo(Us&&...) { return sizeof...(Us); } }; int main() { AType<int, int> t; return t.foo(1, 1); } (You can also add <type_traits>, but it is already added via <tuple>). If we now add upfront template <class, class> struct is_convertible { static const bool value = true; }; and replace the usage of std::is_convertible by is_convertible, the error does no longer occur.
Thanks Daniel. If you feel like helping even more here, I would suggest having a look to the output of g++ -E and check that we aren't goofing something in terms of include guards, double inclusions, these kinds of stupid errors which often lean to very poor diagnostics, unfortunately. That done, I can only imagine a front-end issue.
Eh, this is *not* a library issue: #include <type_traits> #if 1 template<typename... _Elements> class tuple { template<typename... _UElements, typename = typename std::enable_if<std::__and_<std::is_convertible<_UElements, _Elements>...>::value>::type> tuple(_UElements&&...); }; #else template<typename _Elements> class tuple1 { template<typename _UElements, typename = typename std::enable_if<std::__and_<std::is_convertible<_UElements, _Elements>>::value>::type> tuple1(_UElements&&); }; #endif template <bool...> struct Bs { static const bool value = true; }; template <typename... Ts> struct AType { template <typename... Us, typename std::enable_if< Bs<std::is_convertible<Us, Ts>::value...>::value, bool>::type = false > int foo(Us&&...) { return sizeof...(Us); } }; int main() { AType<int, int> t; return t.foo(1, 1); }
So, the below is my final pure C++ testcase: if 1 is changed to 0 the code compiles; likewise if 1 and 0 are swapped. Thus, it seems there is something wrong in global front-end data structures: template <class, class> struct is_convertible { static const bool value = true; }; template<bool, class T> struct enable_if { typedef T type; }; template <bool...> struct Xs { static const bool value = true; }; #if 1 template<typename... Ts> class BType { template <typename... Us, typename enable_if< Xs<is_convertible<Us, Ts>::value...>::value, bool>::type = false> void fooX(Us&&...); }; #endif template <typename... Ts> struct AType { template <typename... Us, typename enable_if< Xs<is_convertible<Us, Ts>::value...>::value, bool>::type = false> void foo(Us&&...); }; #if 0 template<typename... Ts> class CType { template <typename... Us, typename enable_if< Xs<is_convertible<Us, Ts>::value...>::value, bool>::type = false> void fooX(Us&&...); }; #endif int main() { AType<int, int> t; t.foo(1, 1); }
The #c10 testcase started failing with http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=170341 with: pr53039.C: In function 'int main()': pr53039.C:56:5: error: 'struct AType<int, int>' has no member named 'foo'
(In reply to comment #11) > The #c10 testcase started failing with > http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=170341 Right. Using DECL_NAME to compare parameter packs doesn't work if one parameter pack can be replaced by another in substitution. In both BType and AType, we have Xs<is_convertible<Us, Ts>::value...>::value, and the appearance in AType ends up replaced by the version from BType, so when we compare the Us to the AType parameter, they don't match. Clearly they should match. I think comparing the decls was my idea, sorry.
GCC 4.7.1 is being released, adjusting target milestone.
Thus, is it possible that a different approach at fixing PR46394, among those already envisaged, could work for this one? Maybe Dodji can look again into it? He has already analyzed in detail the involved code, AFAICS.
Author: jason Date: Thu Jul 5 19:39:01 2012 New Revision: 189298 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=189298 Log: PR c++/50852 PR c++/53039 * tree.c (strip_typedefs_expr): New. * cp-tree.h: Declare it. * pt.c (convert_template_argument, unify): Use it. * parser.c (cp_parser_template_declaration_after_export): Don't call fixup_template_parms. Added: trunk/gcc/testsuite/g++.dg/cpp0x/variadic133.C trunk/gcc/testsuite/g++.dg/template/typedef39.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/cp-tree.h trunk/gcc/cp/parser.c trunk/gcc/cp/pt.c trunk/gcc/cp/tree.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/template/param1.C
Author: jason Date: Thu Jul 5 21:24:33 2012 New Revision: 189305 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=189305 Log: PR c++/53039 * pt.c (arg_from_parm_pack_p): Go back to using same_type_p or cp_tree_equal. Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/pt.c
Fixed on trunk.
Jason, are we still considering backporting something? It would be great - I find the issue pretty annoying - but it's your call.
GCC 4.7.2 has been released.
Author: jason Date: Thu Nov 29 20:16:46 2012 New Revision: 193955 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=193955 Log: PR c++/50852 PR c++/53039 * tree.c (strip_typedefs_expr): New. * cp-tree.h: Declare it. * pt.c (convert_template_argument, unify): Use it. * parser.c (cp_parser_template_declaration_after_export): Don't call fixup_template_parms. * cp-tree.h (TEMPLATE_PARM_NUM_SIBLINGS): Remove. (struct template_parm_index_s): Remove num_siblings. * pt.c (fixup_template_parms, fixup_template_parm_index): Remove. (fixup_template_type_parm_type): Remove. (build_template_parm_index): Remove num_siblings parm. (process_template_parm): Likewise. * parser.c (cp_parser_template_parameter_list): Adjust. * tree.c (cp_tree_equal): Don't compare num_siblings. * typeck.c (comp_template_parms_position): Likewise. * pt.c (arg_from_parm_pack_p): Go back to using same_type_p or cp_tree_equal. Added: branches/gcc-4_7-branch/gcc/testsuite/g++.dg/cpp0x/alias-decl-20.C branches/gcc-4_7-branch/gcc/testsuite/g++.dg/cpp0x/variadic133.C branches/gcc-4_7-branch/gcc/testsuite/g++.dg/template/typedef39.C Modified: branches/gcc-4_7-branch/gcc/cp/ChangeLog branches/gcc-4_7-branch/gcc/cp/cp-tree.h branches/gcc-4_7-branch/gcc/cp/parser.c branches/gcc-4_7-branch/gcc/cp/pt.c branches/gcc-4_7-branch/gcc/cp/tree.c branches/gcc-4_7-branch/gcc/cp/typeck.c branches/gcc-4_7-branch/gcc/testsuite/ChangeLog branches/gcc-4_7-branch/gcc/testsuite/g++.dg/template/param1.C
Fixed for 4.7.3.