[backport from gcc-4.8/trunk r189298 ] gcc/cp/ 2012-07-05 Jason Merrill 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. gcc/testsuite/ 2012-07-05 Jason Merrill PR c++/50852 * g++.dg/template/typedef39.C: New. PR c++/53039 * g++.dg/cpp0x/variadic133.C: New. * g++.dg/template/param1.C: Adjust. --- gcc-4.7.1/gcc/cp/cp-tree.h.~1~ 2012-06-02 06:05:25.000000000 +0200 +++ gcc-4.7.1/gcc/cp/cp-tree.h 2012-09-08 21:59:49.000000000 +0200 @@ -5655,6 +5655,7 @@ extern bool type_has_nontrivial_copy_ini 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); --- gcc-4.7.1/gcc/cp/parser.c.~1~ 2012-06-02 06:05:25.000000000 +0200 +++ gcc-4.7.1/gcc/cp/parser.c 2012-09-08 21:59:49.000000000 +0200 @@ -21139,7 +21139,6 @@ cp_parser_template_declaration_after_exp { /* 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 --- gcc-4.7.1/gcc/cp/pt.c.~1~ 2012-06-12 17:01:17.000000000 +0200 +++ gcc-4.7.1/gcc/cp/pt.c 2012-09-08 21:59:49.000000000 +0200 @@ -6609,7 +6609,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; @@ -16566,6 +16566,7 @@ unify (tree tparms, tree targs, tree par && !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); --- gcc-4.7.1/gcc/cp/tree.c.~1~ 2012-05-30 16:52:02.000000000 +0200 +++ gcc-4.7.1/gcc/cp/tree.c 2012-09-08 21:59:49.000000000 +0200 @@ -1085,7 +1085,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) @@ -1175,6 +1175,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; } @@ -1196,6 +1206,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 struct A + { + typedef T TT; + B 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. --- gcc-4.7.1/gcc/testsuite/g++.dg/cpp0x/variadic133.C.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.7.1/gcc/testsuite/g++.dg/cpp0x/variadic133.C 2012-09-08 21:59:49.000000000 +0200 @@ -0,0 +1,46 @@ +// PR c++/53039 +// { dg-do compile { target c++11 } } + +template +struct is_convertible +{ + static const bool value = true; +}; + +template +struct enable_if +{ + typedef T type; +}; + +template +struct Xs +{ + static const bool value = true; +}; + +template + class BType + { + template ::value...>::value, + bool>::type = false> + void fooX(BUs&&...); + }; + +template + struct AType + { + template ::value...>::value, + bool>::type = false> + void foo(AUs&&...); + }; + +int main() +{ + AType t; + t.foo(1, 1); +} --- gcc-4.7.1/gcc/testsuite/g++.dg/template/param1.C.~1~ 2011-02-03 20:55:00.000000000 +0100 +++ gcc-4.7.1/gcc/testsuite/g++.dg/template/param1.C 2012-09-08 21:59:49.000000000 +0200 @@ -2,11 +2,11 @@ // Origin: Volker Reichelt // { dg-do compile } -template struct A // { dg-error "declaration" } +template struct A { A(); }; -template A::A() {} // { dg-error "invalid use of incomplete type" } +template A::A() {} // { dg-error "got 2 template parameters|1 required" } A<0> a; --- gcc-4.7.1/gcc/testsuite/g++.dg/template/typedef39.C.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.7.1/gcc/testsuite/g++.dg/template/typedef39.C 2012-09-08 21:59:49.000000000 +0200 @@ -0,0 +1,15 @@ +// PR c++/50852 + +template class A; +template struct B {typedef int K;typedef int L;}; +template struct C +{ + typedef typename U::L X; + typedef A W; // { dg-error "not a member" } +}; +template struct D +{ + typedef typename U::L X; + typedef A W; // the error should really be on this line +}; +template class D >,3>;