diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e11b240f0e6b6f4983fd2b09e09b6cd28e74c7c2..91df62da41b0353d1b9343c9f6243de108057423 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2012-07-05 Jason Merrill <jason@redhat.com> + + 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. + 2012-07-04 Jason Merrill <jason@redhat.com> PR c++/53848 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 41ca83ca8c9bee4e4d20717dca3dbc2e0d70c592..e53f185d428f8d79144fd7bbc50a1a8c1040b804 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5692,6 +5692,7 @@ extern bool type_has_nontrivial_copy_init (const_tree); extern bool class_tmpl_impl_spec_p (const_tree); extern int zero_init_p (const_tree); extern tree strip_typedefs (tree); +extern tree strip_typedefs_expr (tree); extern tree copy_binfo (tree, tree, tree, tree *, int); extern int member_p (const_tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 027a7b9d07afcdb7de006561d5d3a4a2ef830e9a..4c2167aa7f616c17da02461ace3d28dd96a78436 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -21207,7 +21207,6 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) { /* Parse the template parameters. */ parameter_list = cp_parser_template_parameter_list (parser); - fixup_template_parms (); } /* Get the deferred access checks from the parameter list. These diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f618fa557d10212a24a55d96946a67f0288b73a7..550a1cb021c7338cf170db922472a8496e363d7b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6600,7 +6600,7 @@ convert_template_argument (tree parm, argument specification is valid. */ val = convert_nontype_argument (t, orig_arg, complain); else - val = orig_arg; + val = strip_typedefs_expr (orig_arg); if (val == NULL_TREE) val = error_mark_node; @@ -16598,6 +16598,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, && !TEMPLATE_PARM_PARAMETER_PACK (parm)) return unify_parameter_pack_mismatch (explain_p, parm, arg); + arg = strip_typedefs_expr (arg); TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg; return unify_success (explain_p); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index a03f8459da804d8d37de2b0d870a2d1fe7d86031..15effe41555ba1a1522cb24599bf92a4090ab9d3 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1094,7 +1094,7 @@ cv_unqualified (tree type) * If T is a type that needs structural equality its TYPE_CANONICAL (T) will be NULL. * TYPE_CANONICAL (T) desn't carry type attributes - and looses template parameter names. */ + and loses template parameter names. */ tree strip_typedefs (tree t) @@ -1184,6 +1184,16 @@ strip_typedefs (tree t) TYPENAME_TYPE_FULLNAME (t), typename_type, tf_none); break; + case DECLTYPE_TYPE: + result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t)); + if (result == DECLTYPE_TYPE_EXPR (t)) + return t; + else + result = (finish_decltype_type + (result, + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t), + tf_none)); + break; default: break; } @@ -1205,6 +1215,186 @@ strip_typedefs (tree t) return cp_build_qualified_type (result, cp_type_quals (t)); } +/* Like strip_typedefs above, but works on expressions, so that in + + template<class T> struct A + { + typedef T TT; + B<sizeof(TT)> b; + }; + + sizeof(TT) is replaced by sizeof(T). */ + +tree +strip_typedefs_expr (tree t) +{ + unsigned i,n; + tree r, type, *ops; + enum tree_code code; + + if (t == NULL_TREE || t == error_mark_node) + return t; + + if (DECL_P (t) || CONSTANT_CLASS_P (t)) + return t; + + /* Some expressions have type operands, so let's handle types here rather + than check TYPE_P in multiple places below. */ + if (TYPE_P (t)) + return strip_typedefs (t); + + code = TREE_CODE (t); + switch (code) + { + case IDENTIFIER_NODE: + case TEMPLATE_PARM_INDEX: + case OVERLOAD: + case BASELINK: + case ARGUMENT_PACK_SELECT: + return t; + + case TRAIT_EXPR: + { + tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t)); + tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t)); + if (type1 == TRAIT_EXPR_TYPE1 (t) + && type2 == TRAIT_EXPR_TYPE2 (t)) + return t; + r = copy_node (t); + TRAIT_EXPR_TYPE1 (t) = type1; + TRAIT_EXPR_TYPE2 (t) = type2; + return r; + } + + case TREE_LIST: + { + VEC(tree,gc) *vec = make_tree_vector (); + bool changed = false; + tree it; + for (it = t; it; it = TREE_CHAIN (it)) + { + tree val = strip_typedefs_expr (TREE_VALUE (t)); + VEC_safe_push (tree, gc, vec, val); + if (val != TREE_VALUE (t)) + changed = true; + gcc_assert (TREE_PURPOSE (it) == NULL_TREE); + } + if (changed) + { + r = NULL_TREE; + FOR_EACH_VEC_ELT_REVERSE (tree, vec, i, it) + r = tree_cons (NULL_TREE, it, r); + } + else + r = t; + release_tree_vector (vec); + return r; + } + + case TREE_VEC: + { + bool changed = false; + VEC(tree,gc)* vec = make_tree_vector (); + n = TREE_VEC_LENGTH (t); + VEC_reserve (tree, gc, vec, n); + for (i = 0; i < n; ++i) + { + tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i)); + VEC_quick_push (tree, vec, op); + if (op != TREE_VEC_ELT (t, i)) + changed = true; + } + if (changed) + { + r = copy_node (t); + for (i = 0; i < n; ++i) + TREE_VEC_ELT (r, i) = VEC_index (tree, vec, i); + } + else + r = t; + release_tree_vector (vec); + return r; + } + + case CONSTRUCTOR: + { + bool changed = false; + VEC(constructor_elt,gc) *vec + = VEC_copy (constructor_elt, gc, CONSTRUCTOR_ELTS (t)); + n = CONSTRUCTOR_NELTS (t); + type = strip_typedefs (TREE_TYPE (t)); + for (i = 0; i < n; ++i) + { + constructor_elt *e = VEC_index (constructor_elt, vec, i); + tree op = strip_typedefs_expr (e->value); + if (op != e->value) + { + changed = true; + e->value = op; + } + gcc_checking_assert (e->index == strip_typedefs_expr (e->index)); + } + + if (!changed && type == TREE_TYPE (t)) + { + VEC_free (constructor_elt, gc, vec); + return t; + } + else + { + r = copy_node (t); + TREE_TYPE (r) = type; + CONSTRUCTOR_ELTS (r) = vec; + return r; + } + } + + case LAMBDA_EXPR: + gcc_unreachable (); + + default: + break; + } + + gcc_assert (EXPR_P (t)); + + n = TREE_OPERAND_LENGTH (t); + ops = XALLOCAVEC (tree, n); + type = TREE_TYPE (t); + + switch (code) + { + CASE_CONVERT: + case IMPLICIT_CONV_EXPR: + case DYNAMIC_CAST_EXPR: + case STATIC_CAST_EXPR: + case CONST_CAST_EXPR: + case REINTERPRET_CAST_EXPR: + case CAST_EXPR: + case NEW_EXPR: + type = strip_typedefs (type); + /* fallthrough */ + + default: + for (i = 0; i < n; ++i) + ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i)); + break; + } + + /* If nothing changed, return t. */ + for (i = 0; i < n; ++i) + if (ops[i] != TREE_OPERAND (t, i)) + break; + if (i == n && type == TREE_TYPE (t)) + return t; + + r = copy_node (t); + TREE_TYPE (r) = type; + for (i = 0; i < n; ++i) + TREE_OPERAND (r, i) = ops[i]; + return r; +} + /* Makes a copy of BINFO and TYPE, which is to be inherited into a graph dominated by T. If BINFO is NULL, TYPE is a dependent base, and we do a shallow copy. If BINFO is non-NULL, we do a deep copy. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 74ed2a3d9980add354ad5acafe0d3e3df4602803..a3c9f61fdbd926e9e0631c3071b1bf695ed77fb7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2012-07-05 Jason Merrill <jason@redhat.com> + + PR c++/50852 + * g++.dg/template/typedef39.C: New. + + PR c++/53039 + * g++.dg/cpp0x/variadic133.C: New. + * g++.dg/template/param1.C: Adjust. + 2012-07-05 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org> PR target/48941 diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic133.C b/gcc/testsuite/g++.dg/cpp0x/variadic133.C new file mode 100644 index 0000000000000000000000000000000000000000..0265f0991c186d249cb12c01c596dad7f5710604 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic133.C @@ -0,0 +1,46 @@ +// PR c++/53039 +// { dg-do compile { target c++11 } } + +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; +}; + +template<typename... BTs> + class BType + { + template <typename... BUs, + typename enable_if< + Xs<is_convertible<BUs, BTs>::value...>::value, + bool>::type = false> + void fooX(BUs&&...); + }; + +template <typename... ATs> + struct AType + { + template <typename... AUs, + typename enable_if< + Xs<is_convertible<AUs, ATs>::value...>::value, + bool>::type = false> + void foo(AUs&&...); + }; + +int main() +{ + AType<int, int> t; + t.foo(1, 1); +} diff --git a/gcc/testsuite/g++.dg/template/param1.C b/gcc/testsuite/g++.dg/template/param1.C index a8c3791254fd1baa7199693c443f5b395676f211..e3784736fc440fab7780915e292967e978c2db20 100644 --- a/gcc/testsuite/g++.dg/template/param1.C +++ b/gcc/testsuite/g++.dg/template/param1.C @@ -2,11 +2,11 @@ // Origin: Volker Reichelt <reichelt@igpm.rwth-aachen.de> // { dg-do compile } -template<int> struct A // { dg-error "declaration" } +template<int> struct A { A(); }; -template<int N, char> A<N>::A() {} // { dg-error "invalid use of incomplete type" } +template<int N, char> A<N>::A() {} // { dg-error "got 2 template parameters|1 required" } A<0> a; diff --git a/gcc/testsuite/g++.dg/template/typedef39.C b/gcc/testsuite/g++.dg/template/typedef39.C new file mode 100644 index 0000000000000000000000000000000000000000..71d8bdb1bef7f0ea2839ad6f3383f84ceb676a5d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typedef39.C @@ -0,0 +1,15 @@ +// PR c++/50852 + +template<int d> class A; +template<class T> struct B {typedef int K;typedef int L;}; +template<class U,class V> struct C +{ + typedef typename U::L X; + typedef A<X::a-1> W; // { dg-error "not a member" } +}; +template<class U,int d> struct D +{ + typedef typename U::L X; + typedef A<X::a-1> W; // the error should really be on this line +}; +template class D<B<A<1> >,3>;