pt.c (coerce_template_template_parm): Moved the body of the loop of coerce_template_template_parms here...
2008-03-26 Douglas Gregor <doug.gregor@gmail.com> * pt.c (coerce_template_template_parm): Moved the body of the loop of coerce_template_template_parms here, to make iteration over a template argument pack simpler. Also, allow matching of a template parameter pack in the template template parameter to a template parameter in the template template argument. (coerce_template_template_parms): Deal with variadic template template parameters. Use coerce_template_template_parm. (unify): Make sure we coerce the template template argument's template arguments to the template template parameter's template parameters, not the other way around. 2008-03-26 Douglas Gregor <doug.gregor@gmail.com> * g++.dg/cpp0x/variadic84.C: Update to reflect the change in variadic template template parameter binding semantics. * g++.dg/cpp0x/variadic85.C: Ditto. * g++.dg/cpp0x/variadic88.C: New. * g++.dg/cpp0x/variadic89.C: New. * g++.dg/cpp0x/variadic90.C: New. * g++.dg/cpp0x/variadic-ex14.C: Update to reflect the change in variadic template template parameter binding semantics. * g++.dg/cpp0x/variadic-lambda.C: New. From-SVN: r133543
This commit is contained in:
parent
22ec849c3b
commit
a0a5f30f8e
|
@ -1,3 +1,17 @@
|
||||||
|
2008-03-26 Douglas Gregor <doug.gregor@gmail.com>
|
||||||
|
|
||||||
|
* pt.c (coerce_template_template_parm): Moved the body of the loop
|
||||||
|
of coerce_template_template_parms here, to make iteration over a
|
||||||
|
template argument pack simpler.
|
||||||
|
Also, allow matching of a template parameter pack in the template
|
||||||
|
template parameter to a template parameter in the template
|
||||||
|
template argument.
|
||||||
|
(coerce_template_template_parms): Deal with variadic template
|
||||||
|
template parameters. Use coerce_template_template_parm.
|
||||||
|
(unify): Make sure we coerce the template template argument's
|
||||||
|
template arguments to the template template parameter's template
|
||||||
|
parameters, not the other way around.
|
||||||
|
|
||||||
2008-03-25 Tom Tromey <tromey@redhat.com>
|
2008-03-25 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
* Make-lang.in: Remove .o targets.
|
* Make-lang.in: Remove .o targets.
|
||||||
|
|
188
gcc/cp/pt.c
188
gcc/cp/pt.c
|
@ -4630,6 +4630,77 @@ convert_nontype_argument (tree type, tree expr)
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subroutine of coerce_template_template_parms, which returns 1 if
|
||||||
|
PARM_PARM and ARG_PARM match using the rule for the template
|
||||||
|
parameters of template template parameters. Both PARM and ARG are
|
||||||
|
template parameters; the rest of the arguments are the same as for
|
||||||
|
coerce_template_template_parms.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
coerce_template_template_parm (tree parm,
|
||||||
|
tree arg,
|
||||||
|
tsubst_flags_t complain,
|
||||||
|
tree in_decl,
|
||||||
|
tree outer_args)
|
||||||
|
{
|
||||||
|
if (arg == NULL_TREE || arg == error_mark_node
|
||||||
|
|| parm == NULL_TREE || parm == error_mark_node)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (TREE_CODE (arg) != TREE_CODE (parm))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (TREE_CODE (parm))
|
||||||
|
{
|
||||||
|
case TEMPLATE_DECL:
|
||||||
|
/* We encounter instantiations of templates like
|
||||||
|
template <template <template <class> class> class TT>
|
||||||
|
class C; */
|
||||||
|
{
|
||||||
|
tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
|
||||||
|
tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
|
||||||
|
|
||||||
|
if (!coerce_template_template_parms
|
||||||
|
(parmparm, argparm, complain, in_decl, outer_args))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Fall through. */
|
||||||
|
|
||||||
|
case TYPE_DECL:
|
||||||
|
if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (arg))
|
||||||
|
&& !TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm)))
|
||||||
|
/* Argument is a parameter pack but parameter is not. */
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_DECL:
|
||||||
|
/* The tsubst call is used to handle cases such as
|
||||||
|
|
||||||
|
template <int> class C {};
|
||||||
|
template <class T, template <T> class TT> class D {};
|
||||||
|
D<int, C> d;
|
||||||
|
|
||||||
|
i.e. the parameter list of TT depends on earlier parameters. */
|
||||||
|
if (!dependent_type_p (TREE_TYPE (arg))
|
||||||
|
&& !same_type_p
|
||||||
|
(tsubst (TREE_TYPE (parm), outer_args, complain, in_decl),
|
||||||
|
TREE_TYPE (arg)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (arg))
|
||||||
|
&& !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
|
||||||
|
/* Argument is a parameter pack but parameter is not. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
gcc_unreachable ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return 1 if PARM_PARMS and ARG_PARMS matches using rule for
|
/* Return 1 if PARM_PARMS and ARG_PARMS matches using rule for
|
||||||
template template parameters. Both PARM_PARMS and ARG_PARMS are
|
template template parameters. Both PARM_PARMS and ARG_PARMS are
|
||||||
|
@ -4652,6 +4723,7 @@ coerce_template_template_parms (tree parm_parms,
|
||||||
{
|
{
|
||||||
int nparms, nargs, i;
|
int nparms, nargs, i;
|
||||||
tree parm, arg;
|
tree parm, arg;
|
||||||
|
int variadic_p = 0;
|
||||||
|
|
||||||
gcc_assert (TREE_CODE (parm_parms) == TREE_VEC);
|
gcc_assert (TREE_CODE (parm_parms) == TREE_VEC);
|
||||||
gcc_assert (TREE_CODE (arg_parms) == TREE_VEC);
|
gcc_assert (TREE_CODE (arg_parms) == TREE_VEC);
|
||||||
|
@ -4659,10 +4731,37 @@ coerce_template_template_parms (tree parm_parms,
|
||||||
nparms = TREE_VEC_LENGTH (parm_parms);
|
nparms = TREE_VEC_LENGTH (parm_parms);
|
||||||
nargs = TREE_VEC_LENGTH (arg_parms);
|
nargs = TREE_VEC_LENGTH (arg_parms);
|
||||||
|
|
||||||
if (nargs != nparms)
|
/* Determine whether we have a parameter pack at the end of the
|
||||||
|
template template parameter's template parameter list. */
|
||||||
|
if (TREE_VEC_ELT (parm_parms, nparms - 1) != error_mark_node)
|
||||||
|
{
|
||||||
|
parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, nparms - 1));
|
||||||
|
|
||||||
|
switch (TREE_CODE (parm))
|
||||||
|
{
|
||||||
|
case TEMPLATE_DECL:
|
||||||
|
case TYPE_DECL:
|
||||||
|
if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm)))
|
||||||
|
variadic_p = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_DECL:
|
||||||
|
if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
|
||||||
|
variadic_p = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
gcc_unreachable ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nargs != nparms
|
||||||
|
&& !(variadic_p && nargs >= nparms - 1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < nparms; ++i)
|
/* Check all of the template parameters except the parameter pack at
|
||||||
|
the end (if any). */
|
||||||
|
for (i = 0; i < nparms - variadic_p; ++i)
|
||||||
{
|
{
|
||||||
if (TREE_VEC_ELT (parm_parms, i) == error_mark_node
|
if (TREE_VEC_ELT (parm_parms, i) == error_mark_node
|
||||||
|| TREE_VEC_ELT (arg_parms, i) == error_mark_node)
|
|| TREE_VEC_ELT (arg_parms, i) == error_mark_node)
|
||||||
|
@ -4671,60 +4770,35 @@ coerce_template_template_parms (tree parm_parms,
|
||||||
parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, i));
|
parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, i));
|
||||||
arg = TREE_VALUE (TREE_VEC_ELT (arg_parms, i));
|
arg = TREE_VALUE (TREE_VEC_ELT (arg_parms, i));
|
||||||
|
|
||||||
if (arg == NULL_TREE || arg == error_mark_node
|
if (!coerce_template_template_parm (parm, arg, complain, in_decl,
|
||||||
|| parm == NULL_TREE || parm == error_mark_node)
|
outer_args))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (TREE_CODE (arg) != TREE_CODE (parm))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (TREE_CODE (parm))
|
|
||||||
{
|
|
||||||
case TEMPLATE_DECL:
|
|
||||||
/* We encounter instantiations of templates like
|
|
||||||
template <template <template <class> class> class TT>
|
|
||||||
class C; */
|
|
||||||
{
|
|
||||||
tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
|
|
||||||
tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
|
|
||||||
|
|
||||||
if (!coerce_template_template_parms
|
|
||||||
(parmparm, argparm, complain, in_decl, outer_args))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* Fall through. */
|
|
||||||
|
|
||||||
case TYPE_DECL:
|
|
||||||
if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm))
|
|
||||||
!= TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (arg)))
|
|
||||||
/* One is a parameter pack, the other is not. */
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PARM_DECL:
|
|
||||||
/* The tsubst call is used to handle cases such as
|
|
||||||
|
|
||||||
template <int> class C {};
|
|
||||||
template <class T, template <T> class TT> class D {};
|
|
||||||
D<int, C> d;
|
|
||||||
|
|
||||||
i.e. the parameter list of TT depends on earlier parameters. */
|
|
||||||
if (!dependent_type_p (TREE_TYPE (arg))
|
|
||||||
&& !same_type_p
|
|
||||||
(tsubst (TREE_TYPE (parm), outer_args, complain, in_decl),
|
|
||||||
TREE_TYPE (arg)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
|
|
||||||
!= TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (arg)))
|
|
||||||
/* One is a parameter pack, the other is not. */
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
gcc_unreachable ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (variadic_p)
|
||||||
|
{
|
||||||
|
/* Check each of the template parameters in the template
|
||||||
|
argument against the template parameter pack at the end of
|
||||||
|
the template template parameter. */
|
||||||
|
if (TREE_VEC_ELT (parm_parms, i) == error_mark_node)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, i));
|
||||||
|
|
||||||
|
for (; i < nargs; ++i)
|
||||||
|
{
|
||||||
|
if (TREE_VEC_ELT (arg_parms, i) == error_mark_node)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
arg = TREE_VALUE (TREE_VEC_ELT (arg_parms, i));
|
||||||
|
|
||||||
|
if (!coerce_template_template_parm (parm, arg, complain, in_decl,
|
||||||
|
outer_args))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12825,8 +12899,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
|
||||||
{
|
{
|
||||||
tree parmvec = TYPE_TI_ARGS (parm);
|
tree parmvec = TYPE_TI_ARGS (parm);
|
||||||
tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
|
tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
|
||||||
tree argtmplvec
|
tree parm_parms
|
||||||
= DECL_INNERMOST_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (arg));
|
= DECL_INNERMOST_TEMPLATE_PARMS
|
||||||
|
(TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (parm));
|
||||||
int i, len;
|
int i, len;
|
||||||
int parm_variadic_p = 0;
|
int parm_variadic_p = 0;
|
||||||
|
|
||||||
|
@ -12857,7 +12932,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
|
||||||
Here, if Lvalue_proxy is permitted to bind to View, then
|
Here, if Lvalue_proxy is permitted to bind to View, then
|
||||||
the global operator+ will be used; if they are not, the
|
the global operator+ will be used; if they are not, the
|
||||||
Lvalue_proxy will be converted to float. */
|
Lvalue_proxy will be converted to float. */
|
||||||
if (coerce_template_parms (argtmplvec, parmvec,
|
if (coerce_template_parms (parm_parms,
|
||||||
|
argvec,
|
||||||
TYPE_TI_TEMPLATE (parm),
|
TYPE_TI_TEMPLATE (parm),
|
||||||
tf_none,
|
tf_none,
|
||||||
/*require_all_args=*/true,
|
/*require_all_args=*/true,
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
2008-03-26 Douglas Gregor <doug.gregor@gmail.com>
|
||||||
|
|
||||||
|
* g++.dg/cpp0x/variadic84.C: Update to reflect the change in
|
||||||
|
variadic template template parameter binding semantics.
|
||||||
|
* g++.dg/cpp0x/variadic85.C: Ditto.
|
||||||
|
* g++.dg/cpp0x/variadic88.C: New.
|
||||||
|
* g++.dg/cpp0x/variadic89.C: New.
|
||||||
|
* g++.dg/cpp0x/variadic90.C: New.
|
||||||
|
* g++.dg/cpp0x/variadic-ex14.C: Update to reflect the change in
|
||||||
|
variadic template template parameter binding semantics.
|
||||||
|
* g++.dg/cpp0x/variadic-lambda.C: New.
|
||||||
|
|
||||||
2008-03-25 Andrew Pinski <andrew_pinski@playstation.sony.com>
|
2008-03-25 Andrew Pinski <andrew_pinski@playstation.sony.com>
|
||||||
|
|
||||||
PR target/31558
|
PR target/31558
|
||||||
|
|
|
@ -14,10 +14,6 @@ X<B> xB; // { dg-error "mismatch" }
|
||||||
X<C> xC; // { dg-error "mismatch" }
|
X<C> xC; // { dg-error "mismatch" }
|
||||||
// { dg-error "expected a template" "" { target *-*-* } 14 }
|
// { dg-error "expected a template" "" { target *-*-* } 14 }
|
||||||
// { dg-error "invalid type" "" { target *-*-* } 14 }
|
// { dg-error "invalid type" "" { target *-*-* } 14 }
|
||||||
Y<A> yA; // { dg-error "mismatch" }
|
Y<A> yA;
|
||||||
// { dg-error "expected a template" "" { target *-*-* } 17 }
|
Y<B> yB;
|
||||||
// { dg-error "invalid type" "" { target *-*-* } 17 }
|
|
||||||
Y<B> yB; // { dg-error "mismatch" }
|
|
||||||
// { dg-error "expected a template" "" { target *-*-* } 20 }
|
|
||||||
// { dg-error "invalid type" "" { target *-*-* } 20 }
|
|
||||||
Y<C> yC; // okay
|
Y<C> yC; // okay
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
// { dg-options "-std=c++0x" }
|
||||||
|
|
||||||
|
struct int_placeholder;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct do_replace
|
||||||
|
{
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct do_replace<int_placeholder>
|
||||||
|
{
|
||||||
|
typedef int type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> struct lambdalike
|
||||||
|
{
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<template<typename...> class TT, typename... Args>
|
||||||
|
struct lambdalike<TT<Args...> > {
|
||||||
|
typedef TT<typename do_replace<Args>::type...> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct is_same
|
||||||
|
{
|
||||||
|
static const bool value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_same<T, T>
|
||||||
|
{
|
||||||
|
static const bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Elements> struct tuple;
|
||||||
|
template<typename T1, typename T2> struct pair;
|
||||||
|
|
||||||
|
static_assert(is_same<lambdalike<tuple<float, int_placeholder, double>>::type,
|
||||||
|
tuple<float, int, double>>::value,
|
||||||
|
"MPL lambda-like replacement on tuple");
|
||||||
|
static_assert(is_same<lambdalike<pair<float, int_placeholder>>::type,
|
||||||
|
pair<float, int>>::value,
|
||||||
|
"MPL lambda-like replacement on pair");
|
||||||
|
|
||||||
|
|
||||||
|
struct _1 {};
|
||||||
|
|
||||||
|
template<typename Arg0, typename Lambda>
|
||||||
|
struct eval
|
||||||
|
{
|
||||||
|
typedef Lambda type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Arg0>
|
||||||
|
struct eval<Arg0, _1>
|
||||||
|
{
|
||||||
|
typedef Arg0 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Arg0, template<typename...> class T, typename... Pack>
|
||||||
|
struct eval<Arg0, T<Pack...> >
|
||||||
|
{
|
||||||
|
typedef T< typename eval<Arg0, Pack>::type... > type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(is_same<eval<int, tuple<float, _1, double>>::type,
|
||||||
|
tuple<float, int, double>>::value, "eval tuple");
|
||||||
|
static_assert(is_same<eval<int, pair<_1, double>>::type,
|
||||||
|
pair<int, double>>::value, "eval pair");
|
||||||
|
static_assert(is_same<eval<int,
|
||||||
|
tuple<pair<_1, _1>, pair<float, float>,
|
||||||
|
pair<double, _1>>>::type,
|
||||||
|
tuple<pair<int, int>, pair<float, float>, pair<double, int>>>::value,
|
||||||
|
"recursive eval");
|
|
@ -18,9 +18,9 @@ template<int> struct B1 {};
|
||||||
template<int, int> struct B2 {};
|
template<int, int> struct B2 {};
|
||||||
template<typename> struct B3 {};
|
template<typename> struct B3 {};
|
||||||
template<typename, typename> struct B4 {};
|
template<typename, typename> struct B4 {};
|
||||||
A1<B1<0> > a1; // { dg-error "incomplete type" }
|
A1<B1<0> > a1;
|
||||||
A2<B2<0, 1> > a2; // { dg-error "incomplete type" }
|
A2<B2<0, 1> > a2;
|
||||||
A3<B2<0, 1> > a3; // { dg-error "incomplete type" }
|
A3<B2<0, 1> > a3;
|
||||||
A4<B3<int> > a4; // { dg-error "incomplete type" }
|
A4<B3<int> > a4;
|
||||||
A5<B4<int, long> > a5; // { dg-error "incomplete type" }
|
A5<B4<int, long> > a5;
|
||||||
A6<B4<int, long> > a6; // { dg-error "incomplete type" }
|
A6<B4<int, long> > a6;
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
template<typename...> struct A1;
|
template<typename...> struct A1;
|
||||||
template<template<int, int...> class T> struct A1<T<0, 1> > {};
|
template<template<int, int...> class T> struct A1<T<0, 1> > {};
|
||||||
template<int, int, int...> struct B1 {};
|
template<int, int, int...> struct B1 {};
|
||||||
A1<B1<0, 1> > a1; // { dg-error "incomplete type" }
|
A1<B1<0, 1> > a1;
|
||||||
template<int...> struct B2 {};
|
template<int...> struct B2 {};
|
||||||
A1<B2<0, 1> > a2; // { dg-error "incomplete type" }
|
A1<B2<0, 1> > a2; // { dg-error "incomplete type" }
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
// { dg-options "-std=c++0x" }
|
||||||
|
|
||||||
|
template<template<typename...> class TT>
|
||||||
|
TT<int, float, double> foo(TT<int, float>)
|
||||||
|
{
|
||||||
|
return TT<int, float, double>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
int& foo(T)
|
||||||
|
{
|
||||||
|
static int i = 0; return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct pair {};
|
||||||
|
|
||||||
|
void bar()
|
||||||
|
{
|
||||||
|
pair<int, float> p;
|
||||||
|
int& i = foo(p);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
// { dg-options "-std=c++0x" }
|
||||||
|
// Contributed by Eric Niebler
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct pair
|
||||||
|
{};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct test;
|
||||||
|
|
||||||
|
template<template<typename...> class T, typename... Args>
|
||||||
|
struct test<T<Args...> >
|
||||||
|
{};
|
||||||
|
|
||||||
|
test<pair<int, double> > t;
|
|
@ -0,0 +1,8 @@
|
||||||
|
// { dg-options "-std=c++0x" }
|
||||||
|
|
||||||
|
template<template<typename...> class TT>
|
||||||
|
struct X { };
|
||||||
|
|
||||||
|
template<typename T, typename U> struct pair { };
|
||||||
|
|
||||||
|
X<pair> x;
|
Loading…
Reference in New Issue