From: Jason Merrill Date: Sun, 17 Mar 2013 02:37:09 +0000 (-0400) Subject: re PR c++/52748 ([C++11] N3276 changes to decltype) X-Git-Tag: upstream/12.2.0~70844 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=57fcd4f4e4f12b1ede24f05385183d3f2dc7acfa;p=platform%2Fupstream%2Fgcc.git re PR c++/52748 ([C++11] N3276 changes to decltype) N3276 PR c++/52748 * cp-tree.h (tsubst_flags): Add tf_decltype. * call.c (build_cxx_call): Don't build a temporary if it's set. (build_over_call): Make sure it's only passed to build_cxx_call. * parser.c (cp_parser_primary_expression): Add decltype_p parm. (cp_parser_unary_expression): Likewise. (cp_parser_cast_expression): Likewise. (cp_parser_binary_expression): Likewise. (cp_parser_assignment_expression): Likewise. (cp_parser_postfix_expression): Likewise. Pass tf_decltype. (cp_parser_explicit_instantiation): Add decltype_p. Force a temporary for a call on the LHS of a comma. (cp_parser_decltype): Pass true to decltype_p parms. * pt.c (tsubst) [DECLTYPE_TYPE]: Pass tf_decltype. (tsubst_copy_and_build): Pass tf_decltype down only for CALL_EXPR and the RHS of COMPOUND_EXPR. * tree.c (build_cplus_new): Call complete_type_or_maybe_complain. From-SVN: r196736 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b57800e..580208a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,24 @@ 2013-03-16 Jason Merrill + N3276 + PR c++/52748 + * cp-tree.h (tsubst_flags): Add tf_decltype. + * call.c (build_cxx_call): Don't build a temporary if it's set. + (build_over_call): Make sure it's only passed to build_cxx_call. + * parser.c (cp_parser_primary_expression): Add decltype_p parm. + (cp_parser_unary_expression): Likewise. + (cp_parser_cast_expression): Likewise. + (cp_parser_binary_expression): Likewise. + (cp_parser_assignment_expression): Likewise. + (cp_parser_postfix_expression): Likewise. Pass tf_decltype. + (cp_parser_explicit_instantiation): Add decltype_p. Force a + temporary for a call on the LHS of a comma. + (cp_parser_decltype): Pass true to decltype_p parms. + * pt.c (tsubst) [DECLTYPE_TYPE]: Pass tf_decltype. + (tsubst_copy_and_build): Pass tf_decltype down only for + CALL_EXPR and the RHS of COMPOUND_EXPR. + * tree.c (build_cplus_new): Call complete_type_or_maybe_complain. + * cp-tree.h (abstract_class_use): New enum. * typeck2.c (pending_abstract_type): Add use field. (abstract_virtuals_error_sfinae): Add overloads taking diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e40c45f..8362c75 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6693,6 +6693,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) /* else continue to get conversion error. */ } + /* N3276 magic doesn't apply to nested calls. */ + int decltype_flag = (complain & tf_decltype); + complain &= ~tf_decltype; + /* Find maximum size of vector to hold converted arguments. */ parmlen = list_length (parm); nargs = vec_safe_length (args) + (first_arg != NULL_TREE ? 1 : 0); @@ -7064,7 +7068,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) return error_mark_node; } - return build_cxx_call (fn, nargs, argarray, complain); + return build_cxx_call (fn, nargs, argarray, complain|decltype_flag); } /* Build and return a call to FN, using NARGS arguments in ARGARRAY. @@ -7106,12 +7110,20 @@ build_cxx_call (tree fn, int nargs, tree *argarray, if (VOID_TYPE_P (TREE_TYPE (fn))) return fn; - fn = require_complete_type_sfinae (fn, complain); - if (fn == error_mark_node) - return error_mark_node; + /* 5.2.2/11: If a function call is a prvalue of object type: if the + function call is either the operand of a decltype-specifier or the + right operand of a comma operator that is the operand of a + decltype-specifier, a temporary object is not introduced for the + prvalue. The type of the prvalue may be incomplete. */ + if (!(complain & tf_decltype)) + { + fn = require_complete_type_sfinae (fn, complain); + if (fn == error_mark_node) + return error_mark_node; - if (MAYBE_CLASS_TYPE_P (TREE_TYPE (fn))) - fn = build_cplus_new (TREE_TYPE (fn), fn, complain); + if (MAYBE_CLASS_TYPE_P (TREE_TYPE (fn))) + fn = build_cplus_new (TREE_TYPE (fn), fn, complain); + } return convert_from_reference (fn); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 53940a6..39fb3df 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4203,6 +4203,9 @@ enum tsubst_flags { conversion might be permissible, not actually performing the conversion. */ + tf_decltype = 1 << 7, /* We are the operand of decltype. + Used to implement the special rules + for calls in decltype (5.2.2/11). */ tf_partial = 1 << 8, /* Doing initial explicit argument substitution in fn_type_unification. */ /* Convenient substitution flags combinations. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index f414932..3f56ff1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1802,7 +1802,7 @@ static tree cp_parser_nested_name_specifier static tree cp_parser_qualifying_entity (cp_parser *, bool, bool, bool, bool, bool); static tree cp_parser_postfix_expression - (cp_parser *, bool, bool, bool, cp_id_kind *); + (cp_parser *, bool, bool, bool, bool, cp_id_kind *); static tree cp_parser_postfix_open_square_expression (cp_parser *, tree, bool); static tree cp_parser_postfix_dot_deref_expression @@ -1832,7 +1832,7 @@ static vec *cp_parser_new_initializer static tree cp_parser_delete_expression (cp_parser *); static tree cp_parser_cast_expression - (cp_parser *, bool, bool, cp_id_kind *); + (cp_parser *, bool, bool, bool, cp_id_kind *); static tree cp_parser_binary_expression (cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *); static tree cp_parser_question_colon_clause @@ -1843,6 +1843,8 @@ static enum tree_code cp_parser_assignment_operator_opt (cp_parser *); static tree cp_parser_expression (cp_parser *, bool, cp_id_kind *); +static tree cp_parser_expression + (cp_parser *, bool, bool, cp_id_kind *); static tree cp_parser_constant_expression (cp_parser *, bool, bool *); static tree cp_parser_builtin_offsetof @@ -3900,6 +3902,7 @@ cp_parser_primary_expression (cp_parser *parser, bool address_p, bool cast_p, bool template_arg_p, + bool decltype_p, cp_id_kind *idk) { cp_token *token = NULL; @@ -4051,7 +4054,7 @@ cp_parser_primary_expression (cp_parser *parser, else { /* Parse the parenthesized expression. */ - expr = cp_parser_expression (parser, cast_p, idk); + expr = cp_parser_expression (parser, cast_p, decltype_p, idk); /* Let the front end know that this expression was enclosed in parentheses. This matters in case, for example, the expression is of the form `A::B', since @@ -4403,6 +4406,17 @@ cp_parser_primary_expression (cp_parser *parser, } } +static inline tree +cp_parser_primary_expression (cp_parser *parser, + bool address_p, + bool cast_p, + bool template_arg_p, + cp_id_kind *idk) +{ + return cp_parser_primary_expression (parser, address_p, cast_p, template_arg_p, + /*decltype*/false, idk); +} + /* Parse an id-expression. id-expression: @@ -5364,7 +5378,7 @@ cp_parser_qualifying_entity (cp_parser *parser, static tree cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, - bool member_access_only_p, + bool member_access_only_p, bool decltype_p, cp_id_kind * pidk_return) { cp_token *token; @@ -5625,11 +5639,17 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, postfix_expression = cp_parser_primary_expression (parser, address_p, cast_p, /*template_arg_p=*/false, + decltype_p, &idk); } break; } + /* Note that we don't need to worry about calling build_cplus_new on a + class-valued CALL_EXPR in decltype when it isn't the end of the + postfix-expression; unary_complex_lvalue will take care of that for + all these cases. */ + /* Keep looping until the postfix-expression is complete. */ while (true) { @@ -5668,8 +5688,12 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, bool is_builtin_constant_p; bool saved_integral_constant_expression_p = false; bool saved_non_integral_constant_expression_p = false; + int complain = tf_warning_or_error; vec *args; + if (decltype_p) + complain |= tf_decltype; + is_member_access = false; is_builtin_constant_p @@ -5726,7 +5750,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, postfix_expression = perform_koenig_lookup (postfix_expression, args, /*include_std=*/false, - tf_warning_or_error); + complain); } else postfix_expression @@ -5752,7 +5776,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, postfix_expression = perform_koenig_lookup (postfix_expression, args, /*include_std=*/false, - tf_warning_or_error); + complain); } } } @@ -5784,21 +5808,21 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL : LOOKUP_NORMAL), /*fn_p=*/NULL, - tf_warning_or_error)); + complain)); } else postfix_expression = finish_call_expr (postfix_expression, &args, /*disallow_virtual=*/false, /*koenig_p=*/false, - tf_warning_or_error); + complain); } else if (TREE_CODE (postfix_expression) == OFFSET_REF || TREE_CODE (postfix_expression) == MEMBER_REF || TREE_CODE (postfix_expression) == DOTSTAR_EXPR) postfix_expression = (build_offset_ref_call_from_tree (postfix_expression, &args, - tf_warning_or_error)); + complain)); else if (idk == CP_ID_KIND_QUALIFIED) /* A call to a static class member, or a namespace-scope function. */ @@ -5806,14 +5830,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, = finish_call_expr (postfix_expression, &args, /*disallow_virtual=*/true, koenig_p, - tf_warning_or_error); + complain); else /* All other function calls. */ postfix_expression = finish_call_expr (postfix_expression, &args, /*disallow_virtual=*/false, koenig_p, - tf_warning_or_error); + complain); /* The POSTFIX_EXPRESSION is certainly no longer an id. */ idk = CP_ID_KIND_NONE; @@ -6414,7 +6438,7 @@ cp_parser_pseudo_destructor_name (cp_parser* parser, static tree cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p, - cp_id_kind * pidk) + bool decltype_p, cp_id_kind * pidk) { cp_token *token; enum tree_code unary_operator; @@ -6635,7 +6659,9 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p, cast_expression = cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR, - /*cast_p=*/false, pidk); + /*cast_p=*/false, + /*decltype*/false, + pidk); /* Now, build an appropriate representation. */ switch (unary_operator) { @@ -6681,9 +6707,18 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p, return cp_parser_postfix_expression (parser, address_p, cast_p, /*member_access_only_p=*/false, + decltype_p, pidk); } +static inline tree +cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p, + cp_id_kind * pidk) +{ + return cp_parser_unary_expression (parser, address_p, cast_p, + /*decltype*/false, pidk); +} + /* Returns ERROR_MARK if TOKEN is not a unary-operator. If TOKEN is a unary-operator, the corresponding tree code is returned. */ @@ -7162,7 +7197,7 @@ cp_parser_tokens_start_cast_expression (cp_parser *parser) static tree cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, - cp_id_kind * pidk) + bool decltype_p, cp_id_kind * pidk) { /* If it's a `(', then we might be looking at a cast. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) @@ -7236,7 +7271,9 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, cp_parser_parse_definitely (parser); expr = cp_parser_cast_expression (parser, /*address_p=*/false, - /*cast_p=*/true, pidk); + /*cast_p=*/true, + /*decltype_p=*/false, + pidk); /* Warn about old-style casts, if so requested. */ if (warn_old_style_cast @@ -7262,7 +7299,8 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, /* If we get here, then it's not a cast, so it must be a unary-expression. */ - return cp_parser_unary_expression (parser, address_p, cast_p, pidk); + return cp_parser_unary_expression (parser, address_p, cast_p, + decltype_p, pidk); } /* Parse a binary expression of the general form: @@ -7347,6 +7385,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, static tree cp_parser_binary_expression (cp_parser* parser, bool cast_p, bool no_toplevel_fold_p, + bool decltype_p, enum cp_parser_prec prec, cp_id_kind * pidk) { @@ -7361,7 +7400,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, /* Parse the first expression. */ current.lhs = cp_parser_cast_expression (parser, /*address_p=*/false, - cast_p, pidk); + cast_p, decltype_p, pidk); current.lhs_type = ERROR_MARK; current.prec = prec; @@ -7498,6 +7537,15 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, return current.lhs; } +static tree +cp_parser_binary_expression (cp_parser* parser, bool cast_p, + bool no_toplevel_fold_p, + enum cp_parser_prec prec, + cp_id_kind * pidk) +{ + return cp_parser_binary_expression (parser, cast_p, no_toplevel_fold_p, + /*decltype*/false, prec, pidk); +} /* Parse the `? expression : assignment-expression' part of a conditional-expression. The LOGICAL_OR_EXPR is the @@ -7567,12 +7615,13 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr) throw-expression CAST_P is true if this expression is the target of a cast. + DECLTYPE_P is true if this expression is the operand of decltype. Returns a representation for the expression. */ static tree cp_parser_assignment_expression (cp_parser* parser, bool cast_p, - cp_id_kind * pidk) + bool decltype_p, cp_id_kind * pidk) { tree expr; @@ -7586,6 +7635,7 @@ cp_parser_assignment_expression (cp_parser* parser, bool cast_p, { /* Parse the binary expressions (logical-or-expression). */ expr = cp_parser_binary_expression (parser, cast_p, false, + decltype_p, PREC_NOT_OPERATOR, pidk); /* If the next token is a `?' then we're actually looking at a conditional-expression. */ @@ -7631,6 +7681,14 @@ cp_parser_assignment_expression (cp_parser* parser, bool cast_p, return expr; } +static tree +cp_parser_assignment_expression (cp_parser* parser, bool cast_p, + cp_id_kind * pidk) +{ + return cp_parser_assignment_expression (parser, cast_p, + /*decltype*/false, pidk); +} + /* Parse an (optional) assignment-operator. assignment-operator: one of @@ -7722,11 +7780,14 @@ cp_parser_assignment_operator_opt (cp_parser* parser) expression , assignment-expression CAST_P is true if this expression is the target of a cast. + DECLTYPE_P is true if this expression is the immediate operand of decltype, + except possibly parenthesized or on the RHS of a comma (N3276). Returns a representation of the expression. */ static tree -cp_parser_expression (cp_parser* parser, bool cast_p, cp_id_kind * pidk) +cp_parser_expression (cp_parser* parser, bool cast_p, bool decltype_p, + cp_id_kind * pidk) { tree expression = NULL_TREE; location_t loc = UNKNOWN_LOCATION; @@ -7737,7 +7798,19 @@ cp_parser_expression (cp_parser* parser, bool cast_p, cp_id_kind * pidk) /* Parse the next assignment-expression. */ assignment_expression - = cp_parser_assignment_expression (parser, cast_p, pidk); + = cp_parser_assignment_expression (parser, cast_p, decltype_p, pidk); + + /* We don't create a temporary for a call that is the immediate operand + of decltype or on the RHS of a comma. But when we see a comma, we + need to create a temporary for a call on the LHS. */ + if (decltype_p && !processing_template_decl + && TREE_CODE (assignment_expression) == CALL_EXPR + && CLASS_TYPE_P (TREE_TYPE (assignment_expression)) + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + assignment_expression + = build_cplus_new (TREE_TYPE (assignment_expression), + assignment_expression, tf_warning_or_error); + /* If this is the first assignment-expression, we can just save it away. */ if (!expression) @@ -7761,6 +7834,12 @@ cp_parser_expression (cp_parser* parser, bool cast_p, cp_id_kind * pidk) return expression; } +static inline tree +cp_parser_expression (cp_parser* parser, bool cast_p, cp_id_kind * pidk) +{ + return cp_parser_expression (parser, cast_p, /*decltype*/false, pidk); +} + /* Parse a constant-expression. constant-expression: @@ -11287,7 +11366,7 @@ cp_parser_decltype (cp_parser *parser) /* Parse a class member access. */ expr = cp_parser_postfix_expression (parser, /*address_p=*/false, - /*cast_p=*/false, + /*cast_p=*/false, /*decltype*/true, /*member_access_only_p=*/true, NULL); if (expr @@ -11315,7 +11394,8 @@ cp_parser_decltype (cp_parser *parser) parser->greater_than_is_operator_p = true; /* Parse a full expression. */ - expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); + expr = cp_parser_expression (parser, /*cast_p=*/false, + /*decltype*/true, NULL); /* The `>' token might be the end of a template-id or template-parameter-list now. */ @@ -22034,7 +22114,7 @@ static tree cp_parser_simple_cast_expression (cp_parser *parser) { return cp_parser_cast_expression (parser, /*address_p=*/false, - /*cast_p=*/false, NULL); + /*cast_p=*/false, /*decltype*/false, NULL); } /* Parse a functional cast to TYPE. Returns an expression @@ -26831,7 +26911,7 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) op = (token->type == CPP_PLUS_PLUS ? PREINCREMENT_EXPR : PREDECREMENT_EXPR); cp_lexer_consume_token (parser->lexer); - lhs = cp_parser_cast_expression (parser, false, false, NULL); + lhs = cp_parser_simple_cast_expression (parser); if (lhs != decl) return error_mark_node; return build2 (op, TREE_TYPE (decl), decl, NULL_TREE); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index edc2d0b..4ffc353 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11781,7 +11781,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) ++c_inhibit_evaluation_warnings; type = tsubst_expr (DECLTYPE_TYPE_EXPR (t), args, - complain, in_decl, + complain|tf_decltype, in_decl, /*integral_constant_expression_p=*/false); --cp_unevaluated_operand; @@ -13417,6 +13417,12 @@ tsubst_copy_and_build (tree t, if (EXPR_HAS_LOCATION (t)) input_location = EXPR_LOCATION (t); + /* N3276 decltype magic only applies to calls at the top level or on the + right side of a comma. */ + if (TREE_CODE (t) != CALL_EXPR + && TREE_CODE (t) != COMPOUND_EXPR) + complain &= ~tf_decltype; + switch (TREE_CODE (t)) { case USING_DECL: @@ -13848,10 +13854,16 @@ tsubst_copy_and_build (tree t, complain)); case COMPOUND_EXPR: - RETURN (build_x_compound_expr (EXPR_LOCATION (t), - RECUR (TREE_OPERAND (t, 0)), - RECUR (TREE_OPERAND (t, 1)), - complain)); + { + tree op0 = tsubst_copy_and_build (TREE_OPERAND (t, 0), args, + complain & ~tf_decltype, in_decl, + /*function_p=*/false, + integral_constant_expression_p); + RETURN (build_x_compound_expr (EXPR_LOCATION (t), + op0, + RECUR (TREE_OPERAND (t, 1)), + complain)); + } case CALL_EXPR: { @@ -13862,6 +13874,10 @@ tsubst_copy_and_build (tree t, bool koenig_p; tree ret; + /* Don't pass tf_decltype down to subexpressions. */ + tsubst_flags_t decltype_flag = (complain & tf_decltype); + complain &= ~tf_decltype; + function = CALL_EXPR_FN (t); /* When we parsed the expression, we determined whether or not Koenig lookup should be performed. */ @@ -14028,6 +14044,9 @@ tsubst_copy_and_build (tree t, if (DECL_P (function)) mark_used (function); + /* Put back tf_decltype for the actual call. */ + complain |= decltype_flag; + if (TREE_CODE (function) == OFFSET_REF) ret = build_offset_ref_call_from_tree (function, &call_args, complain); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 1b484b1..6dc33b9 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -469,6 +469,9 @@ build_cplus_new (tree type, tree init, tsubst_flags_t complain) tree rval = build_aggr_init_expr (type, init); tree slot; + if (!complete_type_or_maybe_complain (type, init, complain)) + return error_mark_node; + /* Make sure that we're not trying to create an instance of an abstract class. */ if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain)) diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype-call1.C b/gcc/testsuite/g++.dg/cpp0x/decltype-call1.C new file mode 100644 index 0000000..2616bb0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype-call1.C @@ -0,0 +1,32 @@ +// PR c++/52748 +// N3276 +// { dg-do compile { target c++11 } } + +struct A; // { dg-error "forward declaration" } +A f(); + +decltype(f()) g1(); // OK +decltype(((f()))) g2b(); // OK +decltype(42,f()) g3(); // OK +decltype(42,45,f()) g3b(); // OK +decltype(42,45,(f())) g3c(); // OK +decltype(42,((45,(f())))) g3c(); // OK + +decltype(f(),42) g4(); // { dg-error "" } +decltype(45,f(),42) g4b(); // { dg-error "" } + +class B +{ + ~B(); // { dg-error "private" } +public: + int i; + void operator[](int); +}; +B h(); + +void i(const B&); + +decltype(h()) g5a(); // OK +decltype(h().i) g5(); // { dg-error "" } +decltype(h()[0]) g6(); // { dg-error "" } +decltype(i(h())) g7(); // { dg-error "" }