diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4b33059287f9..2c681c0edbc4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2008-12-17 Jason Merrill + + * semantics.c (describable_type): New function. + (finish_decltype_type): Use it for dependent exprs. + * cp-tree.h: Declare it. + * mangle.c (write_type) [DECLTYPE_TYPE]: Set skip_evaluation. + (write_expression): If skip_evaluation, use type stubs. + * tree.c (cp_tree_equal): Handle PARM_DECLs from different + declarations of a function. + * init.c (build_new): Do auto deduction if type is describable. + * decl.c (cp_finish_decl): Likewise. + * parser.c (cp_parser_omp_for_loop): Likewise. + 2008-12-10 Jason Merrill PR c++/35319 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bf22eb4d85f1..ff43bc70d74e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4814,6 +4814,7 @@ extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool); +extern tree describable_type (tree); extern tree finish_decltype_type (tree, bool); extern tree finish_trait_expr (enum cp_trait_kind, tree, tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e786b39c8e30..efc7e2eb8a38 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5496,7 +5496,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, TREE_TYPE (decl) = error_mark_node; return; } - else if (!type_dependent_expression_p (init)) + else if (describable_type (init)) { type = TREE_TYPE (decl) = do_auto_deduction (type, init, auto_node); if (type == error_mark_node) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index d71b68badaa1..abcf85864734 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2329,7 +2329,7 @@ build_new (tree placement, tree type, tree nelts, tree init, orig_init = init; if (nelts == NULL_TREE && init != void_zero_node && list_length (init) == 1 - && !any_type_dependent_arguments_p (init)) + && describable_type (TREE_VALUE (init))) { tree auto_node = type_uses_auto (type); if (auto_node) diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 36b984e32140..1ec27c1ffcd7 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1680,7 +1680,9 @@ write_type (tree type) write_char ('t'); else write_char ('T'); + ++skip_evaluation; write_expression (DECLTYPE_TYPE_EXPR (type)); + --skip_evaluation; write_char ('E'); break; @@ -2139,9 +2141,28 @@ write_member_name (tree member) static void write_expression (tree expr) { - enum tree_code code; + enum tree_code code = TREE_CODE (expr); - code = TREE_CODE (expr); + /* Inside decltype we can simplify some expressions, since we're only + interested in the type. */ + if (skip_evaluation) + { + tree type = describable_type (expr); + if (type == NULL_TREE) + ; + else if (TREE_CODE (type) == REFERENCE_TYPE) + { + write_string ("sT"); + write_type (TREE_TYPE (type)); + return; + } + else + { + write_string ("sR"); + write_type (type); + return; + } + } /* Skip NOP_EXPRs. They can occur when (say) a pointer argument is converted (via qualification conversions) to another diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 45abd2414d51..79be488028f2 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -21159,7 +21159,7 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) &is_direct_init, &is_non_constant_init); - if (auto_node && !type_dependent_expression_p (init)) + if (auto_node && describable_type (init)) { TREE_TYPE (decl) = do_auto_deduction (TREE_TYPE (decl), init, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e0ae6fff4adc..d5efb8348107 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4438,12 +4438,79 @@ finish_static_assert (tree condition, tree message, location_t location, } } +/* Returns decltype((EXPR)) for cases where we can drop the decltype and + just return the type even though EXPR is a type-dependent expression. + The ABI specifies which cases this applies to, which is a subset of the + possible cases. */ + +tree +describable_type (tree expr) +{ + tree type = NULL_TREE; + + /* processing_template_decl isn't set when we're called from the mangling + code, so bump it now. */ + ++processing_template_decl; + if (! type_dependent_expression_p (expr) + && ! type_unknown_p (expr)) + { + type = TREE_TYPE (expr); + if (real_lvalue_p (expr)) + type = build_reference_type (type); + } + --processing_template_decl; + + if (type) + return type; + + switch (TREE_CODE (expr)) + { + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case FUNCTION_DECL: + /* Named rvalue reference becomes lvalue. */ + type = build_reference_type (non_reference (TREE_TYPE (expr))); + break; + + case NEW_EXPR: + case CONST_DECL: + case TEMPLATE_PARM_INDEX: + case CAST_EXPR: + case STATIC_CAST_EXPR: + case REINTERPRET_CAST_EXPR: + case CONST_CAST_EXPR: + case DYNAMIC_CAST_EXPR: + type = TREE_TYPE (expr); + break; + + case INDIRECT_REF: + { + tree ptrtype = describable_type (TREE_OPERAND (expr, 0)); + if (ptrtype && POINTER_TYPE_P (ptrtype)) + type = build_reference_type (TREE_TYPE (ptrtype)); + } + break; + + default: + if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_constant) + type = TREE_TYPE (expr); + break; + } + + if (type && type_uses_auto (type)) + return NULL_TREE; + else + return type; +} + /* Implements the C++0x decltype keyword. Returns the type of EXPR, suitable for use as a type-specifier. ID_EXPRESSION_OR_MEMBER_ACCESS_P is true when EXPR was parsed as an id-expression or a class member access, FALSE when it was parsed as a full expression. */ + tree finish_decltype_type (tree expr, bool id_expression_or_member_access_p) { @@ -4464,6 +4531,29 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) if (type_dependent_expression_p (expr)) { + if (id_expression_or_member_access_p) + { + switch (TREE_CODE (expr)) + { + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case FUNCTION_DECL: + case CONST_DECL: + case TEMPLATE_PARM_INDEX: + type = TREE_TYPE (expr); + break; + + default: + break; + } + } + else + type = describable_type (expr); + + if (type && !type_uses_auto (type)) + return type; + type = cxx_make_type (DECLTYPE_TYPE); DECLTYPE_TYPE_EXPR (type) = expr; DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type) diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 2ae65431c7be..1f2c6319ece6 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1857,8 +1857,17 @@ cp_tree_equal (tree t1, tree t2) return false; return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); - case VAR_DECL: case PARM_DECL: + /* For comparing uses of parameters in late-specified return types + with an out-of-class definition of the function. */ + if ((!DECL_CONTEXT (t1) || !DECL_CONTEXT (t2)) + && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)) + && DECL_NAME (t1) == DECL_NAME (t2)) + return true; + else + return false; + + case VAR_DECL: case CONST_DECL: case FUNCTION_DECL: case TEMPLATE_DECL: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 74b39a4eaf62..11a6a7095314 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-12-17 Jason Merrill + + * g++.dg/cpp0x/auto6.C: Test more stuff. + * g++.dg/cpp0x/auto12.C: New test. + 2008-12-17 Daniel Kraft PR fortran/38137 diff --git a/gcc/testsuite/g++.dg/cpp0x/auto12.C b/gcc/testsuite/g++.dg/cpp0x/auto12.C new file mode 100644 index 000000000000..94652cb5ca88 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/auto12.C @@ -0,0 +1,52 @@ +// More auto/decltype mangling tests. +// { dg-options "-std=c++0x" } + +template +struct B +{ + static int i; +}; + +int&& x(); + +template +struct A +{ + static int i; + static int &ir; + static int &&irr; + template + auto f(U u) -> decltype (u + i); + template + auto fr(U u) -> decltype (u + ir); + template + auto frr(U u) -> decltype (u + irr); + template + auto g(U u) -> decltype (u + sizeof (i)); + template + auto h(U u) -> decltype (u + B::i); + template + auto j(U u) -> decltype (u + x()); +}; + +template template +auto A::f(U u) -> decltype (u + i) +{ + return u + i; +} + +int main() +{ + // { dg-final { scan-assembler "_ZN1AIiE1fIiEEDTplsTT_sTiES2_" } } + A().f(1); + // { dg-final { scan-assembler "_ZN1AIiE2frIiEEDTplsTT_sTiES2_" } } + A().fr(1); + // { dg-final { scan-assembler "_ZN1AIiE3frrIiEEDTplsTT_sTiES2_" } } + A().frr(1); + // { dg-final { scan-assembler "_ZN1AIiE1gIiEEDTplsTT_sRjES2_" } } + A().g(1); + // { dg-final { scan-assembler "_ZN1AIiE1hIiEEDTplsTT_sr1BIS2_E1iES2_" } } + A().h(1); + // { dg-final { scan-assembler "_ZN1AIiE1jIiEEDTplsTT_sRiES2_" } } + A().j(1); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/auto6.C b/gcc/testsuite/g++.dg/cpp0x/auto6.C index d2bcfedb63c6..7d659c7236a0 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto6.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto6.C @@ -30,6 +30,12 @@ auto add3(T t, U u) -> decltype (ag(t,u)) return ag(t,u); } +template +decltype(*(T*)0+*(U*)0) add4(T t, U u) +{ + return t+u; +} + template struct A { @@ -72,13 +78,28 @@ auto k(T t, U u, V v) -> decltype (t.U::template B::MEM) return t.U::template B::MEM; } +// For these two examples we can elide the 'decltype' and just mangle the type. +template +auto l(T t) -> decltype (t) +{ + return t; +} + +template +auto m(T t) -> decltype (u) +{ + return t; +} + A a, *p; int main() { - // { dg-final { scan-assembler "_Z3addIidEDTplsTT_sTT0_ES0_S1_" } } + // { dg-final { scan-assembler "_Z3addIidEDTplsTT_sTT0_ES0_S1_" } } auto i = add(1, 2.0); - // { dg-final { scan-assembler "_Z4add2IidEDTplcvT_vcvT0_vES0_S1_" } } + // { dg-final { scan-assembler "_Z4add4IidEDTplsTT_sTT0_ES0_S1_" } } + auto i4 = add4(1, 2.0); + // { dg-final { scan-assembler "_Z4add2IidEDTplsRT_sRT0_ES0_S1_" } } auto i2 = add2(1, 2.0); // { dg-final { scan-assembler "_Z4add3IidEDTclL_Z2agEsTT_sTT0_EES0_S1_" } } auto i3 = add3(1, 2.0); @@ -90,4 +111,8 @@ int main() h(a,1.0); // { dg-final { scan-assembler "_Z1kI1C1AIiE1DEDtdtsTT_srNT0_1BIT1_EE3MEMES4_S5_S7_" } } k( C(), A(), D() ); + // { dg-final { scan-assembler "_Z1lIiET_S0_" } } + l(1); + // { dg-final { scan-assembler "_Z1mIiLi1EET_S0_" } } + m(1); } diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index a6721bf906d8..4eaee542b3be 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,10 @@ +2008-12-17 Jason Merrill + + * cp-demangle.c (d_expression): Handle rvalue stubs too. + [DEMANGLE_COMPONENT_CAST]: Update mangling. + (d_print_comp): Avoid extra ", " with empty template argument packs. + Remove handling for obsolete T() mangling. + 2008-12-10 Jason Merrill * cp-demangle.c (cplus_demangle_type): Support fixed-point types. diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index de0d9f7610ea..8ab5729dbb76 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -2561,7 +2561,8 @@ d_expression (struct d_info *di) d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, d_template_args (di))); } - else if (peek == 's' && d_peek_next_char (di) == 'T') + else if (peek == 's' + && (d_peek_next_char (di) == 'T' || d_peek_next_char (di) == 'R')) { /* Just demangle a parameter placeholder as its type. */ d_advance (di, 2); @@ -2608,20 +2609,22 @@ d_expression (struct d_info *di) args = op->u.s_extended_operator.args; break; case DEMANGLE_COMPONENT_CAST: - if (d_peek_char (di) == 'v') - /* T() encoded as an operand of void. */ - return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, - cplus_demangle_type (di)); - else - args = 1; + args = 1; break; } switch (args) { case 1: - return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, - d_expression (di)); + { + struct demangle_component *operand; + if (op->type == DEMANGLE_COMPONENT_CAST) + operand = d_exprlist (di); + else + operand = d_expression (di); + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + operand); + } case 2: { struct demangle_component *left; @@ -3763,8 +3766,14 @@ d_print_comp (struct d_print_info *dpi, d_print_comp (dpi, d_left (dc)); if (d_right (dc) != NULL) { + size_t len; d_append_string (dpi, ", "); + len = dpi->len; d_print_comp (dpi, d_right (dc)); + /* If that didn't print anything (which can happen with empty + template argument packs), remove the comma and space. */ + if (dpi->len == len) + dpi->len -= 2; } return; @@ -3800,12 +3809,7 @@ d_print_comp (struct d_print_info *dpi, d_print_cast (dpi, d_left (dc)); d_append_char (dpi, ')'); } - if (d_left (dc)->type == DEMANGLE_COMPONENT_CAST - && d_right (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE) - /* type() -- FIXME what about type(multiple,args) */ - d_append_string (dpi, "()"); - else - d_print_subexpr (dpi, d_right (dc)); + d_print_subexpr (dpi, d_right (dc)); return; case DEMANGLE_COMPONENT_BINARY: