+++ /dev/null
-/* Strict aliasing checks.
- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
- Contributed by Silvius Rus <rus@google.com>.
-
- 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
-<http://www.gnu.org/licenses/>. */
-
-#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<float*> (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<float*> (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<float*> (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<int*> (mem);
- float* b = reinterpret_cast<float*> (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<float*> (raw);
- *b = 2.0;
- return (int)*b;
- } else {
- int* a = reinterpret_cast<int*> (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);
-\f
-
-
-/* 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);
-}
-\f
-
-
-/* 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: <ptr, 1>
- objs: <ptr, 1>
- OBJ does not appear as referenced because we just take its address.
- 2. Expression ptr + *ptr will have the following reference match structure:
- ptrs: <ptr, 1>
- objs: <ptr, 2>
- 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;
-}
-\f
-
-
-/* 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);
-}
-\f
-
-
-/* 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 ();
- }
-}