diff mbox series

constexpr: relax constexprness of constant conditionals

Message ID 20190925224913.6056-1-luc.vanoostenryck@gmail.com (mailing list archive)
State Mainlined, archived
Headers show
Series constexpr: relax constexprness of constant conditionals | expand

Commit Message

Luc Van Oostenryck Sept. 25, 2019, 10:49 p.m. UTC
Currently, sparse emits a warning when a conditional expression with a
constant condition is used where an "Integer Constant Expression" is
expected and only the false-side operand (which is not evaluated) is
not constant. The standard are especially unclear about this situation.

However, GCC silently accept those as ICEs when they evaluate to a compile-time
known value (in other words, when the conditional and the corresponding
true/false sub-expression are themselves constant). The standard are
especially unclear about the situation when the unevaluated side is non-constant.

So, relax sparse to match GCC's behaviour.

Reported-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 evaluate.c                       | 28 +++++++++++++++-------------
 validation/constexpr-constcond.c | 10 ++++++++++
 validation/ioc-typecheck.c       |  4 ----
 3 files changed, 25 insertions(+), 17 deletions(-)
 create mode 100644 validation/constexpr-constcond.c
diff mbox series

Patch

diff --git a/evaluate.c b/evaluate.c
index 3268333ab..d52fd9f99 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1178,20 +1178,22 @@  static struct symbol *evaluate_conditional_expression(struct expression *expr)
 	expr->flags = (expr->conditional->flags & (*cond)->flags &
 			expr->cond_false->flags & ~CEF_CONST_MASK);
 	/*
-	 * A conditional operator yields a particular constant
-	 * expression type only if all of its three subexpressions are
-	 * of that type [6.6(6), 6.6(8)].
-	 * As an extension, relax this restriction by allowing any
-	 * constant expression type for the condition expression.
-	 *
-	 * A conditional operator never yields an address constant
-	 * [6.6(9)].
-	 * However, as an extension, if the condition is any constant
-	 * expression, and the true and false expressions are both
-	 * address constants, mark the result as an address constant.
+	 * In the standard, it is defined that an integer constant expression
+	 * shall only have operands that are themselves constant [6.6(6)].
+	 * While this definition is very clear for expressions that need all
+	 * their operands to be evaluated, for conditional expressions with a
+	 * constant condition things are much less obvious.
+	 * So, as an extension, do the same as GCC seems to do:
+	 *	Consider a conditional expression with a constant condition
+	 *	as having the same constantness as the argument corresponding
+	 *	to the truth value (including in the case of address constants
+	 *	which are defined more stricly [6.6(9)]).
 	 */
-	if (expr->conditional->flags & (CEF_ACE | CEF_ADDR))
-		expr->flags = (*cond)->flags & expr->cond_false->flags & ~CEF_CONST_MASK;
+	if (expr->conditional->flags & (CEF_ACE | CEF_ADDR)) {
+		int is_true = expr_truth_value(expr->conditional);
+		struct expression *arg = is_true ? *cond : expr->cond_false;
+		expr->flags = arg->flags & ~CEF_CONST_MASK;
+	}
 
 	lclass = classify_type(ltype, &ltype);
 	rclass = classify_type(rtype, &rtype);
diff --git a/validation/constexpr-constcond.c b/validation/constexpr-constcond.c
new file mode 100644
index 000000000..d98da3dc4
--- /dev/null
+++ b/validation/constexpr-constcond.c
@@ -0,0 +1,10 @@ 
+extern int var;
+
+static int a[] = {
+	[0 ? var : 1] = 0,
+	[1 ? 2 : var] = 0,
+};
+
+/*
+ * check-name: constexprness in constant conditionals
+ */
diff --git a/validation/ioc-typecheck.c b/validation/ioc-typecheck.c
index 34b37d310..7780773bc 100644
--- a/validation/ioc-typecheck.c
+++ b/validation/ioc-typecheck.c
@@ -4,8 +4,4 @@  static unsigned iocnrs[] = {
 };
 /*
  * check-name: integer constant & conditional expression
- * check-known-to-fail
- *
- * check-error-start
- * check-error-end
  */