aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2006-05-19 03:01:14 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2006-05-19 03:01:14 +0000
commit41990f964687332cd2ea2ad59a02c18ed499db6c (patch)
treee4b7d562777fd7a64677150037b1ea3eaa0694ff
parent84e2e37098ecd0a1085501dade4348e33fe5a695 (diff)
downloadgcc-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/ChangeLog25
-rw-r--r--gcc/cp/call.c33
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/except.c38
-rw-r--r--gcc/cp/init.c22
-rw-r--r--gcc/cp/tree.c33
-rw-r--r--gcc/cp/typeck.c56
-rw-r--r--gcc/cp/typeck2.c4
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/conversion/bitfield5.C14
-rw-r--r--gcc/testsuite/g++.dg/conversion/bitfield6.C10
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);
+}