This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c++/57239] New: GCC cannot handle inner/nested class templates with non-type parameter packs that were declared in the outer/containing class


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57239

            Bug ID: 57239
           Summary: GCC cannot handle inner/nested class templates with
                    non-type parameter packs that were declared in the
                    outer/containing class
           Product: gcc
           Version: 4.8.1
            Status: UNCONFIRMED
          Severity: major
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: scottbaldwin at gmail dot com

GCC 4.7.2 and 4.8.x cannot handle inner/nested class templates with non-type
parameter packs that were declared in the outer/containing class's template
parameter list. This bug can result in either an "internal compile error", or
even generate incorrect code (both are demonstrated), which is why I marked
this bug as "major".

I encountered this bug while trying to implement a helper template called
is_instantiation_of__nontypes<> which is a non-type-parameter counterpart to
the is_instantiation_of<> template described at
[http://stackoverflow.com/questions/11251376/].

The demos below (one for compile-time error demo, one for run-time error demo)
are implementations of this is_instantiation_of__nontypes<> template and work
fine in clang, but in gcc 4.7.2 and 4.8.x fail to compile or produce incorrect
results. These demos should compile "out of the box" as they have no
dependencies other than the standard libraries.

----------------------------------------
compile-time error demo
----------------------------------------

    // generic version of is_instantiation_of__nontypes<> (the template to
check against is template-template parameter 'TT', taking "values" of the
non-type parameter pack 'Ts...' declared in outer/containing class)

    template<bool BoolVal, char CharVal>
    struct Foo {};

    template<typename... Ts>
    struct is_instantiation_of__nontypes
    {
        template<template<Ts...> class TT, typename T>
        struct check : std::false_type {};

        template<template<Ts...> class TT, Ts... Args>
        struct check<TT, TT<Args...>> : std::true_type {};
    };

    int main() {
        using FooInstantiation = Foo<false, 'x'>;
        std::cout << ((is_instantiation_of__nontypes<bool, char>::check<Foo,
FooInstantiation>::value) ? "yes" : "no") << endl;
    }
---
This fails to compile in gcc 4.7.2/4.8.x with the following errors:

[gcc 4.7.2]:
    make[1]: compiling [sandbox_cpp11.cpp] (gcc 4.7.2)
    sandbox_cpp11.cpp: In function âvoid gcc_bug_demo_3::_go_()â:
    sandbox_cpp11.cpp:122:88: error: type/value mismatch at argument 1 in
template parameter list for âtemplate<class ... Ts>
template<template<template<Ts ...<anonymous> > class TT, class T>
template<class ... Ts> template<Ts ...<anonymous> > class TT, class T> struct
gcc_bug_demo_3::is_instantiation_of__nontypes<Ts>::checkâ
    sandbox_cpp11.cpp:122:88: error:   expected a template of type
âtemplate<class ... Ts> template<Ts ...<anonymous> > class TTâ, got
âtemplate<bool BoolVal, char CharVal> struct gcc_bug_demo_3::Fooâ
    make[1]: *** [dbg-mt/sandbox_cpp11.o] Error 1
    make: *** [objs] Error 2

[gcc 4.8.x]:
    make[1]: compiling [sandbox_cpp11.cpp] (gcc 4.8.x)
    sandbox_cpp11.cpp:116:27: error: âTs ...â is not a valid type for a
template non-type parameter
       struct check<TT, TT<Args...>> : std::true_type {};
                               ^
    sandbox_cpp11.cpp:116:30: error: template argument 2 is invalid
       struct check<TT, TT<Args...>> : std::true_type {};
                                  ^
    sandbox_cpp11.cpp: In function âvoid gcc_bug_demo_3::_go_()â:
    sandbox_cpp11.cpp:122:88: error: type/value mismatch at argument 1 in
template parameter list for âtemplate<class ... Ts>
template<template<template<Ts ...<anonymous> > class TT, class T>
template<class ... Ts> template<Ts ...<anonymous> > class TT, class T> struct
gcc_bug_demo_3::is_instantiation_of__nontypes<Ts>::checkâ
       std::cout << ((is_instantiation_of__nontypes<bool, char>::check<Foo,
FooInstantiation>::value) ? "yes" : "no") << endl;
                                                                               
        ^
    sandbox_cpp11.cpp:122:88: error:   expected a template of type
âtemplate<class ... Ts> template<Ts ...<anonymous> > class TTâ, got
âtemplate<bool BoolVal, char CharVal> struct gcc_bug_demo_3::Fooâ
    make[1]: *** [dbg-mt/sandbox_cpp11.o] Error 1
    make: *** [objs] Error 2

4.8.x is slightly more verbose with the additional "error: âTs ...â is not a
valid type for a template non-type parameter", which is incorrect since 'Ts...'
was properly declared as a parameter pack in the containing class's template
parameter list.
In fact, if you simplify the code (by removing template-template parameter 'TT'
and replacing it w/ hard-coded template class 'Foo') then it compiles fine, but
has incorrect results at runtime, as demonstrated in the following code ...

----------------------------------------
run-time error demo
----------------------------------------

    // simplified version of is_instantiation_of__nontypes<> (the template to
check against is hardcoded as template 'Foo', instead of being
template-template parameter 'TT')
    // compiles without error in all 4 compilers tested (gcc 4.7.2, 4.8.0,
4.8.1, and clang 3.3), but only has correct runtime results (output of "yes")
when compiled with clang.

    template<bool BoolVal, char CharVal>
    struct Foo {};

    template<typename... Ts>
    struct is_instantiation_of__nontypes // hard-coded for class template Foo
    {
        template<typename T>
        struct check : std::false_type {};

        template<Ts... Args>
        struct check<Foo<Args...>> : std::true_type {};
    };

    int main() {
        using FooInstantiation = Foo<false, 'x'>;
        // the next line will output "yes" if the compiler has correct logic,
or "no" otherwise
        std::cout << ((is_instantiation_of__nontypes<bool,
char>::check<FooInstantiation>::value) ? "yes" : "no") << std::endl;
    }

This demo outputs "yes" when compiled with clang (3.3), but outputs "no" when
compiled with gcc (4.7.2 or 4.8.x).

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]