re PR c++/36628 ([c++0x] incorrect decltype() handling of conditional operator)
PR c++/36628 * tree.c (rvalue): Use lvalue_or_rvalue_with_address_p. PR c++/37206 * cp-tree.h (enum cp_lvalue_kind_flags): Add clk_rvalueref. * tree.c (lvalue_p_1): Return it. Remove treat_class_rvalues_as_lvalues parm. (real_lvalue_p): Disallow pseudo-lvalues here. (lvalue_or_rvalue_with_address_p): New fn. * call.c (initialize_reference): Use it instead of real_lvalue_p. PR c++/40689 * init.c (build_new_1): Handle initializer list as array initializer. (build_vec_init): Likewise. * typeck.c (cp_build_modify_expr): Likewise. * typeck2.c (process_init_constructor_array): Error rather than abort if too many initializers. From-SVN: r149543
This commit is contained in:
parent
54caab810a
commit
3144f1e8d3
|
@ -1,3 +1,23 @@
|
|||
2009-07-12 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/36628
|
||||
* tree.c (rvalue): Use lvalue_or_rvalue_with_address_p.
|
||||
|
||||
PR c++/37206
|
||||
* cp-tree.h (enum cp_lvalue_kind_flags): Add clk_rvalueref.
|
||||
* tree.c (lvalue_p_1): Return it. Remove
|
||||
treat_class_rvalues_as_lvalues parm.
|
||||
(real_lvalue_p): Disallow pseudo-lvalues here.
|
||||
(lvalue_or_rvalue_with_address_p): New fn.
|
||||
* call.c (initialize_reference): Use it instead of real_lvalue_p.
|
||||
|
||||
PR c++/40689
|
||||
* init.c (build_new_1): Handle initializer list as array initializer.
|
||||
(build_vec_init): Likewise.
|
||||
* typeck.c (cp_build_modify_expr): Likewise.
|
||||
* typeck2.c (process_init_constructor_array): Error rather than abort
|
||||
if too many initializers.
|
||||
|
||||
2009-07-10 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/40502
|
||||
|
|
|
@ -7361,7 +7361,7 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
|
|||
expr = error_mark_node;
|
||||
else
|
||||
{
|
||||
if (!real_lvalue_p (expr))
|
||||
if (!lvalue_or_rvalue_with_address_p (expr))
|
||||
{
|
||||
tree init;
|
||||
var = set_up_extended_ref_temp (decl, expr, cleanup, &init);
|
||||
|
|
|
@ -3488,9 +3488,10 @@ enum tag_types {
|
|||
typedef enum cp_lvalue_kind {
|
||||
clk_none = 0, /* Things that are not an lvalue. */
|
||||
clk_ordinary = 1, /* An ordinary lvalue. */
|
||||
clk_class = 2, /* An rvalue of class-type. */
|
||||
clk_bitfield = 4, /* An lvalue for a bit-field. */
|
||||
clk_packed = 8 /* An lvalue for a packed field. */
|
||||
clk_rvalueref = 2,/* An rvalue formed using an rvalue reference */
|
||||
clk_class = 4, /* An rvalue of class-type. */
|
||||
clk_bitfield = 8, /* An lvalue for a bit-field. */
|
||||
clk_packed = 16 /* An lvalue for a packed field. */
|
||||
} cp_lvalue_kind;
|
||||
|
||||
/* Various kinds of template specialization, instantiation, etc. */
|
||||
|
@ -4851,6 +4852,7 @@ extern tree copy_binfo (tree, tree, tree,
|
|||
tree *, int);
|
||||
extern int member_p (const_tree);
|
||||
extern cp_lvalue_kind real_lvalue_p (tree);
|
||||
extern bool lvalue_or_rvalue_with_address_p (tree);
|
||||
extern bool builtin_valid_in_constant_expr_p (const_tree);
|
||||
extern tree build_min (enum tree_code, tree, ...);
|
||||
extern tree build_min_nt (enum tree_code, ...);
|
||||
|
|
|
@ -2118,7 +2118,28 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
|
|||
|
||||
if (array_p)
|
||||
{
|
||||
if (init)
|
||||
tree non_const_pointer_type = build_pointer_type
|
||||
(cp_build_qualified_type (type, TYPE_QUALS (type) & ~TYPE_QUAL_CONST));
|
||||
|
||||
if (init && TREE_CHAIN (init) == NULL_TREE
|
||||
&& BRACE_ENCLOSED_INITIALIZER_P (TREE_VALUE (init))
|
||||
&& CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
|
||||
{
|
||||
tree arraytype, domain;
|
||||
init = TREE_VALUE (init);
|
||||
if (TREE_CONSTANT (nelts))
|
||||
domain = compute_array_index_type (NULL_TREE, nelts);
|
||||
else
|
||||
{
|
||||
domain = NULL_TREE;
|
||||
if (CONSTRUCTOR_NELTS (init) > 0)
|
||||
warning (0, "non-constant array size in new, unable to "
|
||||
"verify length of initializer-list");
|
||||
}
|
||||
arraytype = build_cplus_array_type (type, domain);
|
||||
init = digest_init (arraytype, init);
|
||||
}
|
||||
else if (init)
|
||||
{
|
||||
if (complain & tf_error)
|
||||
permerror (input_location, "ISO C++ forbids initialization in array new");
|
||||
|
@ -2126,7 +2147,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
|
|||
return error_mark_node;
|
||||
}
|
||||
init_expr
|
||||
= build_vec_init (data_addr,
|
||||
= build_vec_init (fold_convert (non_const_pointer_type, data_addr),
|
||||
cp_build_binary_op (input_location,
|
||||
MINUS_EXPR, outer_nelts,
|
||||
integer_one_node,
|
||||
|
@ -2675,6 +2696,7 @@ build_vec_init (tree base, tree maxindex, tree init,
|
|||
|
||||
inner_elt_type = strip_array_types (type);
|
||||
if (init
|
||||
&& TREE_CODE (atype) == ARRAY_TYPE
|
||||
&& (from_array == 2
|
||||
? (!CLASS_TYPE_P (inner_elt_type)
|
||||
|| !TYPE_HAS_COMPLEX_ASSIGN_REF (inner_elt_type))
|
||||
|
@ -2690,7 +2712,6 @@ build_vec_init (tree base, tree maxindex, tree init,
|
|||
brace-enclosed initializers. In this case, digest_init and
|
||||
store_constructor will handle the semantics for us. */
|
||||
|
||||
gcc_assert (TREE_CODE (atype) == ARRAY_TYPE);
|
||||
stmt_expr = build2 (INIT_EXPR, atype, base, init);
|
||||
return stmt_expr;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ static tree build_cplus_array_type_1 (tree, tree);
|
|||
static int list_hash_eq (const void *, const void *);
|
||||
static hashval_t list_hash_pieces (tree, tree, tree);
|
||||
static hashval_t list_hash (const void *);
|
||||
static cp_lvalue_kind lvalue_p_1 (tree, int);
|
||||
static cp_lvalue_kind lvalue_p_1 (tree);
|
||||
static tree build_target_expr (tree, tree);
|
||||
static tree count_trees_r (tree *, int *, void *);
|
||||
static tree verify_stmt_tree_r (tree *, int *, void *);
|
||||
|
@ -55,12 +55,10 @@ static tree handle_com_interface_attribute (tree *, tree, tree, int, bool *);
|
|||
static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
|
||||
|
||||
/* If REF is an lvalue, returns the kind of lvalue that REF is.
|
||||
Otherwise, returns clk_none. If TREAT_CLASS_RVALUES_AS_LVALUES is
|
||||
nonzero, rvalues of class type are considered lvalues. */
|
||||
Otherwise, returns clk_none. */
|
||||
|
||||
static cp_lvalue_kind
|
||||
lvalue_p_1 (tree ref,
|
||||
int treat_class_rvalues_as_lvalues)
|
||||
lvalue_p_1 (tree ref)
|
||||
{
|
||||
cp_lvalue_kind op1_lvalue_kind = clk_none;
|
||||
cp_lvalue_kind op2_lvalue_kind = clk_none;
|
||||
|
@ -72,8 +70,7 @@ lvalue_p_1 (tree ref,
|
|||
if (TREE_CODE (ref) == INDIRECT_REF
|
||||
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0)))
|
||||
== REFERENCE_TYPE)
|
||||
return lvalue_p_1 (TREE_OPERAND (ref, 0),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
return lvalue_p_1 (TREE_OPERAND (ref, 0));
|
||||
|
||||
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
|
||||
{
|
||||
|
@ -82,12 +79,7 @@ lvalue_p_1 (tree ref,
|
|||
&& TREE_CODE (ref) != PARM_DECL
|
||||
&& TREE_CODE (ref) != VAR_DECL
|
||||
&& TREE_CODE (ref) != COMPONENT_REF)
|
||||
{
|
||||
if (CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (ref))))
|
||||
return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
|
||||
else
|
||||
return clk_none;
|
||||
}
|
||||
return clk_rvalueref;
|
||||
|
||||
/* lvalue references and named rvalue references are lvalues. */
|
||||
return clk_ordinary;
|
||||
|
@ -108,12 +100,10 @@ lvalue_p_1 (tree ref,
|
|||
case WITH_CLEANUP_EXPR:
|
||||
case REALPART_EXPR:
|
||||
case IMAGPART_EXPR:
|
||||
return lvalue_p_1 (TREE_OPERAND (ref, 0),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
return lvalue_p_1 (TREE_OPERAND (ref, 0));
|
||||
|
||||
case COMPONENT_REF:
|
||||
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0));
|
||||
/* Look at the member designator. */
|
||||
if (!op1_lvalue_kind)
|
||||
;
|
||||
|
@ -164,35 +154,28 @@ lvalue_p_1 (tree ref,
|
|||
if (TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 0))
|
||||
|| TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 1)))
|
||||
return clk_none;
|
||||
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0));
|
||||
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1));
|
||||
break;
|
||||
|
||||
case COND_EXPR:
|
||||
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1)
|
||||
? TREE_OPERAND (ref, 1)
|
||||
: TREE_OPERAND (ref, 0),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
: TREE_OPERAND (ref, 0));
|
||||
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2));
|
||||
break;
|
||||
|
||||
case MODIFY_EXPR:
|
||||
return clk_ordinary;
|
||||
|
||||
case COMPOUND_EXPR:
|
||||
return lvalue_p_1 (TREE_OPERAND (ref, 1),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
return lvalue_p_1 (TREE_OPERAND (ref, 1));
|
||||
|
||||
case TARGET_EXPR:
|
||||
return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
|
||||
return clk_class;
|
||||
|
||||
case VA_ARG_EXPR:
|
||||
return (treat_class_rvalues_as_lvalues
|
||||
&& CLASS_TYPE_P (TREE_TYPE (ref))
|
||||
? clk_class : clk_none);
|
||||
return (CLASS_TYPE_P (TREE_TYPE (ref)) ? clk_class : clk_none);
|
||||
|
||||
case CALL_EXPR:
|
||||
/* Any class-valued call would be wrapped in a TARGET_EXPR. */
|
||||
|
@ -207,8 +190,7 @@ lvalue_p_1 (tree ref,
|
|||
case BASELINK:
|
||||
/* We now represent a reference to a single static member function
|
||||
with a BASELINK. */
|
||||
return lvalue_p_1 (BASELINK_FUNCTIONS (ref),
|
||||
treat_class_rvalues_as_lvalues);
|
||||
return lvalue_p_1 (BASELINK_FUNCTIONS (ref));
|
||||
|
||||
case NON_DEPENDENT_EXPR:
|
||||
/* We must consider NON_DEPENDENT_EXPRs to be lvalues so that
|
||||
|
@ -244,18 +226,33 @@ lvalue_p_1 (tree ref,
|
|||
cp_lvalue_kind
|
||||
real_lvalue_p (tree ref)
|
||||
{
|
||||
return lvalue_p_1 (ref,
|
||||
/*treat_class_rvalues_as_lvalues=*/0);
|
||||
cp_lvalue_kind kind = lvalue_p_1 (ref);
|
||||
if (kind & (clk_rvalueref|clk_class))
|
||||
return clk_none;
|
||||
else
|
||||
return kind;
|
||||
}
|
||||
|
||||
/* This differs from real_lvalue_p in that class rvalues are
|
||||
considered lvalues. */
|
||||
/* This differs from real_lvalue_p in that class rvalues are considered
|
||||
lvalues. */
|
||||
|
||||
int
|
||||
lvalue_p (tree ref)
|
||||
{
|
||||
return
|
||||
(lvalue_p_1 (ref, /*class rvalue ok*/ 1) != clk_none);
|
||||
return (lvalue_p_1 (ref) != clk_none);
|
||||
}
|
||||
|
||||
/* This differs from real_lvalue_p in that rvalues formed by dereferencing
|
||||
rvalue references are considered rvalues. */
|
||||
|
||||
bool
|
||||
lvalue_or_rvalue_with_address_p (tree ref)
|
||||
{
|
||||
cp_lvalue_kind kind = lvalue_p_1 (ref);
|
||||
if (kind & clk_class)
|
||||
return false;
|
||||
else
|
||||
return (kind != clk_none);
|
||||
}
|
||||
|
||||
/* Test whether DECL is a builtin that may appear in a
|
||||
|
@ -532,7 +529,9 @@ rvalue (tree expr)
|
|||
if (!CLASS_TYPE_P (type) && cp_type_quals (type))
|
||||
type = TYPE_MAIN_VARIANT (type);
|
||||
|
||||
if (!processing_template_decl && real_lvalue_p (expr))
|
||||
/* We need to do this for rvalue refs as well to get the right answer
|
||||
from decltype; see c++/36628. */
|
||||
if (!processing_template_decl && lvalue_or_rvalue_with_address_p (expr))
|
||||
expr = build1 (NON_LVALUE_EXPR, type, expr);
|
||||
else if (type != TREE_TYPE (expr))
|
||||
expr = build_nop (type, expr);
|
||||
|
|
|
@ -6091,8 +6091,11 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
|
|||
{
|
||||
int from_array;
|
||||
|
||||
if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
|
||||
TYPE_MAIN_VARIANT (TREE_TYPE (rhs))))
|
||||
if (BRACE_ENCLOSED_INITIALIZER_P (rhs))
|
||||
rhs = digest_init (lhstype, rhs);
|
||||
|
||||
else if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
|
||||
TYPE_MAIN_VARIANT (TREE_TYPE (rhs))))
|
||||
{
|
||||
if (complain & tf_error)
|
||||
error ("incompatible types in assignment of %qT to %qT",
|
||||
|
@ -6101,7 +6104,8 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
|
|||
}
|
||||
|
||||
/* Allow array assignment in compiler-generated code. */
|
||||
if (!current_function_decl || !DECL_ARTIFICIAL (current_function_decl))
|
||||
else if (!current_function_decl
|
||||
|| !DECL_ARTIFICIAL (current_function_decl))
|
||||
{
|
||||
/* This routine is used for both initialization and assignment.
|
||||
Make sure the diagnostic message differentiates the context. */
|
||||
|
|
|
@ -906,10 +906,9 @@ process_init_constructor_array (tree type, tree init)
|
|||
/* Vectors are like simple fixed-size arrays. */
|
||||
len = TYPE_VECTOR_SUBPARTS (type);
|
||||
|
||||
/* There cannot be more initializers than needed as otherwise
|
||||
reshape_init would have already rejected the initializer. */
|
||||
if (!unbounded)
|
||||
gcc_assert (VEC_length (constructor_elt, v) <= len);
|
||||
/* There must not be more initializers than needed. */
|
||||
if (!unbounded && VEC_length (constructor_elt, v) > len)
|
||||
error ("too many initializers for %qT", type);
|
||||
|
||||
for (i = 0; VEC_iterate (constructor_elt, v, i, ce); ++i)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
2009-07-12 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/36628
|
||||
* g++.dg/cpp0x/decltype17.C: New.
|
||||
|
||||
PR c++/37206
|
||||
* g++.dg/cpp0x/rv10.C: New.
|
||||
|
||||
2009-07-12 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/40689
|
||||
* g++.dg/cpp0x/initlist20.C: New.
|
||||
* g++.dg/cpp0x/initlist21.C: New.
|
||||
|
||||
2009-07-11 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR target/40668
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// PR c++/36628
|
||||
// { dg-options "-std=c++0x" }
|
||||
// { dg-do run }
|
||||
|
||||
#include <typeinfo>
|
||||
#include <string.h>
|
||||
|
||||
int rvalue();
|
||||
int& lvalueref();
|
||||
int&& rvalueref();
|
||||
|
||||
decltype(true ? rvalue() : rvalue()) f()
|
||||
{}
|
||||
|
||||
decltype(true ? lvalueref() : lvalueref()) g()
|
||||
{}
|
||||
|
||||
decltype(true ? rvalueref() : rvalueref()) h()
|
||||
{}
|
||||
|
||||
int main()
|
||||
{
|
||||
if (strcmp (typeid(f).name(), "FivE") != 0)
|
||||
return 1;
|
||||
if (strcmp (typeid(g).name(), "FRivE") != 0)
|
||||
return 2;
|
||||
if (strcmp (typeid(h).name(), "FivE") != 0)
|
||||
return 3;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// PR c++/40689
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
class X
|
||||
{
|
||||
public:
|
||||
X(): data {1,2,3,4,5} {}
|
||||
private:
|
||||
const short data[5];
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
const float * pData = new const float[4] { 1.5, 2.5, 3.5, 4.5 };
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// PR c++/40689
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
class X
|
||||
{
|
||||
public:
|
||||
X(): data {1,2} {} // { dg-error "too many initializers" }
|
||||
private:
|
||||
const short data[1];
|
||||
};
|
||||
|
||||
int f(int n)
|
||||
{
|
||||
const float * pData = new const float[1] { 1.5, 2.5 }; // { dg-error "too many initializers" }
|
||||
pData = new const float[n] { 1.5, 2.5 }; // { dg-warning "array size" }
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
struct A
|
||||
{
|
||||
A() = default;
|
||||
A(const A&) = delete;
|
||||
};
|
||||
|
||||
A&& f();
|
||||
void h(A&&);
|
||||
void g()
|
||||
{
|
||||
A&& arr = f();
|
||||
h(f());
|
||||
}
|
Loading…
Reference in New Issue