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
This commit is contained in:
Jason Merrill 2013-03-16 22:37:09 -04:00 committed by Jason Merrill
parent 2df663cced
commit 57fcd4f4e4
7 changed files with 203 additions and 35 deletions

View File

@ -1,5 +1,24 @@
2013-03-16 Jason Merrill <jason@redhat.com>
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

View File

@ -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);
}

View File

@ -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. */

View File

@ -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<tree, va_gc> *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<tree, va_gc> *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);

View File

@ -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);

View File

@ -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))

View File

@ -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 "" }