diff options
author | Mark Mitchell <mark@codesourcery.com> | 2006-05-19 03:01:14 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2006-05-19 03:01:14 +0000 |
commit | 41990f964687332cd2ea2ad59a02c18ed499db6c (patch) | |
tree | e4b7d562777fd7a64677150037b1ea3eaa0694ff | |
parent | 84e2e37098ecd0a1085501dade4348e33fe5a695 (diff) | |
download | gcc-41990f964687332cd2ea2ad59a02c18ed499db6c.zip gcc-41990f964687332cd2ea2ad59a02c18ed499db6c.tar.gz gcc-41990f964687332cd2ea2ad59a02c18ed499db6c.tar.bz2 |
re PR c++/27471 (ICE within build_c_cast cp/typeck.c:5434)
PR c++/27471
PR c++/27506
* typeck.c (decay_conversion): Convert bitfields to their declared
types here. Improve documentation. Avoid use of cp_convert.
(default_conversion): Make it static. Perform integral promotions
before lvalue-to-rvalue, function-to-pointer, and array-to-pointer
conversions.
* init.c (build_init): Remove.
(expand_default_init): Do not call rvalue.
* call.c (null_ptr_cst_p): Robustify.
(build_conditional_expr): Tidy.
* except.c (build_throw): Do not perform lvalue-to-rvalue
conversion on operand before initializing temporary.
* tree.c (convert.h): Include it.
(convert_bitfield_to_declared_type): Use convert_to_integer, not
cp_convert.
(rvalue): Don't convert bitfields to their declared type here.
* cp-tree.h (build_init): Remove.
(default_conversion): Likewise.
* typeck2.c (build_m_component_ref): Do not perform
lvalue-to-rvalue, function-to-pointer, or array-to-pointer
conversions here. Correct error message.
PR c++/27471
PR c++/27506
* g++.dg/conversion/bitfield5.C: New test.
* g++.dg/conversion/bitfield6.C: New test.
From-SVN: r113902
-rw-r--r-- | gcc/cp/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/cp/call.c | 33 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 2 | ||||
-rw-r--r-- | gcc/cp/except.c | 38 | ||||
-rw-r--r-- | gcc/cp/init.c | 22 | ||||
-rw-r--r-- | gcc/cp/tree.c | 33 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 56 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/conversion/bitfield5.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/conversion/bitfield6.C | 10 |
11 files changed, 172 insertions, 72 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0d99050..3c13cc0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2006-05-18 Mark Mitchell <mark@codesourcery.com> + + PR c++/27471 + PR c++/27506 + * typeck.c (decay_conversion): Convert bitfields to their declared + types here. Improve documentation. Avoid use of cp_convert. + (default_conversion): Make it static. Perform integral promotions + before lvalue-to-rvalue, function-to-pointer, and array-to-pointer + conversions. + * init.c (build_init): Remove. + (expand_default_init): Do not call rvalue. + * call.c (null_ptr_cst_p): Robustify. + (build_conditional_expr): Tidy. + * except.c (build_throw): Do not perform lvalue-to-rvalue + conversion on operand before initializing temporary. + * tree.c (convert.h): Include it. + (convert_bitfield_to_declared_type): Use convert_to_integer, not + cp_convert. + (rvalue): Don't convert bitfields to their declared type here. + * cp-tree.h (build_init): Remove. + (default_conversion): Likewise. + * typeck2.c (build_m_component_ref): Do not perform + lvalue-to-rvalue, function-to-pointer, or array-to-pointer + conversions here. Correct error message. + 2006-05-17 Mark Mitchell <mark@codesourcery.com> PR c++/26122 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index a7cb22a..9e69772 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -426,11 +426,14 @@ null_ptr_cst_p (tree t) A null pointer constant is an integral constant expression (_expr.const_) rvalue of integer type that evaluates to zero. */ t = integral_constant_value (t); - if (t == null_node - || (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) - && integer_zerop (t) - && !TREE_CONSTANT_OVERFLOW (t))) + if (t == null_node) return true; + if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t)) + { + STRIP_NOPS (t); + if (!TREE_CONSTANT_OVERFLOW (t)) + return true; + } return false; } @@ -3518,16 +3521,18 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3) /* We can't use result_type below, as fold might have returned a throw_expr. */ - /* Expand both sides into the same slot, hopefully the target of the - ?: expression. We used to check for TARGET_EXPRs here, but now we - sometimes wrap them in NOP_EXPRs so the test would fail. */ - if (!lvalue_p && CLASS_TYPE_P (TREE_TYPE (result))) - result = get_target_expr (result); - - /* If this expression is an rvalue, but might be mistaken for an - lvalue, we must add a NON_LVALUE_EXPR. */ - if (!lvalue_p && real_lvalue_p (result)) - result = rvalue (result); + if (!lvalue_p) + { + /* Expand both sides into the same slot, hopefully the target of + the ?: expression. We used to check for TARGET_EXPRs here, + but now we sometimes wrap them in NOP_EXPRs so the test would + fail. */ + if (CLASS_TYPE_P (TREE_TYPE (result))) + result = get_target_expr (result); + /* If this expression is an rvalue, but might be mistaken for an + lvalue, we must add a NON_LVALUE_EXPR. */ + result = rvalue (result); + } return result; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3837628..cac801d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3973,7 +3973,6 @@ extern tree do_friend (tree, tree, tree, tree, enum overload_flags, bool); extern tree expand_member_init (tree); extern void emit_mem_initializers (tree); extern tree build_aggr_init (tree, tree, int); -extern tree build_init (tree, tree, int); extern int is_aggr_type (tree, int); extern tree get_type_value (tree); extern tree build_zero_init (tree, tree, bool); @@ -4357,7 +4356,6 @@ extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, bool); extern tree inline_conversion (tree); extern tree is_bitfield_expr_with_lowered_type (tree); extern tree decay_conversion (tree); -extern tree default_conversion (tree); extern tree build_class_member_access_expr (tree, tree, tree, bool); extern tree finish_class_member_access_expr (tree, tree, bool); extern tree build_x_indirect_ref (tree, const char *); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index d82c07f..efdbd91 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -638,6 +638,7 @@ build_throw (tree exp) else if (exp) { tree throw_type; + tree temp_type; tree cleanup; tree object, ptr; tree tmp; @@ -666,9 +667,17 @@ build_throw (tree exp) fn = push_throw_library_fn (fn, tmp); } - /* throw expression */ - /* First, decay it. */ - exp = decay_conversion (exp); + /* [except.throw] + + A throw-expression initializes a temporary object, the type + of which is determined by removing any top-level + cv-qualifiers from the static type of the operand of throw + and adjusting the type from "array of T" or "function return + T" to "pointer to T" or "pointer to function returning T" + respectively. */ + temp_type = is_bitfield_expr_with_lowered_type (exp); + if (!temp_type) + temp_type = type_decays_to (TYPE_MAIN_VARIANT (TREE_TYPE (exp))); /* OK, this is kind of wacky. The standard says that we call terminate when the exception handling mechanism, after @@ -684,21 +693,32 @@ build_throw (tree exp) matter, since it can't throw). */ /* Allocate the space for the exception. */ - allocate_expr = do_allocate_exception (TREE_TYPE (exp)); + allocate_expr = do_allocate_exception (temp_type); allocate_expr = get_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); - object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr); + object = build_nop (build_pointer_type (temp_type), ptr); object = build_indirect_ref (object, NULL); elided = (TREE_CODE (exp) == TARGET_EXPR); /* And initialize the exception object. */ - exp = build_init (object, exp, LOOKUP_ONLYCONVERTING); - if (exp == error_mark_node) + if (CLASS_TYPE_P (temp_type)) { - error (" in thrown expression"); - return error_mark_node; + /* Call the copy constructor. */ + exp = (build_special_member_call + (object, complete_ctor_identifier, + build_tree_list (NULL_TREE, exp), + TREE_TYPE (object), + LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)); + if (exp == error_mark_node) + { + error (" in thrown expression"); + return error_mark_node; + } } + else + exp = build2 (INIT_EXPR, temp_type, object, + decay_conversion (exp)); /* Pre-evaluate the thrown expression first, since if we allocated the space first we would have to deal with cleaning it up if diff --git a/gcc/cp/init.c b/gcc/cp/init.c index bc6df20..e9528f2 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1142,26 +1142,6 @@ build_aggr_init (tree exp, tree init, int flags) return stmt_expr; } -/* Like build_aggr_init, but not just for aggregates. */ - -tree -build_init (tree decl, tree init, int flags) -{ - tree expr; - - if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - expr = build_aggr_init (decl, init, flags); - else if (CLASS_TYPE_P (TREE_TYPE (decl))) - expr = build_special_member_call (decl, complete_ctor_identifier, - build_tree_list (NULL_TREE, init), - TREE_TYPE (decl), - LOOKUP_NORMAL|flags); - else - expr = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init); - - return expr; -} - static void expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags) { @@ -2057,7 +2037,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init, rval = build_nop (pointer_type, rval); /* A new-expression is never an lvalue. */ - rval = rvalue (rval); + gcc_assert (!lvalue_p (rval)); return rval; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index bc8e737..81b37d6 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -35,6 +35,7 @@ Boston, MA 02110-1301, USA. */ #include "tree-inline.h" #include "debug.h" #include "target.h" +#include "convert.h" static tree bot_manip (tree *, int *, void *); static tree bot_replace (tree *, int *, void *); @@ -373,7 +374,8 @@ convert_bitfield_to_declared_type (tree expr) bitfield_type = is_bitfield_expr_with_lowered_type (expr); if (bitfield_type) - expr = cp_convert (TYPE_MAIN_VARIANT (bitfield_type), expr); + expr = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type), + expr); return expr; } @@ -383,18 +385,23 @@ convert_bitfield_to_declared_type (tree expr) tree rvalue (tree expr) { - expr = convert_bitfield_to_declared_type (expr); - if (real_lvalue_p (expr)) - { - tree type; - /* [basic.lval] - - Non-class rvalues always have cv-unqualified types. */ - type = TREE_TYPE (expr); - if (!CLASS_TYPE_P (type)) - type = TYPE_MAIN_VARIANT (type); - expr = build1 (NON_LVALUE_EXPR, type, expr); - } + tree type; + + if (error_operand_p (expr)) + return expr; + + /* [basic.lval] + + Non-class rvalues always have cv-unqualified types. */ + type = TREE_TYPE (expr); + if (!CLASS_TYPE_P (type) && cp_type_quals (type)) + type = TYPE_MAIN_VARIANT (type); + + if (!processing_template_decl && real_lvalue_p (expr)) + expr = build1 (NON_LVALUE_EXPR, type, expr); + else if (type != TREE_TYPE (expr)) + expr = build_nop (type, expr); + return expr; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 3eeb837..e275f76 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1426,10 +1426,14 @@ is_bitfield_expr_with_lowered_type (tree exp) /* Perform the conversions in [expr] that apply when an lvalue appears in an rvalue context: the lvalue-to-rvalue, array-to-pointer, and - function-to-pointer conversions. + function-to-pointer conversions. In addition, manifest constants + are replaced by their values, and bitfield references are converted + to their declared types. - In addition, manifest constants are replaced by their values, and - bitfield references are converted to their declared types. */ + Although the returned value is being used as an rvalue, this + function does not wrap the returned expression in a + NON_LVALUE_EXPR; the caller is expected to be mindful of the fact + that the return value is no longer an lvalue. */ tree decay_conversion (tree exp) @@ -1448,6 +1452,8 @@ decay_conversion (tree exp) } exp = decl_constant_value (exp); + if (error_operand_p (exp)) + return error_mark_node; /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. Leave such NOP_EXPRs, since RHS is being used in non-lvalue context. */ @@ -1498,22 +1504,52 @@ decay_conversion (tree exp) adr = build_unary_op (ADDR_EXPR, exp, 1); return cp_convert (ptrtype, adr); } + + /* If a bitfield is used in a context where integral promotion + applies, then the caller is expected to have used + default_conversion. That function promotes bitfields correctly + before calling this function. At this point, if we have a + bitfield referenced, we may assume that is not subject to + promotion, and that, therefore, the type of the resulting rvalue + is the declared type of the bitfield. */ + exp = convert_bitfield_to_declared_type (exp); - /* [basic.lval]: Class rvalues can have cv-qualified types; non-class - rvalues always have cv-unqualified types. */ - if (! CLASS_TYPE_P (type)) - exp = cp_convert (TYPE_MAIN_VARIANT (type), exp); + /* We do not call rvalue() here because we do not want to wrap EXP + in a NON_LVALUE_EXPR. */ + + /* [basic.lval] + + Non-class rvalues always have cv-unqualified types. */ + type = TREE_TYPE (exp); + if (!CLASS_TYPE_P (type) && cp_type_quals (type)) + exp = build_nop (TYPE_MAIN_VARIANT (type), exp); return exp; } -tree +/* Perform prepatory conversions, as part of the "usual arithmetic + conversions". In particular, as per [expr]: + + Whenever an lvalue expression appears as an operand of an + operator that expects the rvalue for that operand, the + lvalue-to-rvalue, array-to-pointer, or function-to-pointer + standard conversions are applied to convert the expression to an + rvalue. + + In addition, we perform integral promotions here, as those are + applied to both operands to a binary operator before determining + what additional conversions should apply. */ + +static tree default_conversion (tree exp) { - exp = decay_conversion (exp); - + /* Perform the integral promotions first so that bitfield + expressions (which may promote to "int", even if the bitfield is + declared "unsigned") are promoted correctly. */ if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (exp))) exp = perform_integral_promotions (exp); + /* Perform the other conversions. */ + exp = decay_conversion (exp); return exp; } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 52d7a9e..5356faa 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1200,8 +1200,6 @@ build_m_component_ref (tree datum, tree component) tree binfo; tree ctype; - datum = decay_conversion (datum); - if (datum == error_mark_node || component == error_mark_node) return error_mark_node; @@ -1218,7 +1216,7 @@ build_m_component_ref (tree datum, tree component) if (! IS_AGGR_TYPE (objtype)) { error ("cannot apply member pointer %qE to %qE, which is of " - "non-aggregate type %qT", + "non-class type %qT", component, datum, objtype); return error_mark_node; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8f57ec3..540995b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2006-05-18 Mark Mitchell <mark@codesourcery.com> + + PR c++/27471 + PR c++/27506 + * g++.dg/conversion/bitfield5.C: New test. + * g++.dg/conversion/bitfield6.C: New test. + 2006-05-18 Mike Stump <mrs@apple.com> * gcc.dg/c90-arraydecl-1.c: Update for vla, vm [*] fixups. diff --git a/gcc/testsuite/g++.dg/conversion/bitfield5.C b/gcc/testsuite/g++.dg/conversion/bitfield5.C new file mode 100644 index 0000000..b931ec9 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/bitfield5.C @@ -0,0 +1,14 @@ +// PR c++/27506 + +enum EBorderStyle + { + BNATIVE, BHIDDEN + }; +struct BorderValue +{ + enum EBorderStyle style:8; +}; +enum EBorderStyle f(const struct BorderValue *border) +{ + return border ? border->style : BNATIVE; +} diff --git a/gcc/testsuite/g++.dg/conversion/bitfield6.C b/gcc/testsuite/g++.dg/conversion/bitfield6.C new file mode 100644 index 0000000..79664ab --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/bitfield6.C @@ -0,0 +1,10 @@ +// PR c++/27471 + +struct A { unsigned a:8; }; + +extern void b(unsigned char); + +void breakme (A f) +{ + b((unsigned char) f.a); +} |