Index: c-typeck.c =================================================================== --- c-typeck.c (revision 146612) +++ c-typeck.c (working copy) @@ -4292,6 +4292,8 @@ c_cast_expr (struct c_type_name *type_na } /* Build an assignment expression of lvalue LHS from value RHS. + If LHS_ORIGTYPE is not NULL, it is the original type of LHS, which + may differ from TREE_TYPE (LHS) for an enum bitfield. MODIFYCODE is the code for a binary operator that we use to combine the old value of LHS with RHS to get the new value. Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment. @@ -4301,9 +4303,8 @@ c_cast_expr (struct c_type_name *type_na LOCATION is the location of the MODIFYCODE operator. */ tree -build_modify_expr (location_t location, - tree lhs, enum tree_code modifycode, tree rhs, - tree rhs_origtype) +build_modify_expr (location_t location, tree lhs, tree lhs_origtype, + enum tree_code modifycode, tree rhs, tree rhs_origtype) { tree result; tree newrhs; @@ -4333,7 +4334,8 @@ build_modify_expr (location_t location, if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR) { tree inner = build_modify_expr (location, C_MAYBE_CONST_EXPR_EXPR (lhs), - modifycode, rhs, rhs_origtype); + lhs_origtype, modifycode, rhs, + rhs_origtype); if (inner == error_mark_node) return error_mark_node; result = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), @@ -4393,6 +4395,23 @@ build_modify_expr (location_t location, TREE_TYPE (lhs) = lhstype; } + /* Issue -Wc++-compat warnings about an assignment to an enum type + when LHS does not have its original type. This happens for, + e.g., an enum bitfield in a struct. */ + if (warn_cxx_compat + && lhs_origtype != NULL_TREE + && lhs_origtype != lhstype + && TREE_CODE (lhs_origtype) == ENUMERAL_TYPE) + { + tree checktype = (rhs_origtype != NULL_TREE + ? rhs_origtype + : TREE_TYPE (rhs)); + if (checktype != error_mark_node + && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype)) + warning_at (location, OPT_Wc___compat, + "enum conversion in assignment is invalid in C++"); + } + /* Convert new value to destination type. Fold it first, then restore any excess precision information, for the sake of conversion warnings. */ @@ -4553,9 +4572,9 @@ convert_for_assignment (tree type, tree && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) { /* FIXME: Until the gcc source code is converted, we only - warn about parameter passing. We will add the other - cases when bootstrap succeeds with them. */ - if (errtype == ic_argpass) + warn about assignment and parameter passing. We will add + the other cases when bootstrap succeeds with them. */ + if (errtype == ic_argpass || errtype == ic_assign) { WARN_FOR_ASSIGNMENT (input_location, OPT_Wc___compat, G_("enum conversion when passing argument " Index: c-omp.c =================================================================== --- c-omp.c (revision 146612) +++ c-omp.c (working copy) @@ -142,7 +142,7 @@ c_finish_omp_atomic (enum tree_code code /* There are lots of warnings, errors, and conversions that need to happen in the course of interpreting a statement. Use the normal mechanisms to do this, and then take it apart again. */ - x = build_modify_expr (input_location, lhs, code, rhs, NULL_TREE); + x = build_modify_expr (input_location, lhs, NULL_TREE, code, rhs, NULL_TREE); if (x == error_mark_node) return error_mark_node; gcc_assert (TREE_CODE (x) == MODIFY_EXPR); @@ -260,7 +260,8 @@ c_finish_omp_for (location_t locus, tree fail = true; } - init = build_modify_expr (elocus, decl, NOP_EXPR, init, NULL_TREE); + init = build_modify_expr (elocus, decl, NULL_TREE, NOP_EXPR, init, + NULL_TREE); } gcc_assert (TREE_CODE (init) == MODIFY_EXPR); gcc_assert (TREE_OPERAND (init, 0) == decl); Index: c-common.h =================================================================== --- c-common.h (revision 146612) +++ c-common.h (working copy) @@ -413,7 +413,8 @@ extern tree add_stmt (tree); extern void push_cleanup (tree, tree, bool); extern tree pushdecl_top_level (tree); extern tree pushdecl (tree); -extern tree build_modify_expr (location_t, tree, enum tree_code, tree, tree); +extern tree build_modify_expr (location_t, tree, tree, enum tree_code, + tree, tree); extern tree build_indirect_ref (location_t, tree, const char *); extern int c_expand_decl (tree); Index: c-parser.c =================================================================== --- c-parser.c (revision 146612) +++ c-parser.c (working copy) @@ -4443,8 +4443,8 @@ c_parser_expr_no_commas (c_parser *parse c_parser_consume_token (parser); rhs = c_parser_expr_no_commas (parser, NULL); rhs = default_function_array_conversion (rhs); - ret.value = build_modify_expr (op_location, lhs.value, code, rhs.value, - rhs.original_type); + ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, + code, rhs.value, rhs.original_type); if (code == NOP_EXPR) ret.original_code = MODIFY_EXPR; else @@ -7823,18 +7823,20 @@ c_parser_omp_for_loop (c_parser *parser, else if (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_2nd_token (parser)->type == CPP_EQ) { + struct c_expr decl_exp; struct c_expr init_exp; location_t init_loc; - decl = c_parser_postfix_expression (parser).value; + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; c_parser_require (parser, CPP_EQ, "expected %<=%>"); init_loc = c_parser_peek_token (parser)->location; init_exp = c_parser_expr_no_commas (parser, NULL); init_exp = default_function_array_conversion (init_exp); - init = build_modify_expr (init_loc, - decl, NOP_EXPR, init_exp.value, + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_exp.value, init_exp.original_type); init = c_process_expr_stmt (init); Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 146612) +++ cp/typeck.c (working copy) @@ -5870,7 +5870,8 @@ cp_build_c_cast (tree type, tree expr, t /* For use from the C common bits. */ tree build_modify_expr (location_t location ATTRIBUTE_UNUSED, - tree lhs, enum tree_code modifycode, tree rhs, + tree lhs, tree lhs_origtype ATTRIBUTE_UNUSED, + enum tree_code modifycode, tree rhs, tree rhs_origtype ATTRIBUTE_UNUSED) { return cp_build_modify_expr (lhs, modifycode, rhs, tf_warning_or_error); Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 146612) +++ cp/semantics.c (working copy) @@ -4128,7 +4128,8 @@ handle_omp_for_class_iterator (int i, lo cond = cp_build_binary_op (elocus, TREE_CODE (cond), decl, diff, tf_warning_or_error); - incr = build_modify_expr (elocus, decl, PLUS_EXPR, incr, NULL_TREE); + incr = build_modify_expr (elocus, decl, NULL_TREE, PLUS_EXPR, + incr, NULL_TREE); orig_body = *body; *body = push_stmt_list (); Index: objc/objc-act.c =================================================================== --- objc/objc-act.c (revision 146612) +++ objc/objc-act.c (working copy) @@ -8740,9 +8740,8 @@ get_super_receiver (void) /* Set receiver to self. */ super_expr = objc_build_component_ref (UOBJC_SUPER_decl, self_id); - super_expr = build_modify_expr (input_location, - super_expr, NOP_EXPR, self_decl, - NULL_TREE); + super_expr = build_modify_expr (input_location, super_expr, NULL_TREE, + NOP_EXPR, self_decl, NULL_TREE); super_expr_list = super_expr; /* Set class to begin searching. */ @@ -8754,7 +8753,8 @@ get_super_receiver (void) /* [_cls, __cls]Super are "pre-built" in synth_forward_declarations. */ - super_expr = build_modify_expr (input_location, super_expr, NOP_EXPR, + super_expr = build_modify_expr (input_location, super_expr, + NULL_TREE, NOP_EXPR, ((TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) ? ucls_super_ref @@ -8807,7 +8807,8 @@ get_super_receiver (void) } super_expr - = build_modify_expr (input_location, super_expr, NOP_EXPR, + = build_modify_expr (input_location, super_expr, NULL_TREE, + NOP_EXPR, build_c_cast (TREE_TYPE (super_expr), super_class), NULL_TREE); Index: testsuite/gcc.dg/Wcxx-compat-4.c =================================================================== --- testsuite/gcc.dg/Wcxx-compat-4.c (revision 0) +++ testsuite/gcc.dg/Wcxx-compat-4.c (revision 0) @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-Wc++-compat" } */ +enum E1 { A, B, C }; +enum E2 { D, E, F }; + +enum E1 g1; +enum E2 g2; + +void +f1 () +{ + int a; + int d; + enum E1 e1; + enum E2 e2; + a = A; + a = !B; + d = E; + e1 = A; + e1 = D; /* { dg-warning "invalid in C\[+\]\[+\]" } */ + e1 = 0; /* { dg-warning "invalid in C\[+\]\[+\]" } */ + e1 = (enum E1) 0; + e1 = (enum E2) 0; /* { dg-warning "invalid in C\[+\]\[+\]" } */ + e1 = e2; /* { dg-warning "invalid in C\[+\]\[+\]" } */ + e1 = g1; + e1 = g2; /* { dg-warning "invalid in C\[+\]\[+\]" } */ + e2 = A; /* { dg-warning "invalid in C\[+\]\[+\]" } */ + e2 = D; +} + +struct s { enum E1 e1 : 3; }; + +void +f2 (struct s sv) +{ + sv.e1 = A; + sv.e1 = D; /* { dg-warning "invalid in C\[+\]\[+\]" } */ + g1 = sv.e1; + g2 = sv.e1; /* { dg-warning "invalid in C\[+\]\[+\]" } */ +} + +void +f3 (struct s *pv) +{ + pv->e1 = A; + pv->e1 = D; /* { dg-warning "invalid in C\[+\]\[+\]" } */ + g1 = pv->e1; + g2 = pv->e1; /* { dg-warning "invalid in C\[+\]\[+\]" } */ +}