From patchwork Wed Jun 23 21:21:05 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Le-Chun Wu X-Patchwork-Id: 56721 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 9156EB6F11 for ; Thu, 24 Jun 2010 07:21:59 +1000 (EST) Received: (qmail 5014 invoked by alias); 23 Jun 2010 21:21:50 -0000 Received: (qmail 4934 invoked by uid 22791); 23 Jun 2010 21:21:27 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, TW_CX, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.35) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 23 Jun 2010 21:21:10 +0000 Received: from wpaz33.hot.corp.google.com (wpaz33.hot.corp.google.com [172.24.198.97]) by smtp-out.google.com with ESMTP id o5NLL6RV019459 for ; Wed, 23 Jun 2010 14:21:07 -0700 Received: from gwb1 (gwb1.prod.google.com [10.200.2.1]) by wpaz33.hot.corp.google.com with ESMTP id o5NLL5pv018150 for ; Wed, 23 Jun 2010 14:21:06 -0700 Received: by gwb1 with SMTP id 1so1000961gwb.30 for ; Wed, 23 Jun 2010 14:21:05 -0700 (PDT) MIME-Version: 1.0 Received: by 10.101.134.23 with SMTP id l23mr7239009ann.129.1277328065431; Wed, 23 Jun 2010 14:21:05 -0700 (PDT) Received: by 10.101.80.17 with HTTP; Wed, 23 Jun 2010 14:21:05 -0700 (PDT) In-Reply-To: References: Date: Wed, 23 Jun 2010 14:21:05 -0700 Message-ID: Subject: [patch] [C/C++] Add a new warning flag -Wself-assign From: Le-Chun Wu To: =?ISO-8859-1?Q?Manuel_L=F3pez=2DIb=E1=F1ez?= , "Joseph S. Myers" , Jason Merrill , rguenther@suse.de Cc: Andrew Pinski , GCC Patches , Diego Novillo X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi, Here is the revised patch for the implementation of -Wself-assign warning. Besides minor changes that address the review comments, the major differences of this revised patch from the original one are (1) -Wself-assign is enabled by -Wall, and (2) -Winit-self flag is removed. (For the discussion thread of the original patch, please see http://gcc.gnu.org/ml/gcc-patches/2010-06/msg00974.html) Bootstrapped and tested on x86_64-linux-gnu. OK for trunk? Thanks, Le-chun 2010-06-23 Le-Chun Wu * gcc/doc/invoke.texi (-Wall): Include -Wself-assign. (-Wself-assign): New documentation for the flag. (-Winit-self): Removed. (-Wuninitialized): Remove mention of -Winit-self. (-Wunused-variable): Mention of new workaround. * gcc/c-family/c-gimplify.c (c_gimplify_expr): Remove support for -Winit-self. * gcc/c-family/c.opt: Remove -Winit-self and add -Wself-assign. * gcc/c-family/c-opts.c : Enable -Wself-assign by -Wall. * gcc/c-family/c-common.c (check_for_self_assign): New function. * gcc/c-family/c-common.h: Add prototype for check_for_self_assign. * gcc/tree.h(tree_base): Add a new tree_base flag indicating if an expression is the result of constant-folding. (operand_equal_flag): Add two new flags for operand_equal_p routine. * gcc/fold-const.c (operand_equal_p): Support comparison of NULL operands and operands without types. (set_expr_folded_flag): New helper function. (fold_unary_loc_1): Renamed from fold_unary_loc. (fold_unary_loc): A wrapper around fold_unary_loc_1 function that sets the EXPR_FOLDED flag of the folded expression if folding is successful. (fold_binary_loc_1): Renamed from fold_binary_loc. (fold_binary_loc): A wrapper around fold_binary_loc_1 function that sets the EXPR_FOLDED flag of the folded expression if folding is successful. (fold_ternary_loc_1): Renamed from fold_ternary_loc. (fold_ternary_loc): A wrapper around fold_ternary_loc_1 function that sets the EXPR_FOLDED flag of the folded expression if folding is successful. * gcc/testsuite/gcc.dg/plugin/selfassign.c (check_self_assign): Renamed from warn_self_assign. * gcc/testsuite/gcc.dg/wself-assign-1.c: New test. * gcc/testsuite/gcc.dg/wself-assign-2.c: New test. * gcc/testsuite/gcc.dg/wself-assign-3.c: New test. * gcc/testsuite/gcc.dg/uninit-D-O0.c: Removed. * gcc/testsuite/gcc.dg/uninit-D.c: Removed. * gcc/testsuite/gcc.dg/uninit-E-O0.c: Removed. * gcc/testsuite/gcc.dg/uninit-E.c: Removed. * gcc/testsuite/g++.dg/plugin/selfassign.c (check_self_assign): Renamed from warn_self_assign. * gcc/testsuite/g++.dg/warn/Wself-assign-1.C: New test. * gcc/testsuite/g++.dg/warn/Wself-assign-2.C: New test. * gcc/testsuite/g++.dg/warn/Wself-assign-3.C: New test. * gcc/testsuite/g++.dg/warn/Wself-assign-4.C: New test. * gcc/testsuite/g++.dg/warn/Wself-assign-5.C: New test. * gcc/cp/init.c (perform_member_init): Check for self-assign after parsing class member initialization. * gcc/cp/parser.c (cp_parser_assignment_expression): Check for self-assign after parsing an assignment. (cp_parser_init_declarator): Check for self-assign after parsing variable initialization. * gcc/c-parser.c (c_parser_declaration_or_fndef): Check for self-assign after parsing variable initialization. (c_parser_expr_no_commas): Check for self-assign after parsing an assignment. Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 161236) +++ gcc/doc/invoke.texi (working copy) @@ -242,8 +242,7 @@ Objective-C and Objective-C++ Dialects}. -Wformat-security -Wformat-y2k @gol -Wframe-larger-than=@var{len} -Wjump-misses-init -Wignored-qualifiers @gol -Wimplicit -Wimplicit-function-declaration -Wimplicit-int @gol --Winit-self -Winline @gol --Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol +-Winline -Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol -Winvalid-pch -Wlarger-than=@var{len} -Wunsafe-loop-optimizations @gol -Wlogical-op -Wlong-long @gol -Wmain -Wmissing-braces -Wmissing-field-initializers @gol @@ -254,7 +253,7 @@ Objective-C and Objective-C++ Dialects}. -Wparentheses -Wpedantic-ms-format -Wno-pedantic-ms-format @gol -Wpointer-arith -Wno-pointer-to-int-cast @gol -Wredundant-decls @gol --Wreturn-type -Wsequence-point -Wshadow @gol +-Wreturn-type -Wself-assign -Wsequence-point -Wshadow @gol -Wsign-compare -Wsign-conversion -Wstack-protector @gol -Wstrict-aliasing -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol @@ -2943,6 +2942,7 @@ Options} and @ref{Objective-C and Object -Wpointer-sign @gol -Wreorder @gol -Wreturn-type @gol +-Wself-assign @r{(only in C/C++)} @gol -Wsequence-point @gol -Wsign-compare @r{(only in C++)} @gol -Wstrict-aliasing @gol @@ -3143,24 +3143,6 @@ requiring a non-null value by the @code{ @option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}. It can be disabled with the @option{-Wno-nonnull} option. -@item -Winit-self @r{(C, C++, Objective-C and Objective-C++ only)} -@opindex Winit-self -@opindex Wno-init-self -Warn about uninitialized variables which are initialized with themselves. -Note this option can only be used with the @option{-Wuninitialized} option. - -For example, GCC will warn about @code{i} being uninitialized in the -following snippet only when @option{-Winit-self} has been specified: -@smallexample -@group -int f() -@{ - int i = i; - return i; -@} -@end group -@end smallexample - @item -Wimplicit-int @r{(C and Objective-C only)} @opindex Wimplicit-int @opindex Wno-implicit-int @@ -3323,6 +3305,53 @@ definitions, may be found on the GCC rea This warning is enabled by @option{-Wall} for C and C++. +@item -Wself-assign +@opindex Wself-assign +@opindex Wno-self-assign +Warn about self-assignment and self-initialization. This warning is intended +for detecting accidental self-assignment due to typos, and therefore does +not warn on a statement that is semantically a self-assignment after +constant folding. Here is an example of what will trigger a self-assign +warning and what will not: + +@smallexample +@group +void func() +@{ + int i = 2; + int x = x; /* warn */ + float f = 5.0; + double a[3]; + + i = i + 0; /* not warn */ + f = f / 1; /* not warn */ + a[1] = a[1]; /* warn */ + i += 0; /* not warn */ +@} +@end group +@end smallexample + +There are cases where self-assignment might be intentional. For example, +a C++ programmers might write code to test whether an overloaded +@code{operator=} works when the same object is assigned to itself. +One way to work around the self-assign warning in such case is using +the functional form @code{object.operator=(object)} instead of the +assignment form @code{object = object}, as shown in the following example. + +@smallexample +@group +void test_func() +@{ + MyType t; + + t.operator=(t); // not warn + t = t; // warn +@} +@end group +@end smallexample + +This warning is enabled by @option{-Wall} for C and C++. + @item -Wreturn-type @opindex Wreturn-type @opindex Wno-return-type @@ -3446,6 +3475,10 @@ This warning is enabled by @option{-Wall To suppress this warning use the @samp{unused} attribute (@pxref{Variable Attributes}). +Note that a classic way to avoid @option{-Wunused-variable} warning is +using @code{x = x}, but that does not work with @option{-Wself-assign}. +Use @code{(void) x} or @code{static_cast(x)} instead. + @item -Wunused-value @opindex Wunused-value @opindex Wno-unused-value @@ -3475,9 +3508,6 @@ or if a variable may be clobbered by a @ warn if a non-static reference or non-static @samp{const} member appears in a class without constructors. -If you want to warn about code which uses the uninitialized value of the -variable in its own initializer, use the @option{-Winit-self} option. - These warnings occur for individual uninitialized or clobbered elements of structure, union or array variables as well as for variables which are uninitialized or clobbered as a whole. They do Index: gcc/c-family/c-gimplify.c =================================================================== --- gcc/c-family/c-gimplify.c (revision 161236) +++ gcc/c-family/c-gimplify.c (working copy) @@ -173,18 +173,5 @@ int c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED, gimple_seq *post_p ATTRIBUTE_UNUSED) { - enum tree_code code = TREE_CODE (*expr_p); - - /* This is handled mostly by gimplify.c, but we have to deal with - not warning about int x = x; as it is a GCC extension to turn off - this warning but only if warn_init_self is zero. */ - if (code == DECL_EXPR - && TREE_CODE (DECL_EXPR_DECL (*expr_p)) == VAR_DECL - && !DECL_EXTERNAL (DECL_EXPR_DECL (*expr_p)) - && !TREE_STATIC (DECL_EXPR_DECL (*expr_p)) - && (DECL_INITIAL (DECL_EXPR_DECL (*expr_p)) == DECL_EXPR_DECL (*expr_p)) - && !warn_init_self) - TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1; - return GS_UNHANDLED; } Index: gcc/c-family/c.opt =================================================================== --- gcc/c-family/c.opt (revision 161236) +++ gcc/c-family/c.opt (working copy) @@ -258,10 +258,6 @@ Wignored-qualifiers C C++ Var(warn_ignored_qualifiers) Init(-1) Warning Warn whenever type qualifiers are ignored. -Winit-self -C ObjC C++ ObjC++ Var(warn_init_self) Warning -Warn about variables which are initialized to themselves - Wimplicit C ObjC Var(warn_implicit) Init(-1) Warning Warn about implicit declarations @@ -425,6 +421,10 @@ Wreturn-type C ObjC C++ ObjC++ Var(warn_return_type) Warning Warn whenever a function's return type defaults to \"int\" (C), or about inconsistent return types (C++) +Wself-assign +C C++ Var(warn_self_assign) Init(0) Warning +Warn when a variable is assigned to itself + Wselector ObjC ObjC++ Var(warn_selector) Warning Warn if a selector has multiple methods Index: gcc/c-family/c-opts.c =================================================================== --- gcc/c-family/c-opts.c (revision 161236) +++ gcc/c-family/c-opts.c (working copy) @@ -486,6 +486,7 @@ c_common_handle_option (size_t scode, co warn_unknown_pragmas = value; warn_uninitialized = value; + warn_self_assign = value; if (!c_dialect_cxx ()) { Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c (revision 161236) +++ gcc/c-family/c-common.c (working copy) @@ -9266,4 +9266,20 @@ make_tree_vector_copy (const VEC(tree,gc return ret; } +/* Check for and warn about self-assignment or self-initialization. + LHS and RHS are the tree nodes for the left-hand side and right-hand side + of the assignment or initialization we are checking. + LOCATION is the source location for RHS. */ + +void +check_for_self_assign (location_t location, tree lhs, tree rhs) +{ + /* Only emit a warning if RHS is not a folded expression so that we don't + warn on something like x = x / 1. */ + if (!EXPR_FOLDED (rhs) + && operand_equal_p (lhs, rhs, + OEP_PURE_SAME | OEP_ALLOW_NULL | OEP_ALLOW_NULL_TYPE)) + warning_at (location, OPT_Wself_assign, "%qE is assigned to itself", lhs); +} + #include "gt-c-family-c-common.h" Index: gcc/c-family/c-common.h =================================================================== --- gcc/c-family/c-common.h (revision 161236) +++ gcc/c-family/c-common.h (working copy) @@ -893,6 +893,7 @@ extern VEC(tree,gc) *make_tree_vector (v extern void release_tree_vector (VEC(tree,gc) *); extern VEC(tree,gc) *make_tree_vector_single (tree); extern VEC(tree,gc) *make_tree_vector_copy (const VEC(tree,gc) *); +extern void check_for_self_assign (location_t, tree, tree); /* In c-gimplify.c */ extern void c_genericize (tree); Index: gcc/tree.h =================================================================== --- gcc/tree.h (revision 161236) +++ gcc/tree.h (working copy) @@ -388,8 +388,9 @@ struct GTY(()) tree_base { unsigned visited : 1; unsigned packed_flag : 1; unsigned user_align : 1; + unsigned expr_folded_flag : 1; - unsigned spare : 13; + unsigned spare : 12; /* This field is only used with type nodes; the only reason it is present in tree_base instead of tree_type is to save space. The size of the @@ -627,6 +628,13 @@ struct GTY(()) tree_common { SSA_NAME_IS_DEFAULT_DEF in SSA_NAME + + expr_folded_flag: + + EXPR_FOLDED in + all expressions + all decls + all constants */ #undef DEFTREESTRUCT @@ -1363,6 +1371,10 @@ extern void omp_clause_range_check_faile /* In fixed-point types, means a saturating type. */ #define TYPE_SATURATING(NODE) ((NODE)->base.saturating_flag) +/* Nonzero in an expression, a decl, or a constant node if the node is + the result of a successful constant-folding. */ +#define EXPR_FOLDED(NODE) ((NODE)->base.expr_folded_flag) + /* These flags are available for each language front end to use internally. */ #define TREE_LANG_FLAG_0(NODE) ((NODE)->base.lang_flag_0) #define TREE_LANG_FLAG_1(NODE) ((NODE)->base.lang_flag_1) @@ -4931,7 +4943,9 @@ extern bool fold_deferring_overflow_warn enum operand_equal_flag { OEP_ONLY_CONST = 1, - OEP_PURE_SAME = 2 + OEP_PURE_SAME = 2, + OEP_ALLOW_NULL = 4, /* Allow comparison of NULL operands. */ + OEP_ALLOW_NULL_TYPE = 8 /* Allow comparison of operands without types. */ }; extern int operand_equal_p (const_tree, const_tree, unsigned int); Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 161236) +++ gcc/fold-const.c (working copy) @@ -2404,22 +2404,45 @@ combine_comparisons (location_t loc, If OEP_PURE_SAME is set, then pure functions with identical arguments are considered the same. It is used when the caller has other ways - to ensure that global memory is unchanged in between. */ + to ensure that global memory is unchanged in between. + + If OEP_ALLOW_NULL is set, this routine will not crash on NULL operands, + and two NULL operands are considered equal. This flag is usually set + in the context of frontend when ARG0 and/or ARG1 may be NULL mostly due + to recursion on partially built expressions (e.g. a CAST_EXPR on a NULL + tree.) In this case, we certainly don't want the compiler to crash and + it's OK to consider two NULL operands equal. On the other hand, when + called in the context of code generation and optimization, if NULL + operands are not expected, silently ignoring them could be dangerous + and might cause problems downstream that are hard to find/debug. In that + case, the flag should probably not be set. */ int operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) { + /* If either is NULL, they must be both NULL to be equal. We only do this + check when OEP_ALLOW_NULL is set. */ + if ((flags & OEP_ALLOW_NULL) && (!arg0 || !arg1)) + return arg0 == arg1; + + /* Similar, if either does not have a type (like a released SSA name, or + an operand whose type depends on a template parameter), they aren't + equal, unless OEP_ALLOW_NULL_TYPE is set, in which case we will continue + to compare the operands only when both don't have a type. */ + if (!TREE_TYPE (arg0) || !TREE_TYPE (arg1)) + { + if (((~flags) & OEP_ALLOW_NULL_TYPE) + || ((TREE_TYPE (arg0) && !TREE_TYPE (arg1)) + || (!TREE_TYPE (arg0) && TREE_TYPE (arg1)))) + return 0; + } + /* If either is ERROR_MARK, they aren't equal. */ if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK || TREE_TYPE (arg0) == error_mark_node || TREE_TYPE (arg1) == error_mark_node) return 0; - /* Similar, if either does not have a type (like a released SSA name), - they aren't equal. */ - if (!TREE_TYPE (arg0) || !TREE_TYPE (arg1)) - return 0; - /* Check equality of integer constants before bailing out due to precision differences. */ if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) @@ -2430,19 +2453,25 @@ operand_equal_p (const_tree arg0, const_ because they may change the signedness of the arguments. As pointers strictly don't have a signedness, require either two pointers or two non-pointers as well. */ - if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1)) - || POINTER_TYPE_P (TREE_TYPE (arg0)) != POINTER_TYPE_P (TREE_TYPE (arg1))) + if (TREE_TYPE (arg0) + && (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1)) + || (POINTER_TYPE_P (TREE_TYPE (arg0)) + != POINTER_TYPE_P (TREE_TYPE (arg1))))) return 0; /* We cannot consider pointers to different address space equal. */ - if (POINTER_TYPE_P (TREE_TYPE (arg0)) && POINTER_TYPE_P (TREE_TYPE (arg1)) - && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0))) - != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1))))) + if (TREE_TYPE (arg0) + && (POINTER_TYPE_P (TREE_TYPE (arg0)) + && POINTER_TYPE_P (TREE_TYPE (arg1)) + && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0))) + != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1)))))) return 0; /* If both types don't have the same precision, then it is not safe to strip NOPs. */ - if (TYPE_PRECISION (TREE_TYPE (arg0)) != TYPE_PRECISION (TREE_TYPE (arg1))) + if (TREE_TYPE (arg0) + && (TYPE_PRECISION (TREE_TYPE (arg0)) + != TYPE_PRECISION (TREE_TYPE (arg1)))) return 0; STRIP_NOPS (arg0); @@ -2467,9 +2496,10 @@ operand_equal_p (const_tree arg0, const_ if (TREE_CODE (arg0) != TREE_CODE (arg1) /* This is needed for conversions and for COMPONENT_REF. Might as well play it safe and always test this. */ - || TREE_CODE (TREE_TYPE (arg0)) == ERROR_MARK - || TREE_CODE (TREE_TYPE (arg1)) == ERROR_MARK - || TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1))) + || (TREE_TYPE (arg0) + && (TREE_CODE (TREE_TYPE (arg0)) == ERROR_MARK + || TREE_CODE (TREE_TYPE (arg1)) == ERROR_MARK + || TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1))))) return 0; /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal. @@ -2502,7 +2532,8 @@ operand_equal_p (const_tree arg0, const_ return 1; - if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))) + if (TREE_TYPE (arg0) + && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))) { /* If we do not distinguish between signed and unsigned zero, consider them equal. */ @@ -2570,8 +2601,9 @@ operand_equal_p (const_tree arg0, const_ { CASE_CONVERT: case FIX_TRUNC_EXPR: - if (TYPE_UNSIGNED (TREE_TYPE (arg0)) - != TYPE_UNSIGNED (TREE_TYPE (arg1))) + if (TREE_TYPE (arg0) + && (TYPE_UNSIGNED (TREE_TYPE (arg0)) + != TYPE_UNSIGNED (TREE_TYPE (arg1)))) return 0; break; default: @@ -7653,8 +7685,8 @@ build_fold_addr_expr_loc (location_t loc OP0. Return the folded expression if folding is successful. Otherwise, return NULL_TREE. */ -tree -fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) +static tree +fold_unary_loc_1 (location_t loc, enum tree_code code, tree type, tree op0) { tree tem; tree arg0; @@ -8302,6 +8334,41 @@ fold_unary_loc (location_t loc, enum tre } /* switch (code) */ } +/* Given an expression tree EXP, set the EXPR_FOLDED flag, and if it is + a nop, recursively set the EXPR_FOLDED flag of its operand. */ + +static void +set_expr_folded_flag (tree exp) +{ + EXPR_FOLDED (exp) = 1; + + /* If EXP is a nop (i.e. NON_LVALUE_EXPRs and NOP_EXPRs), we need to + recursively set the EXPR_FOLDED flag of its operand because the + expression will be stripped later. */ + while ((CONVERT_EXPR_P (exp) + || TREE_CODE (exp) == NON_LVALUE_EXPR) + && TREE_OPERAND (exp, 0) != error_mark_node) + { + exp = TREE_OPERAND (exp, 0); + EXPR_FOLDED (exp) = 1; + } +} + +/* Fold a unary expression of code CODE and type TYPE with operand + OP0. Return the folded expression if folding is successful. + Otherwise, return NULL_TREE. + This is a wrapper around fold_unary_loc_1 function (which does the + actual folding). Set the EXPR_FOLDED flag of the folded expression + if folding is successful. */ + +tree +fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) +{ + tree tem = fold_unary_loc_1 (loc, code, type, op0); + if (tem) + set_expr_folded_flag (tem); + return tem; +} /* If the operation was a conversion do _not_ mark a resulting constant with TREE_OVERFLOW if the original constant was not. These conversions @@ -9394,8 +9461,8 @@ get_pointer_modulus_and_residue (tree ex Return the folded expression if folding is successful. Otherwise, return NULL_TREE. */ -tree -fold_binary_loc (location_t loc, +static tree +fold_binary_loc_1 (location_t loc, enum tree_code code, tree type, tree op0, tree op1) { enum tree_code_class kind = TREE_CODE_CLASS (code); @@ -13066,6 +13133,24 @@ fold_binary_loc (location_t loc, return tem; } +/* Fold a binary expression of code CODE and type TYPE with operands + OP0 and OP1. LOC is the location of the resulting expression. + Return the folded expression if folding is successful. Otherwise, + return NULL_TREE. + This is a wrapper around fold_binary_loc_1 function (which does the + actual folding). Set the EXPR_FOLDED flag of the folded expression + if folding is successful. */ + +tree +fold_binary_loc (location_t loc, + enum tree_code code, tree type, tree op0, tree op1) +{ + tree tem = fold_binary_loc_1 (loc, code, type, op0, op1); + if (tem) + set_expr_folded_flag (tem); + return tem; +} + /* Callback for walk_tree, looking for LABEL_EXPR. Return *TP if it is a LABEL_EXPR; otherwise return NULL_TREE. Do not check the subtrees of GOTO_EXPR. */ @@ -13102,8 +13187,8 @@ contains_label_p (tree st) OP0, OP1, and OP2. Return the folded expression if folding is successful. Otherwise, return NULL_TREE. */ -tree -fold_ternary_loc (location_t loc, enum tree_code code, tree type, +static tree +fold_ternary_loc_1 (location_t loc, enum tree_code code, tree type, tree op0, tree op1, tree op2) { tree tem; @@ -13438,6 +13523,23 @@ fold_ternary_loc (location_t loc, enum t } /* switch (code) */ } +/* Fold a ternary expression of code CODE and type TYPE with operands + OP0, OP1, and OP2. Return the folded expression if folding is + successful. Otherwise, return NULL_TREE. + This is a wrapper around fold_ternary_loc_1 function (which does the + actual folding). Set the EXPR_FOLDED flag of the folded expression + if folding is successful. */ + +tree +fold_ternary_loc (location_t loc, enum tree_code code, tree type, + tree op0, tree op1, tree op2) +{ + tree tem = fold_ternary_loc_1 (loc, code, type, op0, op1, op2); + if (tem) + set_expr_folded_flag (tem); + return tem; +} + /* Perform constant folding and related simplification of EXPR. The related simplifications include x*1 => x, x*0 => 0, etc., and application of the associative law. Index: gcc/testsuite/gcc.dg/plugin/selfassign.c =================================================================== --- gcc/testsuite/gcc.dg/plugin/selfassign.c (revision 161236) +++ gcc/testsuite/gcc.dg/plugin/selfassign.c (working copy) @@ -196,7 +196,7 @@ compare_and_warn (gimple stmt, tree lhs, /* Check and warn if STMT is a self-assign statement. */ static void -warn_self_assign (gimple stmt) +check_self_assign (gimple stmt) { tree rhs, lhs; @@ -251,7 +251,7 @@ execute_warn_self_assign (void) FOR_EACH_BB (bb) { for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - warn_self_assign (gsi_stmt (gsi)); + check_self_assign (gsi_stmt (gsi)); } return 0; Index: gcc/testsuite/gcc.dg/wself-assign-1.c =================================================================== --- gcc/testsuite/gcc.dg/wself-assign-1.c (revision 0) +++ gcc/testsuite/gcc.dg/wself-assign-1.c (revision 0) @@ -0,0 +1,27 @@ +/* Test the self-assignemnt detection and warning. */ +/* { dg-do compile } */ +/* { dg-options "-Wself-assign" } */ + +struct Bar { + int b_; + int c_; +}; + +int g; + +int main() +{ + struct Bar *bar; + int x = x; /* { dg-warning "assigned to itself" } */ + static int y; + struct Bar b_array[5]; + + b_array[x+g].b_ = b_array[x+g].b_; /* { dg-warning "assigned to itself" } */ + g = g; /* { dg-warning "assigned to itself" } */ + y = y; /* { dg-warning "assigned to itself" } */ + bar->b_ = bar->b_; /* { dg-warning "assigned to itself" } */ + x += 0; /* should not warn */ + y -= 0; /* should not warn */ + x /= x; /* should not warn */ + y *= y; /* should not warn */ +} Index: gcc/testsuite/gcc.dg/wself-assign-2.c =================================================================== --- gcc/testsuite/gcc.dg/wself-assign-2.c (revision 0) +++ gcc/testsuite/gcc.dg/wself-assign-2.c (revision 0) @@ -0,0 +1,24 @@ +/* Test how self-assignment detection handles constant-folding happening */ +/* when parsing the RHS or the initializer. */ +/* { dg-do compile } */ +/* { dg-options "-Wself-assign" } */ + +struct Bar { + int b_; + float c_; +}; + +int g; + +int main() +{ + struct Bar *bar; + int x = x - 0; /* should not warn */ + static int y; + struct Bar b_array[5]; + + b_array[x+g].b_ = b_array[x+g].b_ * 1; /* should no warn */ + g = g + 0; /* should not warn */ + y = y / 1; /* should not warn */ + bar->b_ = bar->b_ - 0; /* should not warn */ +} Index: gcc/testsuite/gcc.dg/wself-assign-3.c =================================================================== --- gcc/testsuite/gcc.dg/wself-assign-3.c (revision 0) +++ gcc/testsuite/gcc.dg/wself-assign-3.c (revision 0) @@ -0,0 +1,9 @@ +/* Test whether -Wself-assign is enabled by -Wall. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +int bar() { + int i = 0; + i = i; /* { dg-warning "assigned to itself" } */ + return i; +} Index: gcc/testsuite/gcc.dg/uninit-D-O0.c =================================================================== --- gcc/testsuite/gcc.dg/uninit-D-O0.c (revision 161236) +++ gcc/testsuite/gcc.dg/uninit-D-O0.c (working copy) @@ -1,9 +0,0 @@ -/* Test we do not warn about initializing variable with self. */ -/* { dg-do compile } */ -/* { dg-options "-Wuninitialized" } */ - -int f() -{ - int i = i; - return i; -} Index: gcc/testsuite/gcc.dg/uninit-D.c =================================================================== --- gcc/testsuite/gcc.dg/uninit-D.c (revision 161236) +++ gcc/testsuite/gcc.dg/uninit-D.c (working copy) @@ -1,9 +0,0 @@ -/* Test we do not warn about initializing variable with self. */ -/* { dg-do compile } */ -/* { dg-options "-O -Wuninitialized" } */ - -int f() -{ - int i = i; - return i; -} Index: gcc/testsuite/gcc.dg/uninit-E-O0.c =================================================================== --- gcc/testsuite/gcc.dg/uninit-E-O0.c (revision 161236) +++ gcc/testsuite/gcc.dg/uninit-E-O0.c (working copy) @@ -1,9 +0,0 @@ -/* Test we do warn about initializing variable with self when -Winit-self is supplied. */ -/* { dg-do compile } */ -/* { dg-options "-Wuninitialized -Winit-self" } */ - -int f() -{ - int i = i; /* { dg-warning "i" "uninitialized variable warning" } */ - return i; -} Index: gcc/testsuite/gcc.dg/uninit-E.c =================================================================== --- gcc/testsuite/gcc.dg/uninit-E.c (revision 161236) +++ gcc/testsuite/gcc.dg/uninit-E.c (working copy) @@ -1,9 +0,0 @@ -/* Test we do warn about initializing variable with self when -Winit-self is supplied. */ -/* { dg-do compile } */ -/* { dg-options "-O -Wuninitialized -Winit-self" } */ - -int f() -{ - int i = i; /* { dg-warning "i" "uninitialized variable warning" } */ - return i; -} Index: gcc/testsuite/g++.dg/plugin/selfassign.c =================================================================== --- gcc/testsuite/g++.dg/plugin/selfassign.c (revision 161236) +++ gcc/testsuite/g++.dg/plugin/selfassign.c (working copy) @@ -196,7 +196,7 @@ compare_and_warn (gimple stmt, tree lhs, /* Check and warn if STMT is a self-assign statement. */ static void -warn_self_assign (gimple stmt) +check_self_assign (gimple stmt) { tree rhs, lhs; @@ -251,7 +251,7 @@ execute_warn_self_assign (void) FOR_EACH_BB (bb) { for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - warn_self_assign (gsi_stmt (gsi)); + check_self_assign (gsi_stmt (gsi)); } return 0; Index: gcc/testsuite/g++.dg/warn/Wself-assign-1.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wself-assign-1.C (revision 0) +++ gcc/testsuite/g++.dg/warn/Wself-assign-1.C (revision 0) @@ -0,0 +1,54 @@ +// Test the self-assignemnt detection and warning. +// { dg-do compile } +// { dg-options "-Wself-assign" } + +class Foo { + private: + int a_; + + public: + Foo() : a_(a_) {} // { dg-warning "assigned to itself" } + + void setA(int a) { + a_ = a_; // { dg-warning "assigned to itself" } + } + + void operator=(Foo& rhs) { + this->a_ = rhs.a_; + } +}; + +struct Bar { + int b_; + int c_; +}; + +int g = g; // { dg-warning "assigned to itself" } +Foo foo = foo; // { dg-warning "assigned to itself" } + +int func() +{ + Bar *bar1, bar2; + Foo local_foo; + int x = x; // { dg-warning "assigned to itself" } + static int y = y; // { dg-warning "assigned to itself" } + float *f; + Bar bar_array[5]; + char n; + int overflow; + + *f = *f; // { dg-warning "assigned to itself" } + bar1->b_ = bar1->b_; // { dg-warning "assigned to itself" } + bar2.c_ = bar2.c_; // { dg-warning "assigned to itself" } + local_foo = local_foo; // { dg-warning "assigned to itself" } + foo = foo; // { dg-warning "assigned to itself" } + foo.setA(5); + bar_array[3].c_ = bar_array[3].c_; // { dg-warning "assigned to itself" } + bar_array[x+g].b_ = bar_array[x+g].b_; // { dg-warning "assigned to itself" } + y = x; + x = y; + x += 0; // should not warn + y -= 0; // should not warn + x /= x; // should not warn + y *= y; // should not warn +} Index: gcc/testsuite/g++.dg/warn/Wself-assign-2.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wself-assign-2.C (revision 0) +++ gcc/testsuite/g++.dg/warn/Wself-assign-2.C (revision 0) @@ -0,0 +1,31 @@ +// Test the handling of expressions that depend on template parameters in +// self-assignemnt detection. +// { dg-do compile } +// { dg-options "-Wself-assign" } + +template +struct Bar { + T x; + Bar operator++(int) { + Bar tmp = *this; + ++x; + tmp = tmp; // { dg-warning "assigned to itself" } + return tmp; + } +}; + +template +T DoSomething(T y) { + T a[5], *p; + Bar b; + b.x = b.x; // { dg-warning "assigned to itself" } + *p = *p; // { dg-warning "assigned to itself" } + a[2] = a[2]; // { dg-warning "assigned to itself" } + return *p; +} + +main() { + Bar bar; + bar++; + DoSomething(5); +} Index: gcc/testsuite/g++.dg/warn/Wself-assign-3.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wself-assign-3.C (revision 0) +++ gcc/testsuite/g++.dg/warn/Wself-assign-3.C (revision 0) @@ -0,0 +1,35 @@ +// Test how operands_equal_p handles a NULL operand. +// { dg-do compile } +// { dg-options "-Wself-assign" } + +#include + +namespace testing { + +class Foo { + int f; + public: + Foo() { printf("Construct Foo\n"); } +}; + +class Bar { + int b; + public: + Bar(int x) { printf("Construct Bar\n"); } + + void operator=(const Foo& foo) { + printf("Assign Foo to Bar\n"); + } +}; + +} + +template +void func(T t) { + ::testing::Bar(1) = ::testing::Foo(); // used to trigger a segfault + ::testing::Foo() = ::testing::Foo(); // { dg-warning "assigned to itself" } +} + +main() { + func(2); +} Index: gcc/testsuite/g++.dg/warn/Wself-assign-4.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wself-assign-4.C (revision 0) +++ gcc/testsuite/g++.dg/warn/Wself-assign-4.C (revision 0) @@ -0,0 +1,48 @@ +// Test how self-assignment detection handles constant-folding happening +// when parsing the RHS or the initializer. +// { dg-do compile } +// { dg-options "-Wself-assign" } + +class Foo { + private: + int a_; + + public: + Foo() : a_(a_+0) {} // should not warn + + void setA(int a) { + a_ = a_ + 0; // should not warn + } + + void operator=(Foo& rhs) { + this->a_ = rhs.a_; + } +}; + +struct Bar { + int b_; + float c_; +}; + +int g = g * 1; // should not warn + +int func() +{ + Bar *bar1, bar2; + Foo foo; + int x = x - 0; // should not warn + static int y = y / 1; // should not warn + float *f; + Bar bar_array[5]; + + *f = *f / 1; // should not warn + bar1->b_ = bar1->b_ * 1; // should not warn + bar2.c_ = bar2.c_ - 0; // should not warn + foo.setA(5); + bar_array[3].c_ = bar_array[3].c_ * 1; // should not warn + bar_array[x+g].b_ = bar_array[x+g].b_ / 1; // should not warn + x += 0; + y -= 0; + foo = foo; // { dg-warning "assigned to itself" } + foo.operator=(foo); // should not warn +} Index: gcc/testsuite/g++.dg/warn/Wself-assign-5.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wself-assign-5.C (revision 0) +++ gcc/testsuite/g++.dg/warn/Wself-assign-5.C (revision 0) @@ -0,0 +1,21 @@ +// Test whether -Wself-assign is enabled by -Wall. +// { dg-do compile } +// { dg-options "-Wall" } + +class Foo { + int a, b; + public: + Foo() : a(a) { } // { dg-warning "assigned to itself" } + int foo() { return b; } +}; + +int c = c; // { dg-warning "assigned to itself" } + +Foo foo; + +int bar() { + static int d = d; // { dg-warning "assigned to itself" } + int i = 0; + i = i; // { dg-warning "assigned to itself" } + return d; +} Index: gcc/cp/init.c =================================================================== --- gcc/cp/init.c (revision 161236) +++ gcc/cp/init.c (working copy) @@ -529,8 +529,14 @@ perform_member_init (tree member, tree i init = build_x_compound_expr_from_list (init, ELK_MEM_INIT); if (init) - finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init, - tf_warning_or_error)); + { + finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init, + tf_warning_or_error)); + /* Check for and warn about self-initialization if -Wself-assign is + enabled. */ + if (warn_self_assign) + check_for_self_assign (input_location, decl, init); + } } if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 161236) +++ gcc/cp/parser.c (working copy) @@ -6903,6 +6903,12 @@ cp_parser_assignment_expression (cp_pars if (cp_parser_non_integral_constant_expression (parser, NIC_ASSIGNMENT)) return error_mark_node; + + /* Check for and warn about self-assignment if -Wself-assign is + enabled and the assignment operator is "=". */ + if (warn_self_assign && assignment_operator == NOP_EXPR) + check_for_self_assign (input_location, expr, rhs); + /* Build the assignment expression. */ expr = build_x_modify_expr (expr, assignment_operator, @@ -14075,6 +14081,10 @@ cp_parser_init_declarator (cp_parser* pa `explicit' constructor cannot be used. */ ((is_direct_init || !is_initialized) ? 0 : LOOKUP_ONLYCONVERTING)); + /* Check for and warn about self-initialization if -Wself-assign is + enabled. */ + if (warn_self_assign && initializer) + check_for_self_assign (input_location, decl, initializer); } else if ((cxx_dialect != cxx98) && friend_p && decl && TREE_CODE (decl) == FUNCTION_DECL) Index: gcc/c-parser.c =================================================================== --- gcc/c-parser.c (revision 161236) +++ gcc/c-parser.c (working copy) @@ -1297,6 +1297,11 @@ c_parser_declaration_or_fndef (c_parser maybe_warn_string_init (TREE_TYPE (d), init); finish_decl (d, init_loc, init.value, init.original_type, asm_name); + /* Check for and warn about self-initialization if + -Wself-assign is enabled. Don't warn if there is + already an error for the initializer. */ + if (warn_self_assign && DECL_INITIAL (d) != error_mark_node) + check_for_self_assign (here, d, init.value); } } else @@ -4767,7 +4772,13 @@ c_parser_expr_no_commas (c_parser *parse code, exp_location, rhs.value, rhs.original_type); if (code == NOP_EXPR) - ret.original_code = MODIFY_EXPR; + { + ret.original_code = MODIFY_EXPR; + /* Check for and warn about self-assignment if -Wself-assign is + enabled. */ + if (warn_self_assign) + check_for_self_assign (op_location, lhs.value, rhs.value); + } else { TREE_NO_WARNING (ret.value) = 1;