aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/call.c24
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/parser.c128
-rw-r--r--gcc/cp/pt.c29
-rw-r--r--gcc/cp/tree.c3
6 files changed, 171 insertions, 35 deletions
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 <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
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<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);
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))