aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2017-11-28 22:22:52 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2017-11-28 22:22:52 +0100
commit058f0b9e5f073da9d1d98a91e482cbdead1561ee (patch)
tree54a203fbcbecced881bb3fc81e309166d8c9ad5b /gcc/c-family
parent67c24a8bd6141021da49e005c0111bd42bfc7d08 (diff)
downloadgcc-058f0b9e5f073da9d1d98a91e482cbdead1561ee.zip
gcc-058f0b9e5f073da9d1d98a91e482cbdead1561ee.tar.gz
gcc-058f0b9e5f073da9d1d98a91e482cbdead1561ee.tar.bz2
re PR sanitizer/81275 (-fsanitize=thread produce incorrect -Wreturn-type warning)
PR sanitizer/81275 * tree.c (block_may_fallthru): Return false if SWITCH_ALL_CASES_P is set on SWITCH_EXPR and !block_may_fallthru (SWITCH_BODY ()). c/ * c-typeck.c (c_finish_case): Set SWITCH_ALL_CASES_P if c_switch_covers_all_cases_p returns true. c-family/ * c-common.c (c_switch_covers_all_cases_p_1, c_switch_covers_all_cases_p): New functions. * c-common.h (c_switch_covers_all_cases_p): Declare. testsuite/ * c-c++-common/tsan/pr81275.c: New test. From-SVN: r255217
Diffstat (limited to 'gcc/c-family')
-rw-r--r--gcc/c-family/ChangeLog7
-rw-r--r--gcc/c-family/c-common.c58
-rw-r--r--gcc/c-family/c-common.h1
3 files changed, 66 insertions, 0 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index ce966bb..abbcb90 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,10 @@
+2017-11-28 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/81275
+ * c-common.c (c_switch_covers_all_cases_p_1,
+ c_switch_covers_all_cases_p): New functions.
+ * c-common.h (c_switch_covers_all_cases_p): Declare.
+
2017-11-28 Julia Koval <julia.koval@intel.com>
Sebastian Peryt <sebastian.peryt@intel.com>
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 82561657..1d79aee 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -4898,6 +4898,64 @@ c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type,
return error_mark_node;
}
+/* Subroutine of c_switch_covers_all_cases_p, called via
+ splay_tree_foreach. Return 1 if it doesn't cover all the cases.
+ ARGS[0] is initially NULL and after the first iteration is the
+ so far highest case label. ARGS[1] is the minimum of SWITCH_COND's
+ type. */
+
+static int
+c_switch_covers_all_cases_p_1 (splay_tree_node node, void *data)
+{
+ tree label = (tree) node->value;
+ tree *args = (tree *) data;
+
+ /* If there is a default case, we shouldn't have called this. */
+ gcc_assert (CASE_LOW (label));
+
+ if (args[0] == NULL_TREE)
+ {
+ if (wi::to_widest (args[1]) < wi::to_widest (CASE_LOW (label)))
+ return 1;
+ }
+ else if (wi::add (wi::to_widest (args[0]), 1)
+ != wi::to_widest (CASE_LOW (label)))
+ return 1;
+ if (CASE_HIGH (label))
+ args[0] = CASE_HIGH (label);
+ else
+ args[0] = CASE_LOW (label);
+ return 0;
+}
+
+/* Return true if switch with CASES and switch condition with type
+ covers all possible values in the case labels. */
+
+bool
+c_switch_covers_all_cases_p (splay_tree cases, tree type)
+{
+ /* If there is default:, this is always the case. */
+ splay_tree_node default_node
+ = splay_tree_lookup (cases, (splay_tree_key) NULL);
+ if (default_node)
+ return true;
+
+ if (!INTEGRAL_TYPE_P (type))
+ return false;
+
+ tree args[2] = { NULL_TREE, TYPE_MIN_VALUE (type) };
+ if (splay_tree_foreach (cases, c_switch_covers_all_cases_p_1, args))
+ return false;
+
+ /* If there are no cases at all, or if the highest case label
+ is smaller than TYPE_MAX_VALUE, return false. */
+ if (args[0] == NULL_TREE
+ || wi::to_widest (args[0]) < wi::to_widest (TYPE_MAX_VALUE (type)))
+ return false;
+
+ return true;
+}
+
/* Finish an expression taking the address of LABEL (an
IDENTIFIER_NODE). Returns an expression for the address.
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 5e55e5e..7561531 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -969,6 +969,7 @@ extern int case_compare (splay_tree_key, splay_tree_key);
extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree, tree,
bool *);
+extern bool c_switch_covers_all_cases_p (splay_tree, tree);
extern tree build_function_call (location_t, tree, tree);