From patchwork Thu Jun 24 22:54:36 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: 56868 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 ACAD0B707E for ; Fri, 25 Jun 2010 08:55:00 +1000 (EST) Received: (qmail 17333 invoked by alias); 24 Jun 2010 22:54:59 -0000 Received: (qmail 17312 invoked by uid 22791); 24 Jun 2010 22:54:52 -0000 X-SWARE-Spam-Status: No, hits=-1.8 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; Thu, 24 Jun 2010 22:54:43 +0000 Received: from kpbe17.cbf.corp.google.com (kpbe17.cbf.corp.google.com [172.25.105.81]) by smtp-out.google.com with ESMTP id o5OMsclU014377 for ; Thu, 24 Jun 2010 15:54:39 -0700 Received: from gwj17 (gwj17.prod.google.com [10.200.10.17]) by kpbe17.cbf.corp.google.com with ESMTP id o5OMsbYn015123 for ; Thu, 24 Jun 2010 15:54:37 -0700 Received: by gwj17 with SMTP id 17so4055765gwj.15 for ; Thu, 24 Jun 2010 15:54:37 -0700 (PDT) MIME-Version: 1.0 Received: by 10.100.234.26 with SMTP id g26mr8914023anh.244.1277420077170; Thu, 24 Jun 2010 15:54:37 -0700 (PDT) Received: by 10.101.80.17 with HTTP; Thu, 24 Jun 2010 15:54:36 -0700 (PDT) In-Reply-To: References: Date: Thu, 24 Jun 2010 15:54:36 -0700 Message-ID: Subject: Re: [patch] [C/C++] Add a new warning flag -Wself-assign From: Le-Chun Wu To: "Joseph S. Myers" Cc: =?ISO-8859-1?Q?Manuel_L=F3pez=2DIb=E1=F1ez?= , Jason Merrill , rguenther@suse.de, Andrew Pinski , GCC Patches , Diego Novillo , sebastian.pop@inria.fr, jh@suse.cz 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 Attached please find the revised patch for the new flag -Wself-assign. Comparing with the previous patch, this one puts -Winit-self back but keeps it as a no-op, and resurrects the -Winit-self test cases to make sure the flag is still accepted by GCC. It also fixes the following self-assign/self-init warnings in GCC source code when bootstrapping. (The flag actually identified a real bug/typo in cgraphunit.c. Yeah! :-)) Relevant maintainers of these files are also cc'ed in this email. * dbxout.c (DEBUGGER_ARG_OFFSET): * omega.c (omega_eliminate_redundant) * tree-ssa-ccp.c (ccp_lattice_meet) * cgraphunit.c (cgraph_copy_node_for_versioning) * config/i386/i386.c (ix86_vectorize_builtin_vec_perm) Again, bootstrapped and tested on x86_64-linux-gnu. OK for trunk? Le-chun gcc/ChangeLog 2010-06-24 Le-Chun Wu * doc/invoke.texi (-Wall): Include -Wself-assign. (-Wself-assign): Documentation for the new flag. (-Winit-self): Remove. (-Wuninitialized): Remove mention of -Winit-self. (-Wunused-variable): Mention of new workaround. * 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. * 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. * 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. * dbxout.c (DEBUGGER_ARG_OFFSET): Change OFFSET to OFFSET+0 to avoid self-assign warning. * omega.c (omega_eliminate_redundant): Remove a self-assign statement. * tree-ssa-ccp.c (ccp_lattice_meet): Remove a self-assign statement and an unnecessary assignment. * cgraphunit.c (cgraph_copy_node_for_versioning): Fix a typo detected by -Wself-assign. * config/i386/i386.c (ix86_vectorize_builtin_vec_perm): Remove unnecessary self-init. gcc/c-family/ChangeLog 2010-06-24 Le-Chun Wu * gcc/c-family/c-gimplify.c (c_gimplify_expr): Remove support for -Winit-self. * gcc/c-family/c.opt: Make -Winit-self a no-op 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/cp/ChangeLog 2010-06-24 Le-Chun Wu * init.c (perform_member_init): Check for self-assign after parsing class member initialization. * 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/testsuite/ChangeLog * gcc.dg/plugin/selfassign.c (check_self_assign): Renamed from warn_self_assign. * gcc.dg/wself-assign-1.c: New test. * gcc.dg/wself-assign-2.c: New test. * gcc.dg/wself-assign-3.c: New test. * gcc.dg/uninit-D-O0.c: Add new warning. * gcc.dg/uninit-D.c: Add new warning. * gcc.dg/uninit-E-O0.c: Modify comment. * gcc.dg/uninit-E.c: Modify comment. * g++.dg/plugin/selfassign.c (check_self_assign): Renamed from warn_self_assign. * g++.dg/warn/Wself-assign-1.C: New test. * g++.dg/warn/Wself-assign-2.C: New test. * g++.dg/warn/Wself-assign-3.C: New test. * g++.dg/warn/Wself-assign-4.C: New test. * g++.dg/warn/Wself-assign-5.C: New test. 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) @@ -259,8 +259,8 @@ C C++ Var(warn_ignored_qualifiers) Init( 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 +C ObjC C++ ObjC++ +Does nothing. Preserved for backward compatibility. Wimplicit C ObjC Var(warn_implicit) Init(-1) Warning @@ -425,6 +425,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/omega.c =================================================================== --- gcc/omega.c (revision 161236) +++ gcc/omega.c (working copy) @@ -2213,7 +2213,9 @@ omega_eliminate_redundant (omega_pb pb, || pb->geqs[e3].color == omega_red) goto nextE3; - alpha3 = alpha3; + /* Dubious self-assignment. */ + /* alpha3 = alpha3; */ + /* verify alpha1*v1+alpha2*v2 = alpha3*v3 */ for (k = pb->num_vars; k >= 1; k--) if (alpha3 * pb->geqs[e3].coef[k] Index: gcc/cgraphunit.c =================================================================== --- gcc/cgraphunit.c (revision 161236) +++ gcc/cgraphunit.c (working copy) @@ -2128,7 +2128,7 @@ cgraph_copy_node_for_versioning (struct new_version->local.local = true; new_version->local.vtable_method = false; new_version->global = old_version->global; - new_version->rtl = new_version->rtl; + new_version->rtl = old_version->rtl; new_version->reachable = true; new_version->count = old_version->count; 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 +1,9 @@ -/* Test we do not warn about initializing variable with self. */ +/* Test we do warn about initializing variable with self. */ /* { dg-do compile } */ /* { dg-options "-Wuninitialized" } */ int f() { - int i = i; + int i = i; /* { dg-warning "i" "uninitialized variable warning" } */ 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 +1,9 @@ -/* Test we do not warn about initializing variable with self. */ +/* Test we do warn about initializing variable with self. */ /* { dg-do compile } */ /* { dg-options "-O -Wuninitialized" } */ int f() { - int i = i; + int i = i; /* { dg-warning "i" "uninitialized variable warning" } */ return i; } 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/uninit-E.c =================================================================== --- gcc/testsuite/gcc.dg/uninit-E.c (revision 161236) +++ gcc/testsuite/gcc.dg/uninit-E.c (working copy) @@ -1,4 +1,5 @@ -/* Test we do warn about initializing variable with self when -Winit-self is supplied. */ +/* Test we do warn about initializing variable with self and that -Winit-self + is preserved for backward compatibility. */ /* { dg-do compile } */ /* { dg-options "-O -Wuninitialized -Winit-self" } */ 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/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,4 +1,5 @@ -/* Test we do warn about initializing variable with self when -Winit-self is supplied. */ +/* Test we do warn about initializing variable with self and that -Winit-self + is preserved for backward compatibility. */ /* { dg-do compile } */ /* { dg-options "-Wuninitialized -Winit-self" } */ 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/tree-ssa-ccp.c =================================================================== --- gcc/tree-ssa-ccp.c (revision 161236) +++ gcc/tree-ssa-ccp.c (working copy) @@ -728,9 +728,8 @@ ccp_lattice_meet (prop_value_t *val1, pr Ci M Cj = VARYING if (i != j) If these two values come from memory stores, make sure that - they come from the same memory reference. */ - val1->lattice_val = CONSTANT; - val1->value = val1->value; + they come from the same memory reference. + Nothing to do. VAL1 already contains the value we want. */ } else { Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 161236) +++ gcc/dbxout.c (working copy) @@ -288,9 +288,12 @@ static const char *base_input_file; #endif /* A C expression for the integer offset value of an argument (N_PSYM) - having address X (an RTX). The nominal offset is OFFSET. */ + having address X (an RTX). The nominal offset is OFFSET. + Note that we use OFFSET + 0 here to avoid the self-assign warning + when the macro is called in a context like + number = DEBUGGER_ARG_OFFSET(number, X) */ #ifndef DEBUGGER_ARG_OFFSET -#define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET) +#define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET + 0) #endif /* This obstack holds the stab string currently being constructed. We 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; Index: gcc/config/i386/i386.c =================================================================== --- gcc/config/i386/i386.c (revision 161236) +++ gcc/config/i386/i386.c (working copy) @@ -29379,7 +29379,7 @@ ix86_vectorize_builtin_vec_perm (tree ve tree itype = TREE_TYPE (vec_type); bool u = TYPE_UNSIGNED (itype); enum machine_mode vmode = TYPE_MODE (vec_type); - enum ix86_builtins fcode = fcode; /* Silence bogus warning. */ + enum ix86_builtins fcode; bool ok = TARGET_SSE2; switch (vmode)