aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-08-04 01:32:22 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-08-04 15:49:49 +0200
commitbe35da05f38df984d518bc4670b36aa0b7ad4185 (patch)
tree084b3d919d888f394b51524e24c5454d48cb59ec
parent69e12d779f77120ed7be3b7c67c501e4aa953bd3 (diff)
downloadsparse-dev-be35da05f38df984d518bc4670b36aa0b7ad4185.tar.gz
fix: give a type to bad cond expr with known condition
Conditional expressions whose second & third operands have non-compatible types are not conform to the C standard and sparse emit a warning for them and return the expression as being erroneous. In consequence, such expressions are not given a type. This, in turn, makes that some further processing cannot be done (correctly). It seems that neither GCC nor clang emit a warning when there is a type mismatch but the condition is a constant. In the case we're interested here (the slow compilation of a file) the operation that cannot be done is the expansion its operands. This, in turn and among other things, makes that builtins like __builtin_constant_p() are not evaluated with disatrous consequence for the amount of work done in the next phases. Fix this by giving to conditional expressions with constant condition the same type as the operand selected by the conditional (but keeping the warning) as GCC & clang seems to do. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--evaluate.c12
-rw-r--r--validation/cond-err-expand.c27
2 files changed, 39 insertions, 0 deletions
diff --git a/evaluate.c b/evaluate.c
index cf3cf244..649e132b 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1220,6 +1220,18 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
Err:
expression_error(expr, "incompatible types in conditional expression (%s)", typediff);
+ /*
+ * if the condition is constant, the type is in fact known
+ * so use it, as gcc & clang do.
+ */
+ switch (expr_truth_value(expr->conditional)) {
+ case 1: expr->ctype = ltype;
+ break;
+ case 0: expr->ctype = rtype;
+ break;
+ default:
+ break;
+ }
return NULL;
out:
diff --git a/validation/cond-err-expand.c b/validation/cond-err-expand.c
new file mode 100644
index 00000000..93bbac15
--- /dev/null
+++ b/validation/cond-err-expand.c
@@ -0,0 +1,27 @@
+static inline void f(void)
+{
+ __builtin_constant_p(0);
+}
+
+void foo(void)
+{
+ 0 ? 0 : f();
+}
+
+void bar(void)
+{
+ 1 ? f() : 0;
+}
+
+/*
+ * check-name: cond-err-expand.c
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-start
+cond-err-expand.c:8:11: error: incompatible types in conditional expression (different base types)
+cond-err-expand.c:13:11: error: incompatible types in conditional expression (different base types)
+ * check-error-end
+ *
+ * check-output-ignore
+ * check-excludes: call.* __builtin_constant_p
+ */