diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 49d2b33fdb08..d9b81fede57c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2008-12-04 Richard Guenther + + PR middle-end/36509 + * Makefile.in (tree-ssa-alias-warnings.o): Remove. + (tree-ssa-structalias.o): Remove errors.h dependency. + (tree-ssa-reassoc.o): Likewise. + * tree-ssa-reassoc.c: Do not include errors.h. + * tree-ssa-alias-warnings.c: Remove. + * tree-ssa-alias.c (compute_may_aliases): Remove call to + strict_aliasing_warning_backend. + * tree-ssa-structalias.c (emit_pointer_definition): New function. + (emit_alias_warning): Likewise. + (set_uids_in_ptset): Warn for clear cases of type-punning. + * tree-inline.c (remap_gimple_op_r): Preserve TREE_NO_WARNING + on INDIRECT_REFs. + 2008-12-04 Eric Botcazou * cse.c (equiv_constant): Fix pasto. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b55c5c14e842..b50d1f4e3dc8 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1243,7 +1243,6 @@ OBJS-common = \ tree-switch-conversion.o \ tree-ssa-address.o \ tree-ssa-alias.o \ - tree-ssa-alias-warnings.o \ tree-ssa-ccp.o \ tree-ssa-coalesce.o \ tree-ssa-copy.o \ @@ -2089,7 +2088,7 @@ stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TOPLEV_H) tree-ssa-structalias.o: tree-ssa-structalias.c tree-ssa-structalias.h \ $(SYSTEM_H) $(CONFIG_H) coretypes.h $(TM_H) $(GGC_H) $(OBSTACK_H) $(BITMAP_H) \ - $(FLAGS_H) $(RTL_H) $(TM_P_H) hard-reg-set.h $(BASIC_BLOCK_H) output.h errors.h \ + $(FLAGS_H) $(RTL_H) $(TM_P_H) hard-reg-set.h $(BASIC_BLOCK_H) output.h \ $(DIAGNOSTIC_H) $(TREE_H) $(C_COMMON_H) $(TREE_FLOW_H) $(TREE_INLINE_H) varray.h \ $(C_TREE_H) $(GIMPLE_H) $(HASHTAB_H) $(FUNCTION_H) $(CGRAPH_H) tree-pass.h \ $(TIMEVAR_H) alloc-pool.h $(SPLAY_TREE_H) $(PARAMS_H) gt-tree-ssa-structalias.h \ @@ -2309,11 +2308,6 @@ tree-ssa-loop-im.o : tree-ssa-loop-im.c $(TREE_FLOW_H) $(CONFIG_H) \ tree-ssa-math-opts.o : tree-ssa-math-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(FLAGS_H) $(TREE_H) $(TREE_FLOW_H) $(REAL_H) $(TIMEVAR_H) tree-pass.h \ alloc-pool.h $(BASIC_BLOCK_H) $(TARGET_H) -tree-ssa-alias-warnings.o : tree-ssa-alias-warnings.c \ - $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(TREE_DUMP_H) \ - $(TREE_FLOW_H) $(PARAMS_H) $(FUNCTION_H) $(EXPR_H) $(TOPLEV_H) \ - tree-ssa-structalias.h tree-ssa-propagate.h langhooks.h alloc-pool.h \ - $(DIAGNOSTIC_H) tree-ssa-alias.o : tree-ssa-alias.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(TREE_INLINE_H) $(FLAGS_H) \ $(FUNCTION_H) $(TIMEVAR_H) convert.h $(TM_H) coretypes.h langhooks.h \ @@ -2321,7 +2315,7 @@ tree-ssa-alias.o : tree-ssa-alias.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ hard-reg-set.h $(GIMPLE_H) vec.h tree-ssa-structalias.h \ $(IPA_TYPE_ESCAPE_H) vecprim.h pointer-set.h alloc-pool.h tree-ssa-reassoc.o : tree-ssa-reassoc.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) errors.h $(TIMEVAR_H) \ + $(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \ $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) tree-iterator.h\ $(BASIC_BLOCK_H) $(GIMPLE_H) $(TREE_INLINE_H) vec.h langhooks.h \ alloc-pool.h pointer-set.h $(CFGLOOP_H) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0c6ecf813147..029d2adbb86e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2008-12-04 Richard Guenther + + PR c++/38334 + * typeck.c (get_member_function_from_ptrfunc): Mark the vtbl + pointer access with TREE_NO_WARNING. + 2008-12-03 Jason Merrill PR c++/38232 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 7595b58da72e..ed01c511f3c2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2790,6 +2790,10 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node), instance_ptr); vtbl = cp_build_indirect_ref (vtbl, NULL, tf_warning_or_error); + /* If the object is not dynamic the access invokes undefined + behavior. As it is not executed in this case silence the + spurious warnings it may provoke. */ + TREE_NO_WARNING (vtbl) = 1; /* Finally, extract the function pointer from the vtable. */ e2 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e54d5eabefe4..e58bdbb01b87 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2008-12-04 Richard Guenther + + PR middle-end/36509 + * gcc.dg/Wstrict-aliasing-float-ptr-int-obj.c: Adjust, remove XFAIL. + * gcc.dg/Wstrict-aliasing-converted-assigned.c: Adjust. + * g++.dg/warn/Wstrict-aliasing-float-ref-int-obj.C: Likewise. + 2008-12-04 Eric Botcazou * gcc.dg/union-4.c: New test. diff --git a/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-float-ref-int-obj.C b/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-float-ref-int-obj.C index 5527808b4a6a..d88ed4314b33 100644 --- a/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-float-ref-int-obj.C +++ b/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-float-ref-int-obj.C @@ -4,7 +4,9 @@ int foo() { int x; - float& q = reinterpret_cast (x); /* { dg-warning "type-punn" } */ - q = 1.0; + float& q = reinterpret_cast (x); /* { dg-message "initialized" } */ + q = 1.0; /* { dg-warning "does break strict-aliasing" } */ return x; } + +/* { dg-message "dereferencing type-punned" "" { target *-*-* } 7 } */ diff --git a/gcc/testsuite/gcc.dg/Wstrict-aliasing-converted-assigned.c b/gcc/testsuite/gcc.dg/Wstrict-aliasing-converted-assigned.c index 409120f2a40a..eb404a190135 100644 --- a/gcc/testsuite/gcc.dg/Wstrict-aliasing-converted-assigned.c +++ b/gcc/testsuite/gcc.dg/Wstrict-aliasing-converted-assigned.c @@ -8,3 +8,6 @@ int foo() *(long*)&i = 0; /* { dg-warning "type-punn" } */ return i; } + +/* { dg-message "does break strict-aliasing" "" { target *-*-* } 8 } */ +/* { dg-message "initialized" "" { target *-*-* } 8 } */ diff --git a/gcc/testsuite/gcc.dg/Wstrict-aliasing-float-ptr-int-obj.c b/gcc/testsuite/gcc.dg/Wstrict-aliasing-float-ptr-int-obj.c index 737191574110..fccc178d2242 100644 --- a/gcc/testsuite/gcc.dg/Wstrict-aliasing-float-ptr-int-obj.c +++ b/gcc/testsuite/gcc.dg/Wstrict-aliasing-float-ptr-int-obj.c @@ -11,12 +11,12 @@ int foo() { float* r; if (flag) { - q = (float*) &x; /* { dg-warning "type-punn" "" { xfail *-*-* } } */ + q = (float*) &x; /* { dg-message "initialized" } */ } else { - q = (float*) &y; /* { dg-warning "type-punn" "" { xfail *-*-* } } */ + q = (float*) &y; /* { dg-message "initialized" } */ } - *q = 1.0; + *q = 1.0; /* { dg-warning "does break strict-aliasing" } */ return x; diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 33ccafdb78c9..075e575d11b1 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -710,6 +710,7 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data) { *tp = build1 (INDIRECT_REF, type, new_tree); TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old); + TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old); } } *walk_subtrees = 0; diff --git a/gcc/tree-ssa-alias-warnings.c b/gcc/tree-ssa-alias-warnings.c deleted file mode 100644 index 5bae978187a6..000000000000 --- a/gcc/tree-ssa-alias-warnings.c +++ /dev/null @@ -1,1033 +0,0 @@ -/* Strict aliasing checks. - Copyright (C) 2007, 2008 Free Software Foundation, Inc. - Contributed by Silvius Rus . - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - GCC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GCC; see the file COPYING3. If not see -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "alloc-pool.h" -#include "tree.h" -#include "tree-dump.h" -#include "tree-flow.h" -#include "params.h" -#include "function.h" -#include "expr.h" -#include "toplev.h" -#include "diagnostic.h" -#include "tree-ssa-structalias.h" -#include "tree-ssa-propagate.h" -#include "langhooks.h" - -/* Module to issue a warning when a program uses data through a type - different from the type through which the data were defined. - Implements -Wstrict-aliasing and -Wstrict-aliasing=n. - These checks only happen when -fstrict-aliasing is present. - - The idea is to use the compiler to identify occurrences of nonstandard - aliasing, and report them to programmers. Programs free of such aliasing - are more portable, maintainable, and can usually be optimized better. - - The current, as of April 2007, C and C++ language standards forbid - accessing data of type A through an lvalue of another type B, - with certain exceptions. See the C Standard ISO/IEC 9899:1999, - section 6.5, paragraph 7, and the C++ Standard ISO/IEC 14882:1998, - section 3.10, paragraph 15. - - Example 1:*a is used as int but was defined as a float, *b. - int* a = ...; - float* b = reinterpret_cast (a); - *b = 2.0; - return *a - - Unfortunately, the problem is in general undecidable if we take into - account arithmetic expressions such as array indices or pointer arithmetic. - (It is at least as hard as Peano arithmetic decidability.) - Even ignoring arithmetic, the problem is still NP-hard, because it is - at least as hard as flow-insensitive may-alias analysis, which was proved - NP-hard by Horwitz et al, TOPLAS 1997. - - It is clear that we need to choose some heuristics. - Unfortunately, various users have different goals which correspond to - different time budgets so a common approach will not suit all. - We present the user with three effort/accuracy levels. By accuracy, we mean - a common-sense mix of low count of false positives with a - reasonably low number of false negatives. We are heavily biased - towards a low count of false positives. - The effort (compilation time) is likely to increase with the level. - - -Wstrict-aliasing=1 - =================== - Most aggressive, least accurate. Possibly useful when higher levels - do not warn but -fstrict-aliasing still breaks the code, as - it has very few false negatives. - Warn for all bad pointer conversions, even if never dereferenced. - Implemented in the front end (c-common.c). - Uses alias_sets_might_conflict to compare types. - - -Wstrict-aliasing=2 - =================== - Aggressive, not too precise. - May still have many false positives (not as many as level 1 though), - and few false negatives (but possibly more than level 1). - Runs only in the front end. Uses alias_sets_might_conflict to - compare types. Does not check for pointer dereferences. - Only warns when an address is taken. Warns about incomplete type punning. - - -Wstrict-aliasing=3 (default) - =================== - Should have very few false positives and few false negatives. - Takes care of the common pun+dereference pattern in the front end: - *(int*)&some_float. - Takes care of multiple statement cases in the back end, - using flow-sensitive points-to information (-O required). - Uses alias_sets_conflict_p to compare types and only warns - when the converted pointer is dereferenced. - Does not warn about incomplete type punning. - - Future improvements can be included by adding higher levels. - - In summary, expression level analysis is performed in the front-end, - and multiple-statement analysis is performed in the backend. - The remainder of this discussion is only about the backend analysis. - - This implementation uses flow-sensitive points-to information. - Flow-sensitivity refers to accesses to the pointer, and not the object - pointed. For instance, we do not warn about the following case. - - Example 2. - int* a = (int*)malloc (...); - float* b = reinterpret_cast (a); - *b = 2.0; - a = (int*)malloc (...); - return *a; - - In SSA, it becomes clear that the INT value *A_2 referenced in the - return statement is not aliased to the FLOAT defined through *B_1. - int* a_1 = (int*)malloc (...); - float* b_1 = reinterpret_cast (a_1); - *b_1 = 2.0; - a_2 = (int*)malloc (...); - return *a_2; - - - Algorithm Outline - ================= - - ForEach (ptr, object) in the points-to table - If (incompatible_types (*ptr, object)) - If (referenced (ptr, current function) - and referenced (object, current function)) - Issue warning (ptr, object, reference locations) - - The complexity is: - O (sizeof (points-to table) - + sizeof (function body) * lookup_time (points-to table)) - - Pointer dereference locations are looked up on demand. The search is - a single scan of the function body, in which all references to pointers - and objects in the points-to table are recorded. However, this dominant - time factor occurs rarely, only when cross-type aliasing was detected. - - - Limitations of the Proposed Implementation - ========================================== - - 1. We do not catch the following case, because -fstrict-aliasing will - associate different tags with MEM while building points-to information, - thus before we get to analyze it. - XXX: this could be solved by either running with -fno-strict-aliasing - or by recording the points-to information before splitting the original - tag based on type. - - Example 3. - void* mem = malloc (...); - int* pi = reinterpret_cast (mem); - float* b = reinterpret_cast (mem); - *b = 2.0; - return *pi+1; - - 2. We do not check whether the two conflicting (de)references can - reach each other in the control flow sense. If we fixed limitation - 1, we would wrongly issue a warning in the following case. - - Example 4. - void* raw = malloc (...); - if (...) { - float* b = reinterpret_cast (raw); - *b = 2.0; - return (int)*b; - } else { - int* a = reinterpret_cast (raw); - *a = 1; - return *a; - - 3. Only simple types are compared, thus no structures, unions or classes - are analyzed. A first attempt to deal with structures introduced much - complication and has not showed much improvement in preliminary tests, - so it was left out. - - 4. All analysis is intraprocedural. */ - - -/* Local declarations. */ -static void find_references_in_function (void); - - - -/* Get main type of tree TYPE, stripping array dimensions and qualifiers. */ - -static tree -get_main_type (tree type) -{ - while (TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - return TYPE_MAIN_VARIANT (type); -} - - -/* Get the type of the given object. If IS_PTR is true, get the type of the - object pointed to or referenced by OBJECT instead. - For arrays, return the element type. Ignore all qualifiers. */ - -static tree -get_otype (tree object, bool is_ptr) -{ - tree otype = TREE_TYPE (object); - - if (is_ptr) - { - gcc_assert (POINTER_TYPE_P (otype)); - otype = TREE_TYPE (otype); - } - return get_main_type (otype); -} - - -/* Return true if tree TYPE is struct, class or union. */ - -static bool -struct_class_union_p (tree type) -{ - return (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE); -} - - - -/* Keep data during a search for an aliasing site. - RHS = object or pointer aliased. No LHS is specified because we are only - looking in the UseDef paths of a given variable, so LHS will always be - an SSA name of the same variable. - When IS_RHS_POINTER = true, we are looking for ... = RHS. Otherwise, - we are looking for ... = &RHS. - SITE is the output of a search, non-NULL if the search succeeded. */ - -struct alias_match -{ - tree rhs; - bool is_rhs_pointer; - gimple site; -}; - - -/* Callback for find_alias_site. Return true if the right hand site - of STMT matches DATA. */ - -static bool -find_alias_site_helper (tree var ATTRIBUTE_UNUSED, gimple stmt, void *data) -{ - struct alias_match *match = (struct alias_match *) data; - tree rhs_pointer = NULL_TREE; - tree to_match = NULL_TREE; - - if (gimple_assign_cast_p (stmt)) - rhs_pointer = gimple_assign_rhs1 (stmt); - - if (!rhs_pointer) - /* Not a type conversion. */ - return false; - - if (TREE_CODE (rhs_pointer) == ADDR_EXPR && !match->is_rhs_pointer) - to_match = TREE_OPERAND (rhs_pointer, 0); - else if (POINTER_TYPE_P (rhs_pointer) && match->is_rhs_pointer) - to_match = rhs_pointer; - - if (to_match != match->rhs) - /* Type conversion, but not a name match. */ - return false; - - /* Found it. */ - match->site = stmt; - return true; -} - - -/* Find the statement where OBJECT1 gets aliased to OBJECT2. - If IS_PTR2 is true, consider OBJECT2 to be the name of a pointer or - reference rather than the actual aliased object. - For now, just implement the case where OBJECT1 is an SSA name defined - by a PHI statement. */ - -static gimple -find_alias_site (tree object1, bool is_ptr1 ATTRIBUTE_UNUSED, - tree object2, bool is_ptr2) -{ - struct alias_match match; - - match.rhs = object2; - match.is_rhs_pointer = is_ptr2; - match.site = NULL; - - if (TREE_CODE (object1) != SSA_NAME) - return NULL; - - walk_use_def_chains (object1, find_alias_site_helper, &match, false); - return match.site; -} - - -/* Structure to store temporary results when trying to figure out whether - an object is referenced. Just its presence in the text is not enough, - as we may just be taking its address. */ - -struct match_info -{ - tree object; - bool is_ptr; - /* The difference between the number of references to OBJECT - and the number of occurrences of &OBJECT. */ - int found; -}; - - -/* Return the base if EXPR is an SSA name. Return EXPR otherwise. */ - -static tree -get_ssa_base (tree expr) -{ - if (TREE_CODE (expr) == SSA_NAME) - return SSA_NAME_VAR (expr); - else - return expr; -} - - -/* Record references to objects and pointer dereferences across some piece of - code. The number of references is recorded for each item. - References to an object just to take its address are not counted. - For instance, if PTR is a pointer and OBJ is an object: - 1. Expression &obj + *ptr will have the following reference match structure: - ptrs: - objs: - OBJ does not appear as referenced because we just take its address. - 2. Expression ptr + *ptr will have the following reference match structure: - ptrs: - objs: - PTR shows up twice as an object, but is dereferenced only once. - - The elements of the hash tables are gimple_map objects. */ -struct reference_matches -{ - htab_t ptrs; - htab_t objs; -}; - -struct gimple_tree_map -{ - tree from; - gimple to; -}; - -/* Return true if the from tree in both gimple-tree maps are equal. - VA and VB are really instances of struct gimple_tree_map. */ - -static int -gimple_tree_map_eq (const void *va, const void *vb) -{ - const struct gimple_tree_map *const a = (const struct gimple_tree_map *) va; - const struct gimple_tree_map *const b = (const struct gimple_tree_map *) vb; - return (a->from == b->from); -} - -/* Hash a from tree in a gimple_tree_map. ITEM is really an instance - of struct gimple_tree_map. */ - -static unsigned int -gimple_tree_map_hash (const void *item) -{ - return htab_hash_pointer (((const struct gimple_tree_map *)item)->from); -} - -/* Return the match, if any. Otherwise, return NULL. It will return - NULL even when a match was found, if the value associated to KEY is - NULL. */ - -static inline gimple -match (htab_t ref_map, tree key) -{ - struct gimple_tree_map *found; - void **slot = NULL; - slot = htab_find_slot (ref_map, &key, NO_INSERT); - - if (!slot) - return NULL; - - found = (struct gimple_tree_map *) *slot; - - return found->to; -} - - -/* Set the entry corresponding to KEY, but only if the entry - already exists and its value is NULL_TREE. Otherwise, do nothing. */ - -static inline void -maybe_add_match (htab_t ref_map, struct gimple_tree_map *key) -{ - struct gimple_tree_map *found; - - found = (struct gimple_tree_map *) htab_find (ref_map, key); - - if (found && !found->to) - found->to = key->to; -} - - -/* Add an entry to HT, with key T and value NULL_TREE. */ - -static void -add_key (htab_t ht, tree t, alloc_pool references_pool) -{ - void **slot; - struct gimple_tree_map *tp; - - tp = (struct gimple_tree_map *) pool_alloc (references_pool); - - tp->from = t; - tp->to = NULL; - slot = htab_find_slot (ht, &t, INSERT); - *slot = (void *) tp; -} - - -/* Some memory to keep the objects in the reference table. */ - -static alloc_pool ref_table_alloc_pool = NULL; - - -/* Get some memory to keep the objects in the reference table. */ - -static inline alloc_pool -reference_table_alloc_pool (bool build) -{ - if (ref_table_alloc_pool || !build) - return ref_table_alloc_pool; - - ref_table_alloc_pool = create_alloc_pool ("ref_table_alloc_pool", - sizeof (struct gimple_tree_map), - 20); - - return ref_table_alloc_pool; -} - - -/* Initialize the reference table by adding all pointers in the points-to - table as keys, and NULL_TREE as associated values. */ - -static struct reference_matches * -build_reference_table (void) -{ - unsigned int i; - struct reference_matches *ref_table = NULL; - alloc_pool references_pool = reference_table_alloc_pool (true); - - ref_table = XNEW (struct reference_matches); - ref_table->objs = htab_create (10, gimple_tree_map_hash, gimple_tree_map_eq, - NULL); - ref_table->ptrs = htab_create (10, gimple_tree_map_hash, gimple_tree_map_eq, - NULL); - - for (i = 1; i < num_ssa_names; i++) - { - tree ptr = ssa_name (i); - struct ptr_info_def *pi; - - if (ptr == NULL_TREE) - continue; - - pi = SSA_NAME_PTR_INFO (ptr); - - if (!SSA_NAME_IN_FREE_LIST (ptr) && pi && pi->name_mem_tag) - { - /* Add pointer to the interesting dereference list. */ - add_key (ref_table->ptrs, ptr, references_pool); - - /* Add all aliased names to the interesting reference list. */ - if (pi->pt_vars) - { - unsigned ix; - bitmap_iterator bi; - - EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi) - { - tree alias = referenced_var (ix); - add_key (ref_table->objs, alias, references_pool); - } - } - } - } - - return ref_table; -} - - -/* Reference table. */ - -static struct reference_matches *ref_table = NULL; - - -/* Clean up the reference table if allocated. */ - -static void -maybe_free_reference_table (void) -{ - if (ref_table) - { - htab_delete (ref_table->ptrs); - htab_delete (ref_table->objs); - free (ref_table); - ref_table = NULL; - } - - if (ref_table_alloc_pool) - { - free_alloc_pool (ref_table_alloc_pool); - ref_table_alloc_pool = NULL; - } -} - - -/* Get the reference table. Initialize it if needed. */ - -static inline struct reference_matches * -reference_table (bool build) -{ - if (ref_table || !build) - return ref_table; - - ref_table = build_reference_table (); - find_references_in_function (); - return ref_table; -} - - -/* Callback for find_references_in_function. - Check whether *TP is an object reference or pointer dereference for the - variables given in ((struct match_info*)DATA)->OBJS or - ((struct match_info*)DATA)->PTRS. The total number of references - is stored in the same structures. */ - -static tree -find_references_in_tree_helper (tree *tp, - int *walk_subtrees ATTRIBUTE_UNUSED, - void *data) -{ - struct gimple_tree_map match; - static int parent_tree_code = ERROR_MARK; - struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - - /* Do not report references just for the purpose of taking an address. - XXX: we rely on the fact that the tree walk is in preorder - and that ADDR_EXPR is not a leaf, thus cannot be carried over across - walks. */ - if (parent_tree_code == ADDR_EXPR) - goto finish; - - match.to = (gimple) wi->info; - - if (TREE_CODE (*tp) == INDIRECT_REF) - { - match.from = TREE_OPERAND (*tp, 0); - maybe_add_match (reference_table (true)->ptrs, &match); - } - else - { - match.from = *tp; - maybe_add_match (reference_table (true)->objs, &match); - } - -finish: - parent_tree_code = TREE_CODE (*tp); - return NULL_TREE; -} - - -/* Find all the references to aliased variables in the current function. */ - -static void -find_references_in_function (void) -{ - basic_block bb; - gimple_stmt_iterator i; - - FOR_EACH_BB (bb) - for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) - { - struct walk_stmt_info wi; - memset (&wi, 0, sizeof (wi)); - wi.info = (void *) gsi_stmt (i); - walk_gimple_op (gsi_stmt (i), find_references_in_tree_helper, &wi); - } -} - - -/* Find the reference site for OBJECT. - If IS_PTR is true, look for dereferences of OBJECT instead. - XXX: only the first site is returned in the current - implementation. If there are no matching sites, return NULL_TREE. */ - -static gimple -reference_site (tree object, bool is_ptr) -{ - if (is_ptr) - return match (reference_table (true)->ptrs, object); - else - return match (reference_table (true)->objs, object); -} - - -/* Try to get more location info when something is missing. - OBJECT1 and OBJECT2 are aliased names. If IS_PTR1 or IS_PTR2, the alias - is on the memory referenced or pointed to by OBJECT1 and OBJECT2. - ALIAS_SITE, DEREF_SITE1 and DEREF_SITE2 are the statements where the - alias takes place (some pointer assignment usually) and where the - alias is referenced through OBJECT1 and OBJECT2 respectively. - REF_TYPE1 and REF_TYPE2 will return the type of the reference at the - respective sites. Only the first matching reference is returned for - each name. If no statement is found, the function header is returned. */ - -static void -maybe_find_missing_stmts (tree object1, bool is_ptr1, - tree object2, bool is_ptr2, - gimple *alias_site, - gimple *deref_site1, - gimple *deref_site2) -{ - if (object1 && object2) - { - if (!*alias_site || !gimple_has_location (*alias_site)) - *alias_site = find_alias_site (object1, is_ptr1, object2, is_ptr2); - - if (!*deref_site1 || !gimple_has_location (*deref_site1)) - *deref_site1 = reference_site (object1, is_ptr1); - - if (!*deref_site2 || !gimple_has_location (*deref_site2)) - *deref_site2 = reference_site (object2, is_ptr2); - } - - /* If we could not find the alias site, set it to one of the dereference - sites, if available. */ - if (!*alias_site) - { - if (*deref_site1) - *alias_site = *deref_site1; - else if (*deref_site2) - *alias_site = *deref_site2; - } - - /* If we could not find the dereference sites, set them to the alias site, - if known. */ - if (!*deref_site1 && *alias_site) - *deref_site1 = *alias_site; - if (!*deref_site2 && *alias_site) - *deref_site2 = *alias_site; -} - - -/* Callback for find_first_artificial_name. - Find out if there are no artificial names at tree node *T. */ - -static tree -ffan_walker (tree *t, - int *go_below ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - if (DECL_P (*t) && !MTAG_P (*t) && DECL_ARTIFICIAL (*t)) - return *t; - else - return NULL_TREE; -} - -/* Return the first artificial name within EXPR, or NULL_TREE if - none exists. */ - -static tree -find_first_artificial_name (tree expr) -{ - return walk_tree_without_duplicates (&expr, ffan_walker, NULL); -} - - -/* Get a name from the original program for VAR. */ - -static const char * -get_var_name (tree var) -{ - if (TREE_CODE (var) == SSA_NAME) - return get_var_name (get_ssa_base (var)); - - if (find_first_artificial_name (var)) - return "{unknown}"; - - if (TREE_CODE (var) == VAR_DECL || TREE_CODE (var) == PARM_DECL) - if (DECL_NAME (var)) - return IDENTIFIER_POINTER (DECL_NAME (var)); - - return "{unknown}"; -} - - -/* Return "*" if OBJECT is not the actual alias but a pointer to it, or - "" otherwise. - IS_PTR is true when OBJECT is not the actual alias. - In addition to checking IS_PTR, we also make sure that OBJECT is a pointer - since IS_PTR would also be true for C++ references, but we should only - print a * before a pointer and not before a reference. */ - -static const char * -get_maybe_star_prefix (tree object, bool is_ptr) -{ - gcc_assert (object); - return (is_ptr - && TREE_CODE (TREE_TYPE (object)) == POINTER_TYPE) ? "*" : ""; -} - -/* Callback for contains_node_type_p. - Returns true if *T has tree code *(int*)DATA. */ - -static tree -contains_node_type_p_callback (tree *t, - int *go_below ATTRIBUTE_UNUSED, - void *data) -{ - return ((int) TREE_CODE (*t) == *((int *) data)) ? *t : NULL_TREE; -} - - -/* Return true if T contains a node with tree code TYPE. */ - -static bool -contains_node_type_p (tree t, int type) -{ - return (walk_tree_without_duplicates (&t, contains_node_type_p_callback, - (void *) &type) - != NULL_TREE); -} - - -/* Return true if a warning was issued in the front end at STMT. */ - -static bool -already_warned_in_frontend_p (gimple stmt) -{ - if (stmt == NULL) - return false; - - if (gimple_assign_cast_p (stmt) - && TREE_NO_WARNING (gimple_assign_rhs1 (stmt))) - return true; - else - return false; -} - - -/* Return true if and only if TYPE is a function or method pointer type, - or pointer to a pointer to ... to a function or method. */ - -static bool -is_method_pointer (tree type) -{ - while (TREE_CODE (type) == POINTER_TYPE) - type = TREE_TYPE (type); - return TREE_CODE (type) == METHOD_TYPE || TREE_CODE (type) == FUNCTION_TYPE; -} - - -/* Issue a -Wstrict-aliasing warning. - OBJECT1 and OBJECT2 are aliased names. - If IS_PTR1 and/or IS_PTR2 is true, then the corresponding name - OBJECT1/OBJECT2 is a pointer or reference to the aliased memory, - rather than actual storage. - ALIAS_SITE is a statement where the alias took place. In the most common - case, that is where a pointer was assigned to the address of an object. */ - -static bool -strict_aliasing_warn (gimple alias_site, - tree object1, bool is_ptr1, - tree object2, bool is_ptr2, - bool filter_artificials) -{ - gimple ref_site1 = NULL; - gimple ref_site2 = NULL; - const char *name1; - const char *name2; - location_t alias_loc; - location_t ref1_loc; - location_t ref2_loc; - gcc_assert (object1); - gcc_assert (object2); - name1 = get_var_name (object1); - name2 = get_var_name (object2); - - - if (is_method_pointer (get_main_type (TREE_TYPE (object2)))) - return false; - - maybe_find_missing_stmts (object1, is_ptr1, object2, is_ptr2, &alias_site, - &ref_site1, &ref_site2); - - if (gimple_has_location (alias_site)) - alias_loc = gimple_location (alias_site); - else - return false; - - if (gimple_has_location (ref_site1)) - ref1_loc = gimple_location (ref_site1); - else - ref1_loc = alias_loc; - - if (gimple_has_location (ref_site2)) - ref2_loc = gimple_location (ref_site2); - else - ref2_loc = alias_loc; - - if (already_warned_in_frontend_p (alias_site)) - return false; - - /* If they are not SSA names, but contain SSA names, drop the warning - because it cannot be displayed well. - Also drop it if they both contain artificials. - XXX: this is a hack, must figure out a better way to display them. */ - if (filter_artificials) - if ((find_first_artificial_name (get_ssa_base (object1)) - && find_first_artificial_name (get_ssa_base (object2))) - || (TREE_CODE (object1) != SSA_NAME - && contains_node_type_p (object1, SSA_NAME)) - || (TREE_CODE (object2) != SSA_NAME - && contains_node_type_p (object2, SSA_NAME))) - return false; - - - /* XXX: In the following format string, %s:%d should be replaced by %H. - However, in my tests only the first %H printed ok, while the - second and third were printed as blanks. */ - warning (OPT_Wstrict_aliasing, - "%Hlikely type-punning may break strict-aliasing rules: " - "object %<%s%s%> of main type %qT is referenced at or around " - "%s:%d and may be " - "aliased to object %<%s%s%> of main type %qT which is referenced " - "at or around %s:%d.", - &alias_loc, - get_maybe_star_prefix (object1, is_ptr1), - name1, get_otype (object1, is_ptr1), - LOCATION_FILE (ref1_loc), LOCATION_LINE (ref1_loc), - get_maybe_star_prefix (object2, is_ptr2), - name2, get_otype (object2, is_ptr2), - LOCATION_FILE (ref2_loc), LOCATION_LINE (ref2_loc)); - - return true; -} - - - -/* Return true when any objects of TYPE1 and TYPE2 respectively - may not be aliased according to the language standard. */ - -static bool -nonstandard_alias_types_p (tree type1, tree type2) -{ - alias_set_type set1; - alias_set_type set2; - - if (VOID_TYPE_P (type1) || VOID_TYPE_P (type2)) - return false; - - set1 = get_alias_set (type1); - set2 = get_alias_set (type2); - return !alias_sets_conflict_p (set1, set2); -} - - - -/* Returns true when *PTR may not be aliased to ALIAS. - See C standard 6.5p7 and C++ standard 3.10p15. - If PTR_PTR is true, ALIAS represents a pointer or reference to the - aliased storage rather than its actual name. */ - -static bool -nonstandard_alias_p (tree ptr, tree alias, bool ptr_ptr) -{ - /* Find the types to compare. */ - tree ptr_type = get_otype (ptr, true); - tree alias_type = get_otype (alias, ptr_ptr); - - /* If this is a ref-all pointer the access is ok. */ - if (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (ptr))) - return false; - - /* XXX: for now, say it's OK if the alias escapes. - Not sure this is needed in general, but otherwise GCC will not - bootstrap. */ - if (var_ann (get_ssa_base (alias))->escape_mask != NO_ESCAPE) - return false; - - /* XXX: don't get into structures for now. It brings much complication - and little benefit. */ - if (struct_class_union_p (ptr_type) || struct_class_union_p (alias_type)) - return false; - - /* If they are both SSA names of artificials, let it go, the warning - is too confusing. */ - if (find_first_artificial_name (ptr) && find_first_artificial_name (alias)) - return false; - - /* Compare the types. */ - return nonstandard_alias_types_p (ptr_type, alias_type); -} - - -/* Return true when we should skip analysis for pointer PTR based on the - fact that their alias information *PI is not considered relevant. */ - -static bool -skip_this_pointer (tree ptr ATTRIBUTE_UNUSED, struct ptr_info_def *pi) -{ - /* If it is not dereferenced, it is not a problem (locally). */ - if (!pi->is_dereferenced) - return true; - - /* This would probably cause too many false positives. */ - if (pi->value_escapes_p || pi->pt_anything) - return true; - - return false; -} - - -/* Find aliasing to named objects for pointer PTR. */ - -static void -dsa_named_for (tree ptr ATTRIBUTE_UNUSED) -{ - struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr); - - if (pi) - { - if (skip_this_pointer (ptr, pi)) - return; - - /* For all the variables it could be aliased to. */ - if (pi->pt_vars) - { - unsigned ix; - bitmap_iterator bi; - bool any = false; - - EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi) - { - tree alias = referenced_var (ix); - - if (nonstandard_alias_p (ptr, alias, false)) - strict_aliasing_warn (SSA_NAME_DEF_STMT (ptr), - ptr, true, alias, false, true); - else - any = true; - } - - /* If there was no object in the points-to set that the pointer - may alias, unconditionally warn. */ - if (!any) - warning (OPT_Wstrict_aliasing, - "dereferencing type-punned pointer %D will " - "break strict-aliasing rules", SSA_NAME_VAR (ptr)); - } - } -} - - -/* Detect and report strict aliasing violation of named objects. */ - -static void -detect_strict_aliasing_named (void) -{ - unsigned int i; - - for (i = 1; i < num_ssa_names; i++) - { - tree ptr = ssa_name (i); - struct ptr_info_def *pi; - - if (ptr == NULL_TREE) - continue; - - pi = SSA_NAME_PTR_INFO (ptr); - - if (!SSA_NAME_IN_FREE_LIST (ptr) && pi && pi->name_mem_tag) - dsa_named_for (ptr); - } -} - - -/* Return false only the first time I see each instance of FUNC. */ - -static bool -processed_func_p (tree func) -{ - static htab_t seen = NULL; - void **slot = NULL; - - if (!seen) - seen = htab_create (10, gimple_tree_map_hash, gimple_tree_map_eq, NULL); - - slot = htab_find_slot (seen, &func, INSERT); - gcc_assert (slot); - - if (*slot) - return true; - - gcc_assert (slot); - *slot = &func; - return false; -} - - -/* Detect and warn about type-punning using points-to information. */ - -void -strict_aliasing_warning_backend (void) -{ - if (flag_strict_aliasing && warn_strict_aliasing == 3 - && !processed_func_p (current_function_decl)) - { - detect_strict_aliasing_named (); - maybe_free_reference_table (); - } -} diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 6155809631db..4e9d28bf9eba 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -1825,9 +1825,6 @@ compute_may_aliases (void) dump_referenced_vars (dump_file); } - /* Report strict aliasing violations. */ - strict_aliasing_warning_backend (); - /* Deallocate memory used by aliasing data structures. */ delete_alias_info (ai); diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index aa01258da703..c71680aae248 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tm.h" -#include "errors.h" #include "ggc.h" #include "tree.h" #include "basic-block.h" diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 3be76acf1b81..46781b82129d 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -31,14 +31,14 @@ #include "hard-reg-set.h" #include "basic-block.h" #include "output.h" -#include "errors.h" -#include "diagnostic.h" #include "tree.h" #include "c-common.h" #include "tree-flow.h" #include "tree-inline.h" #include "varray.h" #include "c-tree.h" +#include "diagnostic.h" +#include "toplev.h" #include "gimple.h" #include "hashtab.h" #include "function.h" @@ -4648,14 +4648,15 @@ shared_bitmap_add (bitmap pt_vars) IS_DEREFED is true if PTR was directly dereferenced, which we use to help determine whether we are we are allowed to prune using TBAA. If NO_TBAA_PRUNING is true, we do not perform any TBAA pruning of - the from set. */ + the from set. Returns the number of pruned variables. */ -static void +static unsigned set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed, bool no_tbaa_pruning) { unsigned int i; bitmap_iterator bi; + unsigned pruned = 0; gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr))); @@ -4688,14 +4689,97 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed, if (may_alias_p (SSA_NAME_VAR (ptr), mem_alias_set, vi->decl, var_alias_set, true)) bitmap_set_bit (into, DECL_UID (vi->decl)); + else + ++pruned; } } } + + return pruned; } static bool have_alias_info = false; +/* Emit a note for the pointer initialization point DEF. */ + +static void +emit_pointer_definition (gimple def) +{ + if (gimple_code (def) == GIMPLE_PHI) + { + use_operand_p argp; + ssa_op_iter oi; + + FOR_EACH_PHI_ARG (argp, def, oi, SSA_OP_USE) + { + tree arg = USE_FROM_PTR (argp); + if (TREE_CODE (arg) == SSA_NAME) + emit_pointer_definition (SSA_NAME_DEF_STMT (arg)); + else + inform (0, "initialized from %qE", arg); + } + } + else if (!gimple_nop_p (def)) + inform (gimple_location (def), "initialized from here"); +} + +/* Emit a strict aliasing warning for dereferencing the pointer PTR. */ + +static void +emit_alias_warning (tree ptr) +{ + gimple def = SSA_NAME_DEF_STMT (ptr); + gimple use; + imm_use_iterator ui; + unsigned warned = 0; + + FOR_EACH_IMM_USE_STMT (use, ui, ptr) + { + tree deref = NULL_TREE; + + if (gimple_has_lhs (use)) + { + tree lhs = get_base_address (gimple_get_lhs (use)); + if (lhs + && INDIRECT_REF_P (lhs) + && TREE_OPERAND (lhs, 0) == ptr) + deref = lhs; + } + if (gimple_assign_single_p (use)) + { + tree rhs = get_base_address (gimple_assign_rhs1 (use)); + if (rhs + && INDIRECT_REF_P (rhs) + && TREE_OPERAND (rhs, 0) == ptr) + deref = rhs; + } + else if (is_gimple_call (use)) + { + unsigned i; + for (i = 0; i < gimple_call_num_args (use); ++i) + { + tree op = get_base_address (gimple_call_arg (use, i)); + if (op + && INDIRECT_REF_P (op) + && TREE_OPERAND (op, 0) == ptr) + deref = op; + } + } + if (deref + && !TREE_NO_WARNING (deref)) + { + TREE_NO_WARNING (deref) = 1; + warning_at (gimple_location (use), OPT_Wstrict_aliasing, + "dereferencing pointer %qD does break strict-aliasing " + "rules", SSA_NAME_VAR (ptr)); + ++warned; + } + } + if (warned > 0) + emit_pointer_definition (def); +} + /* Given a pointer variable P, fill in its points-to set, or return false if we can't. Rather than return false for variables that point-to anything, we @@ -4740,7 +4824,7 @@ find_what_p_points_to (tree p) else { struct ptr_info_def *pi = get_ptr_info (p); - unsigned int i; + unsigned int i, pruned; bitmap_iterator bi; bool was_pt_anything = false; bitmap finished_solution; @@ -4792,9 +4876,9 @@ find_what_p_points_to (tree p) finished_solution = BITMAP_GGC_ALLOC (); stats.points_to_sets_created++; - set_uids_in_ptset (p, finished_solution, vi->solution, - pi->is_dereferenced, - vi->no_tbaa_pruning); + pruned = set_uids_in_ptset (p, finished_solution, vi->solution, + pi->is_dereferenced, + vi->no_tbaa_pruning); result = shared_bitmap_lookup (finished_solution); if (!result) @@ -4809,7 +4893,22 @@ find_what_p_points_to (tree p) } if (bitmap_empty_p (pi->pt_vars)) - pi->pt_vars = NULL; + { + pi->pt_vars = NULL; + if (pruned > 0 + && pi->is_dereferenced + && warn_strict_aliasing > 0 + && !SSA_NAME_IS_DEFAULT_DEF (p)) + { + if (dump_file && dump_flags & TDF_DETAILS) + { + fprintf (dump_file, "alias warning for "); + print_generic_expr (dump_file, p, 0); + fprintf (dump_file, "\n"); + } + emit_alias_warning (p); + } + } return true; }