Bug 53039 - [4.7 Regression] including <functional> breaks std::is_convertible with template-pack expansion
Summary: [4.7 Regression] including <functional> breaks std::is_convertible with templ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.8.0
: P2 normal
Target Milestone: 4.7.3
Assignee: Jason Merrill
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-04-19 07:56 UTC by Radics Péter
Modified: 2012-11-29 20:57 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-04-19 00:00:00


Attachments
test code (276 bytes, application/octet-stream)
2012-04-19 07:56 UTC, Radics Péter
Details
4.8.0 output (861 bytes, text/plain)
2012-04-19 07:59 UTC, Radics Péter
Details
4.7.0 output (789 bytes, text/plain)
2012-04-19 08:00 UTC, Radics Péter
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Radics Péter 2012-04-19 07:56:11 UTC
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'
Comment 1 Radics Péter 2012-04-19 07:59:06 UTC
Created attachment 27186 [details]
4.8.0 output

test run by sam of #c++ on freenode
Comment 2 Radics Péter 2012-04-19 08:00:00 UTC
Created attachment 27187 [details]
4.7.0 output

test run on arch linux
Comment 3 Jonathan Wakely 2012-04-19 08:41:54 UTC
Very strange. Confirmed.
Comment 4 Paolo Carlini 2012-04-19 10:45:53 UTC
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)
Comment 5 H.J. Lu 2012-04-19 14:49:32 UTC
(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.
Comment 6 Paolo Carlini 2012-04-19 15:58:17 UTC
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" ;)
Comment 7 Daniel Krügler 2012-04-20 06:48:39 UTC
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.
Comment 8 Paolo Carlini 2012-04-20 09:06:30 UTC
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.
Comment 9 Paolo Carlini 2012-04-20 10:27:11 UTC
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);
}
Comment 10 Paolo Carlini 2012-04-20 12:37:33 UTC
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);
}
Comment 11 Jakub Jelinek 2012-05-02 11:46:24 UTC
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'
Comment 12 Jason Merrill 2012-06-11 05:59:25 UTC
(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.
Comment 13 Richard Biener 2012-06-14 08:47:08 UTC
GCC 4.7.1 is being released, adjusting target milestone.
Comment 14 Paolo Carlini 2012-06-14 10:03:07 UTC
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.
Comment 15 Jason Merrill 2012-07-05 19:39:07 UTC
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
Comment 16 Jason Merrill 2012-07-05 21:24:43 UTC
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
Comment 17 Jason Merrill 2012-07-06 01:34:09 UTC
Fixed on trunk.
Comment 18 Paolo Carlini 2012-09-13 10:31:18 UTC
Jason, are we still considering backporting something? It would be great - I find the issue pretty annoying - but it's your call.
Comment 19 Jakub Jelinek 2012-09-20 10:21:00 UTC
GCC 4.7.2 has been released.
Comment 20 Jason Merrill 2012-11-29 20:16:57 UTC
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
Comment 21 Jason Merrill 2012-11-29 20:57:15 UTC
Fixed for 4.7.3.