* [PATCH v4 00/25] improve constexpr handling
@ 2017-03-31 1:44 Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 01/25] constexpr: introduce additional expression constness tracking flags Luc Van Oostenryck
` (25 more replies)
0 siblings, 26 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
Here is a respin of the series originally made and
submitted by Nicolai Stange.
The goal of this series is to improve the tracking of
expression constness in the sense of C99 [6.4.4, 6.6]:
more fine-grained and more correct. A new flag is added
for a strict mode while by default offering the relaxed
mode we're used to, for example for kernel compile.
Many thanks for Nicolai for his great job.
Changes since v3:
* take Chris' remarks in account:
- rename 'constexpr_flags' to the shorter 'flags'
- rename 'CONSTEXPR_FLAG_XYZ' to something shorter
- remove redundant 'INT' in the CONST_MASK
- try to avoid long lines and
- try to avoid to have to break lines
* and also:
- initialize EXPR_VALUE with SET_INT when typed
- extract the logic added in evaluate_cast and
use it in cast_to() where it is also needed
- remove patch 20 (symbol: do not inherit storage mod...)
as now MOD_PTRINHERIT doesn't imply MOD_STORAGE anymore
- avoid borrowing of surrounding storage mods
- add constness stuff for __builtin_bswap()
This serie can also be pulled from:
git://github.com/lucvoo/sparse.git constexpr-v4
the changes up to commit:
4d963a28d371ce75f65a70aa29f14cec5f08d8ff
since commit:
5c9411a5c0482b0ceb70861114df4c229e1298ca
Nicolai Stange (20):
constexpr: introduce additional expression constness tracking flags
constexpr: init flags at expression allocation
constexpr: examine constness of casts at evaluation only
constexpr: examine constness of binops and alike at evaluation only
constexpr: examine constness of preops at evaluation only
constexpr: examine constness of conditionals at evaluation only
constexpr: add support for tagging arithmetic constant expressions
constexpr: add support for tagging address constants
constexpr: check static storage duration objects' intializers' constness
constexpr: recognize static objects as address constants
constexpr: recognize address constants created through casts
constexpr: recognize address constants created through pointer arithmetic
constexpr: recognize members of static compound objects as address constants
constexpr: recognize string literals as address constants
constexpr: recognize references to labels as address constants
constexpr: examine constness of __builtin_offsetof at evaluation only
constexpr: flag builtins constant_p, safe_p and warning as constexprs
constexpr: relax some constant expression rules for pointer expressions
constexpr: support compound literals as address constants
constexpr: treat comparisons between types as integer constexpr
Luc Van Oostenryck (5):
constexpr: rename handle_simple_initializer() to handle_initializer()
constexpr: collect storage modifiers of initializers
return an error if too few args
give default return type in evaluate_call()
constexpr: flag __builtin_bswap() as constexpr
builtin.c | 26 +++-
evaluate.c | 206 ++++++++++++++++++++-------
expand.c | 2 +-
expression.c | 48 +++----
expression.h | 70 ++++++++-
lib.c | 2 +
lib.h | 1 +
sparse.1 | 9 ++
validation/constexpr-addr-of-static-member.c | 26 ++++
validation/constexpr-addr-of-static.c | 36 +++++
validation/constexpr-binop.c | 33 +++++
validation/constexpr-cast.c | 25 ++++
validation/constexpr-compound-literal.c | 19 +++
validation/constexpr-conditional.c | 34 +++++
validation/constexpr-init.c | 60 ++++++++
validation/constexpr-labelref.c | 14 ++
validation/constexpr-offsetof.c | 21 +++
validation/constexpr-pointer-arith.c | 28 ++++
validation/constexpr-pointer-cast.c | 13 ++
validation/constexpr-preop.c | 29 ++++
validation/constexpr-pure-builtin.c | 23 +++
validation/constexpr-string.c | 9 ++
validation/constexpr-types-compatible-p.c | 8 ++
23 files changed, 649 insertions(+), 93 deletions(-)
create mode 100644 validation/constexpr-addr-of-static-member.c
create mode 100644 validation/constexpr-addr-of-static.c
create mode 100644 validation/constexpr-binop.c
create mode 100644 validation/constexpr-cast.c
create mode 100644 validation/constexpr-compound-literal.c
create mode 100644 validation/constexpr-conditional.c
create mode 100644 validation/constexpr-init.c
create mode 100644 validation/constexpr-labelref.c
create mode 100644 validation/constexpr-offsetof.c
create mode 100644 validation/constexpr-pointer-arith.c
create mode 100644 validation/constexpr-pointer-cast.c
create mode 100644 validation/constexpr-preop.c
create mode 100644 validation/constexpr-pure-builtin.c
create mode 100644 validation/constexpr-string.c
create mode 100644 validation/constexpr-types-compatible-p.c
--
2.12.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v4 01/25] constexpr: introduce additional expression constness tracking flags
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 02/25] constexpr: init flags at expression allocation Luc Van Oostenryck
` (24 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Even if sparse attempted to verify that initializers for static storage
duration objects are constant expressions [6.7.8(4)] (which it
currently does not), it could not tell reliably.
Example:
enum { b = 0 };
static void *c = { (void*)b }; /* disallowed by C99 */
References to enum members are not allowed in address constants [6.6(9)]
and thus, the initializer is not a constant expression at all.
Prepare for a more fine-grained tracking of expression constness in the
sense of C99 [6.4.4, 6.6].
Introduce a broader set of constness tracking flags, resembling the
four types of primary expression constants [6.4.4] (integer, floating,
enumeration, character). Define helper macros to consistently set and
clear these flags as they are not completely independent.
In particular, introduce the following flags for tagging expression constness
at the level of primary expressions:
- CEF_INT: integer constant, i.e. literal
- CEF_FLOAT: floating point constant (former Float_literal flag)
- CEF_ENUM: enumeration constant
- CEF_CHAR: character constant
Introduce the CEF_ICE flag meant for tagging integer constant
expressions. It is equivalent to the former Int_const_expr flag.
Note that CEF_INT, CEF_ENUM and CEF_CHAR flags imply CEF_ICE being set.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 52 +++++++++++++++++++++++++-------------------------
expand.c | 2 +-
expression.c | 62 +++++++++++++++++++++++++++++++++++++-----------------------
expression.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++----
4 files changed, 118 insertions(+), 55 deletions(-)
diff --git a/evaluate.c b/evaluate.c
index 47eeaef2e..18f1da8b3 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -404,7 +404,7 @@ static struct symbol *bad_expr_type(struct expression *expr)
break;
}
- expr->flags = 0;
+ expr->flags = CEF_NONE;
return expr->ctype = &bad_ctype;
}
@@ -889,8 +889,8 @@ static struct symbol *evaluate_logical(struct expression *expr)
/* the result is int [6.5.13(3), 6.5.14(3)] */
expr->ctype = &int_ctype;
if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & Int_const_expr))
- expr->flags = 0;
+ if (!(expr->left->flags & expr->right->flags & CEF_ICE))
+ expr->flags = CEF_NONE;
}
return &int_ctype;
}
@@ -903,8 +903,8 @@ static struct symbol *evaluate_binop(struct expression *expr)
int op = expr->op;
if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & Int_const_expr))
- expr->flags = 0;
+ if (!(expr->left->flags & expr->right->flags & CEF_ICE))
+ expr->flags = CEF_NONE;
}
/* number op number */
@@ -995,7 +995,7 @@ static inline int is_null_pointer_constant(struct expression *e)
{
if (e->ctype == &null_ctype)
return 1;
- if (!(e->flags & Int_const_expr))
+ if (!(e->flags & CEF_ICE))
return 0;
return is_zero_constant(e) ? 2 : 0;
}
@@ -1010,8 +1010,8 @@ static struct symbol *evaluate_compare(struct expression *expr)
const char *typediff;
if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & Int_const_expr))
- expr->flags = 0;
+ if (!(expr->left->flags & expr->right->flags & CEF_ICE))
+ expr->flags = CEF_NONE;
}
/* Type types? */
@@ -1129,10 +1129,10 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
}
if (expr->flags) {
- int flags = expr->conditional->flags & Int_const_expr;
+ int flags = expr->conditional->flags & CEF_ICE;
flags &= (*true)->flags & expr->cond_false->flags;
if (!flags)
- expr->flags = 0;
+ expr->flags = CEF_NONE;
}
lclass = classify_type(ltype, <ype);
@@ -1693,7 +1693,7 @@ static struct symbol *evaluate_addressof(struct expression *expr)
}
ctype = op->ctype;
*expr = *op->unop;
- expr->flags = 0;
+ expr->flags = CEF_NONE;
if (expr->type == EXPR_SYMBOL) {
struct symbol *sym = expr->symbol;
@@ -1721,7 +1721,7 @@ static struct symbol *evaluate_dereference(struct expression *expr)
/* Simplify: *&(expr) => (expr) */
if (op->type == EXPR_PREOP && op->op == '&') {
*expr = *op->unop;
- expr->flags = 0;
+ expr->flags = CEF_NONE;
return expr->ctype;
}
@@ -1811,8 +1811,8 @@ static struct symbol *evaluate_sign(struct expression *expr)
{
struct symbol *ctype = expr->unop->ctype;
int class = classify_type(ctype, &ctype);
- if (expr->flags && !(expr->unop->flags & Int_const_expr))
- expr->flags = 0;
+ if (expr->flags && !(expr->unop->flags & CEF_ICE))
+ expr->flags = CEF_NONE;
/* should be an arithmetic type */
if (!(class & TYPE_NUM))
return bad_expr_type(expr);
@@ -1866,8 +1866,8 @@ static struct symbol *evaluate_preop(struct expression *expr)
return evaluate_postop(expr);
case '!':
- if (expr->flags && !(expr->unop->flags & Int_const_expr))
- expr->flags = 0;
+ if (expr->flags && !(expr->unop->flags & CEF_ICE))
+ expr->flags = CEF_NONE;
if (is_safe_type(ctype))
warning(expr->pos, "testing a 'safe expression'");
if (is_float_type(ctype)) {
@@ -2770,12 +2770,12 @@ static struct symbol *evaluate_cast(struct expression *expr)
/* cast to non-integer type -> not an integer constant expression */
if (!is_int(class1))
- expr->flags = 0;
+ expr->flags = CEF_NONE;
/* if argument turns out to be not an integer constant expression *and*
it was not a floating literal to start with -> too bad */
- else if (expr->flags == Int_const_expr &&
- !(target->flags & Int_const_expr))
- expr->flags = 0;
+ else if (expr->flags & CEF_ICE && !(target->flags & CEF_ICE))
+ expr->flags = CEF_NONE;
+
/*
* You can always throw a value away by casting to
* "void" - that's an implicit "force". Note that
@@ -2837,7 +2837,7 @@ static struct symbol *evaluate_cast(struct expression *expr)
"cast adds address space to expression (<asn:%d>)", as1);
if (!(t1->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR &&
- !as1 && (target->flags & Int_const_expr)) {
+ !as1 && (target->flags & CEF_ICE)) {
if (t1->ctype.base_type == &void_ctype) {
if (is_zero_constant(target)) {
/* NULL */
@@ -2971,7 +2971,7 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
}
ctype = field;
expr->type = EXPR_VALUE;
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_ICE;
expr->value = offset;
expr->taint = 0;
expr->ctype = size_t_ctype;
@@ -2989,7 +2989,7 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
ctype = ctype->ctype.base_type;
if (!expr->index) {
expr->type = EXPR_VALUE;
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_ICE;
expr->value = 0;
expr->taint = 0;
expr->ctype = size_t_ctype;
@@ -3006,13 +3006,13 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
m = alloc_const_expression(expr->pos,
bits_to_bytes(ctype->bit_size));
m->ctype = size_t_ctype;
- m->flags = Int_const_expr;
+ m->flags |= CEF_SET_ICE;
expr->type = EXPR_BINOP;
expr->left = idx;
expr->right = m;
expr->op = '*';
expr->ctype = size_t_ctype;
- expr->flags = m->flags & idx->flags & Int_const_expr;
+ expr->flags = m->flags & idx->flags;
}
}
if (e) {
@@ -3023,7 +3023,7 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
if (!evaluate_expression(e))
return NULL;
expr->type = EXPR_BINOP;
- expr->flags = e->flags & copy->flags & Int_const_expr;
+ expr->flags = e->flags & copy->flags & ~CEF_CONST_MASK;
expr->op = '+';
expr->ctype = size_t_ctype;
expr->left = copy;
diff --git a/expand.c b/expand.c
index 5f908c971..3a6684226 100644
--- a/expand.c
+++ b/expand.c
@@ -1223,7 +1223,7 @@ static int expand_statement(struct statement *stmt)
static inline int bad_integer_constant_expression(struct expression *expr)
{
- if (!(expr->flags & Int_const_expr))
+ if (!(expr->flags & CEF_ICE))
return 1;
if (expr->taint & Taint_comma)
return 1;
diff --git a/expression.c b/expression.c
index 638639df8..4189e5f3a 100644
--- a/expression.c
+++ b/expression.c
@@ -131,7 +131,7 @@ static struct token *parse_type(struct token *token, struct expression **tree)
{
struct symbol *sym;
*tree = alloc_expression(token->pos, EXPR_TYPE);
- (*tree)->flags = Int_const_expr; /* sic */
+ (*tree)->flags = CEF_SET_ICE; /* sic */
token = typename(token, &sym, NULL);
if (sym->ident)
sparse_error(token->pos,
@@ -146,7 +146,7 @@ static struct token *builtin_types_compatible_p_expr(struct token *token,
{
struct expression *expr = alloc_expression(
token->pos, EXPR_COMPARE);
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_ICE;
expr->op = SPECIAL_EQUAL;
token = token->next;
if (!match_op(token, '('))
@@ -200,7 +200,7 @@ static struct token *builtin_offsetof_expr(struct token *token,
return expect(token, ')', "at end of __builtin_offset");
case SPECIAL_DEREFERENCE:
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = Int_const_expr;
+ e->flags = CEF_SET_ICE;
e->op = '[';
*p = e;
p = &e->down;
@@ -208,7 +208,7 @@ static struct token *builtin_offsetof_expr(struct token *token,
case '.':
token = token->next;
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = Int_const_expr;
+ e->flags = CEF_SET_ICE;
e->op = '.';
if (token_type(token) != TOKEN_IDENT) {
sparse_error(token->pos, "Expected member name");
@@ -220,7 +220,7 @@ static struct token *builtin_offsetof_expr(struct token *token,
case '[':
token = token->next;
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = Int_const_expr;
+ e->flags = CEF_SET_ICE;
e->op = '[';
token = parse_expression(token, &e->index);
token = expect(token, ']',
@@ -336,7 +336,7 @@ got_it:
"likely to produce unsigned long (and a warning) here",
show_token(token));
expr->type = EXPR_VALUE;
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_INT;
expr->ctype = ctype_integer(size, want_unsigned);
expr->value = value;
return;
@@ -361,7 +361,7 @@ Float:
else
goto Enoint;
- expr->flags = Float_literal;
+ expr->flags = CEF_SET_FLOAT;
expr->type = EXPR_FVALUE;
return;
@@ -375,8 +375,8 @@ struct token *primary_expression(struct token *token, struct expression **tree)
switch (token_type(token)) {
case TOKEN_CHAR ... TOKEN_WIDE_CHAR_EMBEDDED_3:
- expr = alloc_expression(token->pos, EXPR_VALUE);
- expr->flags = Int_const_expr;
+ expr = alloc_expression(token->pos, EXPR_VALUE);
+ expr->flags = CEF_SET_CHAR;
expr->ctype = token_type(token) < TOKEN_WIDE_CHAR ? &int_ctype : &long_ctype;
get_char_constant(token, &expr->value);
token = token->next;
@@ -390,7 +390,7 @@ struct token *primary_expression(struct token *token, struct expression **tree)
case TOKEN_ZERO_IDENT: {
expr = alloc_expression(token->pos, EXPR_SYMBOL);
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_INT;
expr->ctype = &int_ctype;
expr->symbol = &zero_int;
expr->symbol_name = token->ident;
@@ -417,7 +417,7 @@ struct token *primary_expression(struct token *token, struct expression **tree)
*expr = *sym->initializer;
/* we want the right position reported, thus the copy */
expr->pos = token->pos;
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_ENUM;
token = next;
break;
}
@@ -457,7 +457,8 @@ struct token *primary_expression(struct token *token, struct expression **tree)
}
if (token->special == '[' && lookup_type(token->next)) {
expr = alloc_expression(token->pos, EXPR_TYPE);
- expr->flags = Int_const_expr; /* sic */
+ /* sic */
+ expr->flags = CEF_SET_ICE;
token = typename(token->next, &expr->symbol, NULL);
token = expect(token, ']', "in type expression");
break;
@@ -573,7 +574,7 @@ static struct token *type_info_expression(struct token *token,
struct token *p;
*tree = expr;
- expr->flags = Int_const_expr; /* XXX: VLA support will need that changed */
+ expr->flags = CEF_SET_ICE; /* XXX: VLA support will need that changed */
token = token->next;
if (!match_op(token, '(') || !lookup_type(token->next))
return unary_expression(token, &expr->cast_expression);
@@ -663,7 +664,7 @@ static struct token *unary_expression(struct token *token, struct expression **t
unary = alloc_expression(token->pos, EXPR_PREOP);
unary->op = token->special;
unary->unop = unop;
- unary->flags = unop->flags & Int_const_expr;
+ unary->flags = unop->flags & ~CEF_CONST_MASK;
*tree = unary;
return next;
}
@@ -721,10 +722,25 @@ static struct token *cast_expression(struct token *token, struct expression **tr
if (!v)
return token;
cast->cast_expression = v;
- if (v->flags & Int_const_expr)
- cast->flags = Int_const_expr;
- else if (v->flags & Float_literal) /* and _not_ int */
- cast->flags = Int_const_expr | Float_literal;
+
+ cast->flags = v->flags & ~CEF_CONST_MASK;
+ /*
+ * Up to now, we missed the (int).0 case here
+ * which should really get a
+ * CEF_ICE marker. Also,
+ * conversion to non-numeric types is not
+ * properly reflected up to this point.
+ * However, we do not know until evaluation.
+ * For the moment, in order to preserve
+ * semantics, speculatively set
+ * CEF_ICE if
+ * CEF_FLOAT is
+ * set. evaluate_cast() will unset
+ * inappropriate flags again after examining
+ * type information.
+ */
+ if (v->flags & CEF_FLOAT)
+ cast->flags |= CEF_SET_ICE;
return token;
}
}
@@ -762,7 +778,7 @@ static struct token *cast_expression(struct token *token, struct expression **tr
break; \
} \
top->flags = left->flags & right->flags \
- & Int_const_expr; \
+ & ~CEF_CONST_MASK; \
top->op = op; \
top->left = left; \
top->right = right; \
@@ -866,12 +882,10 @@ struct token *conditional_expression(struct token *token, struct expression **tr
token = expect(token, ':', "in conditional expression");
token = conditional_expression(token, &expr->cond_false);
if (expr->left && expr->cond_false) {
- int is_const = expr->left->flags &
- expr->cond_false->flags &
- Int_const_expr;
+ expr->flags = expr->left->flags & expr->cond_false->flags;
if (expr->cond_true)
- is_const &= expr->cond_true->flags;
- expr->flags = is_const;
+ expr->flags &= expr->cond_true->flags;
+ expr->flags &= ~CEF_CONST_MASK;
}
}
return token;
diff --git a/expression.h b/expression.h
index 80b3be5f5..e02cb8584 100644
--- a/expression.h
+++ b/expression.h
@@ -66,10 +66,59 @@ enum expression_type {
EXPR_OFFSETOF,
};
-enum {
- Int_const_expr = 1,
- Float_literal = 2,
-}; /* for expr->flags */
+
+/*
+ * Flags for tracking the promotion of constness related attributes
+ * from subexpressions to their parents.
+ *
+ * The flags are not independent as one might imply another.
+ * The implications are as follows:
+ * - CEF_INT, CEF_ENUM and
+ * CEF_CHAR imply CEF_ICE.
+ *
+ * Use the CEF_*_SET_MASK and CEF_*_CLEAR_MASK
+ * helper macros defined below to set or clear one of these flags.
+ */
+enum constexpr_flag {
+ CEF_NONE = 0,
+ /*
+ * A constant in the sense of [6.4.4]:
+ * - Integer constant [6.4.4.1]
+ * - Floating point constant [6.4.4.2]
+ * - Enumeration constant [6.4.4.3]
+ * - Character constant [6.4.4.4]
+ */
+ CEF_INT = (1 << 0),
+ CEF_FLOAT = (1 << 1),
+ CEF_ENUM = (1 << 2),
+ CEF_CHAR = (1 << 3),
+
+ /*
+ * A constant expression in the sense of [6.6]:
+ * - integer constant expression [6.6(6)]
+ */
+ CEF_ICE = (1 << 4),
+
+
+ CEF_SET_ICE = (CEF_ICE),
+
+ /* integer constant => integer constant expression */
+ CEF_SET_INT = (CEF_INT | CEF_SET_ICE),
+
+ CEF_SET_FLOAT = (CEF_FLOAT),
+
+ /* enumeration constant => integer constant expression */
+ CEF_SET_ENUM = (CEF_ENUM | CEF_SET_ICE),
+
+ /* character constant => integer constant expression */
+ CEF_SET_CHAR = (CEF_CHAR | CEF_SET_ICE),
+
+ /*
+ * Remove any "Constant" [6.4.4] flag, but retain the "constant
+ * expression" [6.6] flags.
+ */
+ CEF_CONST_MASK = (CEF_INT | CEF_FLOAT | CEF_CHAR),
+};
enum {
Taint_comma = 1,
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 02/25] constexpr: init flags at expression allocation
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 01/25] constexpr: introduce additional expression constness tracking flags Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 03/25] constexpr: examine constness of casts at evaluation only Luc Van Oostenryck
` (23 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Currently, the expression evaluation code explicitly opts out from
constness at evaluation if certain criteria regarding the subexpressions
are not matched.
Instead of this active opt-out, we want to have subexpression constness
attributes to get propagated from child expressions to their parents in
the future.
A prerequisite is that each expression's ->flags is in a defined
state at all times.
Set ->flags to SET_INT or NONE at expression allocation time,
depending if the expression has a type or not
(alloc_const_expression() or alloc_expression()).
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
expression.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/expression.h b/expression.h
index e02cb8584..ec94ff4a1 100644
--- a/expression.h
+++ b/expression.h
@@ -249,6 +249,7 @@ static inline struct expression *alloc_expression(struct position pos, int type)
struct expression *expr = __alloc_expression(0);
expr->type = type;
expr->pos = pos;
+ expr->flags = CEF_NONE;
return expr;
}
@@ -259,6 +260,7 @@ static inline struct expression *alloc_const_expression(struct position pos, int
expr->pos = pos;
expr->value = value;
expr->ctype = &int_ctype;
+ expr->flags = CEF_SET_INT;
return expr;
}
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 03/25] constexpr: examine constness of casts at evaluation only
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 01/25] constexpr: introduce additional expression constness tracking flags Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 02/25] constexpr: init flags at expression allocation Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 04/25] constexpr: examine constness of binops and alike " Luc Van Oostenryck
` (22 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Move the whole calculation of cast expressions' constness flags to the
evaluation phase such that expressions like
(int)__builtin_choose_expr(0, 0, 0)
can now be recognized as qualifying as integer constant expressions.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 37 +++++++++++++++++++++++++++++--------
expression.c | 19 -------------------
expression.h | 7 +++++++
validation/constexpr-cast.c | 25 +++++++++++++++++++++++++
4 files changed, 61 insertions(+), 27 deletions(-)
create mode 100644 validation/constexpr-cast.c
diff --git a/evaluate.c b/evaluate.c
index 18f1da8b3..5725e898f 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -271,6 +271,7 @@ warn_for_different_enum_types (struct position pos,
}
}
+static int cast_flags(struct expression *expr, struct expression *target);
static struct symbol *cast_to_bool(struct expression *expr);
/*
@@ -323,10 +324,10 @@ static struct expression * cast_to(struct expression *old, struct symbol *type)
}
expr = alloc_expression(old->pos, EXPR_IMPLIED_CAST);
- expr->flags = old->flags;
expr->ctype = type;
expr->cast_type = type;
expr->cast_expression = old;
+ expr->flags = cast_flags(expr, old);
if (is_bool_type(type))
cast_to_bool(expr);
@@ -2720,6 +2721,32 @@ static struct symbol *cast_to_bool(struct expression *expr)
return expr->ctype;
}
+static int cast_flags(struct expression *expr, struct expression *old)
+{
+ struct symbol *t;
+ int class;
+ int flags = CEF_NONE;
+
+ class = classify_type(expr->ctype, &t);
+ if (class & TYPE_NUM) {
+ flags = old->flags & ~CEF_CONST_MASK;
+ /*
+ * Cast to float type -> not an integer constant
+ * expression [6.6(6)].
+ */
+ if (class & TYPE_FLOAT)
+ flags &= ~CEF_CLR_ICE;
+ /*
+ * Casts of float literals to integer type results in
+ * a constant integer expression [6.6(6)].
+ */
+ else if (old->flags & CEF_FLOAT)
+ flags = CEF_SET_ICE;
+ }
+
+ return flags;
+}
+
static struct symbol *evaluate_cast(struct expression *expr)
{
struct expression *target = expr->cast_expression;
@@ -2768,13 +2795,7 @@ static struct symbol *evaluate_cast(struct expression *expr)
class1 = classify_type(ctype, &t1);
- /* cast to non-integer type -> not an integer constant expression */
- if (!is_int(class1))
- expr->flags = CEF_NONE;
- /* if argument turns out to be not an integer constant expression *and*
- it was not a floating literal to start with -> too bad */
- else if (expr->flags & CEF_ICE && !(target->flags & CEF_ICE))
- expr->flags = CEF_NONE;
+ expr->flags = cast_flags(expr, target);
/*
* You can always throw a value away by casting to
diff --git a/expression.c b/expression.c
index 4189e5f3a..3262cf22c 100644
--- a/expression.c
+++ b/expression.c
@@ -722,25 +722,6 @@ static struct token *cast_expression(struct token *token, struct expression **tr
if (!v)
return token;
cast->cast_expression = v;
-
- cast->flags = v->flags & ~CEF_CONST_MASK;
- /*
- * Up to now, we missed the (int).0 case here
- * which should really get a
- * CEF_ICE marker. Also,
- * conversion to non-numeric types is not
- * properly reflected up to this point.
- * However, we do not know until evaluation.
- * For the moment, in order to preserve
- * semantics, speculatively set
- * CEF_ICE if
- * CEF_FLOAT is
- * set. evaluate_cast() will unset
- * inappropriate flags again after examining
- * type information.
- */
- if (v->flags & CEF_FLOAT)
- cast->flags |= CEF_SET_ICE;
return token;
}
}
diff --git a/expression.h b/expression.h
index ec94ff4a1..c084783c8 100644
--- a/expression.h
+++ b/expression.h
@@ -120,6 +120,13 @@ enum constexpr_flag {
CEF_CONST_MASK = (CEF_INT | CEF_FLOAT | CEF_CHAR),
};
+/*
+ * not an integer constant expression => neither of integer,
+ * enumeration and character constant
+ */
+#define CEF_CLR_ICE \
+ (CEF_ICE | CEF_INT | CEF_ENUM | CEF_CHAR)
+
enum {
Taint_comma = 1,
}; /* for expr->taint */
diff --git a/validation/constexpr-cast.c b/validation/constexpr-cast.c
new file mode 100644
index 000000000..27069614c
--- /dev/null
+++ b/validation/constexpr-cast.c
@@ -0,0 +1,25 @@
+static int a[] = {
+ [(int)0] = 0, // OK
+ [(int)(int)0] = 0, // OK
+ [(int)0.] = 0, // OK
+ [(int)(int)0.] = 0, // OK
+ [(int)__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [(int)__builtin_choose_expr(0, 0, 0.)] = 0, // OK
+
+ [(int)(float)0] = 0, // KO
+ [(int)(float)0.] = 0, // KO
+
+ [(int)(void*)0] = 0, // KO
+ [(int)(void*)0.] = 0, // KO
+
+};
+/*
+ * check-name: Expression constness propagation in casts
+ *
+ * check-error-start
+constexpr-cast.c:9:11: error: bad integer constant expression
+constexpr-cast.c:10:11: error: bad integer constant expression
+constexpr-cast.c:12:11: error: bad integer constant expression
+constexpr-cast.c:13:11: error: bad integer constant expression
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 04/25] constexpr: examine constness of binops and alike at evaluation only
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (2 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 03/25] constexpr: examine constness of casts at evaluation only Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 05/25] constexpr: examine constness of preops " Luc Van Oostenryck
` (21 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Move the whole calculation of binary operations', compare and logical
expressions' constness flags to the evaluation phase such that expressions
like
0 + __builtin_choose_expr(0, 0, 0)
0 < __builtin_choose_expr(0, 0, 0)
0 && __builtin_choose_expr(0, 0, 0)
can now be recognized as qualifying as integer constant expressions.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 19 ++++++-------------
expression.c | 3 ---
validation/constexpr-binop.c | 33 +++++++++++++++++++++++++++++++++
3 files changed, 39 insertions(+), 16 deletions(-)
create mode 100644 validation/constexpr-binop.c
diff --git a/evaluate.c b/evaluate.c
index 5725e898f..48530f28c 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -889,10 +889,8 @@ static struct symbol *evaluate_logical(struct expression *expr)
/* the result is int [6.5.13(3), 6.5.14(3)] */
expr->ctype = &int_ctype;
- if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & CEF_ICE))
- expr->flags = CEF_NONE;
- }
+ expr->flags = expr->left->flags & expr->right->flags;
+ expr->flags &= ~CEF_CONST_MASK;
return &int_ctype;
}
@@ -903,13 +901,11 @@ static struct symbol *evaluate_binop(struct expression *expr)
int rclass = classify_type(expr->right->ctype, &rtype);
int op = expr->op;
- if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & CEF_ICE))
- expr->flags = CEF_NONE;
- }
-
/* number op number */
if (lclass & rclass & TYPE_NUM) {
+ expr->flags = expr->left->flags & expr->right->flags;
+ expr->flags &= ~CEF_CONST_MASK;
+
if ((lclass | rclass) & TYPE_FLOAT) {
switch (op) {
case '+': case '-': case '*': case '/':
@@ -1010,10 +1006,7 @@ static struct symbol *evaluate_compare(struct expression *expr)
struct symbol *ctype;
const char *typediff;
- if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & CEF_ICE))
- expr->flags = CEF_NONE;
- }
+ expr->flags = left->flags & right->flags & ~CEF_CONST_MASK;
/* Type types? */
if (is_type_type(ltype) && is_type_type(rtype))
diff --git a/expression.c b/expression.c
index 3262cf22c..b59af8886 100644
--- a/expression.c
+++ b/expression.c
@@ -146,7 +146,6 @@ static struct token *builtin_types_compatible_p_expr(struct token *token,
{
struct expression *expr = alloc_expression(
token->pos, EXPR_COMPARE);
- expr->flags = CEF_SET_ICE;
expr->op = SPECIAL_EQUAL;
token = token->next;
if (!match_op(token, '('))
@@ -758,8 +757,6 @@ static struct token *cast_expression(struct token *token, struct expression **tr
sparse_error(next->pos, "No right hand side of '%s'-expression", show_special(op)); \
break; \
} \
- top->flags = left->flags & right->flags \
- & ~CEF_CONST_MASK; \
top->op = op; \
top->left = left; \
top->right = right; \
diff --git a/validation/constexpr-binop.c b/validation/constexpr-binop.c
new file mode 100644
index 000000000..85a88e3cd
--- /dev/null
+++ b/validation/constexpr-binop.c
@@ -0,0 +1,33 @@
+static int a[] = {
+ [0 + 0] = 0, // OK
+ [0 + 0.] = 0, // KO
+ [(void*)0 + 0] = 0, // KO
+ [0 + __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [0 + __builtin_choose_expr(0, 0., 0)] = 0, // OK
+ [0 + __builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [0 < 0] = 0, // OK
+ [0 < 0.] = 0, // KO
+ [0 < __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [0 < __builtin_choose_expr(0, 0., 0)] = 0, // OK
+ [0 < __builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [0 && 0] = 0, // OK
+ [0 && 0.] = 0, // KO
+ [0 && __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [0 && __builtin_choose_expr(0, 0., 0)] = 0, // OK
+ [0 && __builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [0 + __builtin_types_compatible_p(int, float)] = 0, // OK
+};
+
+/*
+ * check-name: Expression constness propagation in binops and alike
+ *
+ * check-error-start
+constexpr-binop.c:3:12: error: bad constant expression
+constexpr-binop.c:4:19: error: bad integer constant expression
+constexpr-binop.c:7:12: error: bad constant expression
+constexpr-binop.c:9:12: error: bad integer constant expression
+constexpr-binop.c:12:12: error: bad integer constant expression
+constexpr-binop.c:14:12: error: bad integer constant expression
+constexpr-binop.c:17:12: error: bad integer constant expression
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 05/25] constexpr: examine constness of preops at evaluation only
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (3 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 04/25] constexpr: examine constness of binops and alike " Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 06/25] constexpr: examine constness of conditionals " Luc Van Oostenryck
` (20 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Move the whole calculation of prefix expressions' constness flags to
the evaluation phase such that expressions like
-__builtin_choose_expr(0, 0, 0)
~__builtin_choose_expr(0, 0, 0)
!__builtin_choose_expr(0, 0, 0)
can now be recognized as qualifying as integer constant expressions.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 8 ++++----
expression.c | 3 ---
validation/constexpr-preop.c | 29 +++++++++++++++++++++++++++++
3 files changed, 33 insertions(+), 7 deletions(-)
create mode 100644 validation/constexpr-preop.c
diff --git a/evaluate.c b/evaluate.c
index 48530f28c..07788eacc 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1805,8 +1805,8 @@ static struct symbol *evaluate_sign(struct expression *expr)
{
struct symbol *ctype = expr->unop->ctype;
int class = classify_type(ctype, &ctype);
- if (expr->flags && !(expr->unop->flags & CEF_ICE))
- expr->flags = CEF_NONE;
+ unsigned char flags = expr->unop->flags & ~CEF_CONST_MASK;
+
/* should be an arithmetic type */
if (!(class & TYPE_NUM))
return bad_expr_type(expr);
@@ -1823,6 +1823,7 @@ Normal:
}
if (expr->op == '+')
*expr = *expr->unop;
+ expr->flags = flags;
expr->ctype = ctype;
return ctype;
Restr:
@@ -1860,8 +1861,7 @@ static struct symbol *evaluate_preop(struct expression *expr)
return evaluate_postop(expr);
case '!':
- if (expr->flags && !(expr->unop->flags & CEF_ICE))
- expr->flags = CEF_NONE;
+ expr->flags = expr->unop->flags & ~CEF_CONST_MASK;
if (is_safe_type(ctype))
warning(expr->pos, "testing a 'safe expression'");
if (is_float_type(ctype)) {
diff --git a/expression.c b/expression.c
index b59af8886..0332c4406 100644
--- a/expression.c
+++ b/expression.c
@@ -450,8 +450,6 @@ struct token *primary_expression(struct token *token, struct expression **tree)
expr = alloc_expression(token->pos, EXPR_PREOP);
expr->op = '(';
token = parens_expression(token, &expr->unop, "in expression");
- if (expr->unop)
- expr->flags = expr->unop->flags;
break;
}
if (token->special == '[' && lookup_type(token->next)) {
@@ -663,7 +661,6 @@ static struct token *unary_expression(struct token *token, struct expression **t
unary = alloc_expression(token->pos, EXPR_PREOP);
unary->op = token->special;
unary->unop = unop;
- unary->flags = unop->flags & ~CEF_CONST_MASK;
*tree = unary;
return next;
}
diff --git a/validation/constexpr-preop.c b/validation/constexpr-preop.c
new file mode 100644
index 000000000..5d869da4f
--- /dev/null
+++ b/validation/constexpr-preop.c
@@ -0,0 +1,29 @@
+static int a[] = {
+ [+0] = 0, // OK
+ [+__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [+0.] = 0, // KO
+ [+__builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [-0] = 0, // OK
+ [-__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [-0.] = 0, // KO
+ [-__builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [~0] = 0, // OK
+ [~__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [!0] = 0, // OK
+ [!__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [!0.] = 0, // KO
+ [!__builtin_choose_expr(0, 0, 0.)] = 0, // KO
+};
+
+/*
+ * check-name: Expression constness propagation in preops
+ *
+ * check-error-start
+constexpr-preop.c:4:5: error: bad constant expression
+constexpr-preop.c:5:33: error: bad constant expression
+constexpr-preop.c:8:4: error: bad constant expression
+constexpr-preop.c:9:4: error: bad constant expression
+constexpr-preop.c:14:4: error: bad integer constant expression
+constexpr-preop.c:15:4: error: bad integer constant expression
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 06/25] constexpr: examine constness of conditionals at evaluation only
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (4 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 05/25] constexpr: examine constness of preops " Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 07/25] constexpr: add support for tagging arithmetic constant expressions Luc Van Oostenryck
` (19 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Move the whole calculation of conditional expressions' constness flags
to the evaluation phase such that expressions like
0 ? __builtin_choose_expr(0, 0, 0) : 0
0 ? 0 : __builtin_choose_expr(0, 0, 0)
can now be recognized as qualifying as integer constant expressions.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 8 ++------
expression.c | 6 ------
validation/constexpr-conditional.c | 34 ++++++++++++++++++++++++++++++++++
3 files changed, 36 insertions(+), 12 deletions(-)
create mode 100644 validation/constexpr-conditional.c
diff --git a/evaluate.c b/evaluate.c
index 07788eacc..6d6e462cd 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1122,12 +1122,8 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
true = &expr->cond_true;
}
- if (expr->flags) {
- int flags = expr->conditional->flags & CEF_ICE;
- flags &= (*true)->flags & expr->cond_false->flags;
- if (!flags)
- expr->flags = CEF_NONE;
- }
+ expr->flags = (expr->conditional->flags & (*true)->flags &
+ expr->cond_false->flags & ~CEF_CONST_MASK);
lclass = classify_type(ltype, <ype);
rclass = classify_type(rtype, &rtype);
diff --git a/expression.c b/expression.c
index 0332c4406..7f1eff306 100644
--- a/expression.c
+++ b/expression.c
@@ -856,12 +856,6 @@ struct token *conditional_expression(struct token *token, struct expression **tr
token = parse_expression(token->next, &expr->cond_true);
token = expect(token, ':', "in conditional expression");
token = conditional_expression(token, &expr->cond_false);
- if (expr->left && expr->cond_false) {
- expr->flags = expr->left->flags & expr->cond_false->flags;
- if (expr->cond_true)
- expr->flags &= expr->cond_true->flags;
- expr->flags &= ~CEF_CONST_MASK;
- }
}
return token;
}
diff --git a/validation/constexpr-conditional.c b/validation/constexpr-conditional.c
new file mode 100644
index 000000000..a3331b3ef
--- /dev/null
+++ b/validation/constexpr-conditional.c
@@ -0,0 +1,34 @@
+static int a[] = {
+ [0 ? : 0] = 0, // OK
+ [1 ? : 0] = 0, // OK
+ [0 ? 0 : 0] = 0, // OK
+ [1 ? 0 : 0] = 0, // OK
+ [0 ? 0 : __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [1 ? __builtin_choose_expr(0, 0, 0) : 0] = 0, // OK
+ [0 ? __builtin_choose_expr(0, 0, 0) : 0] = 0, // OK
+ [1 ? 1 : __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [__builtin_choose_expr(0, 0, 0) ? : 0] = 0, // OK
+ [__builtin_choose_expr(0, 0, 1) ? : 0] = 0, // OK
+ [0. ? : 0] = 0, // KO
+ [0 ? 0. : 0] = 0, // KO
+ [1 ? : 0.] = 0, // KO
+ [__builtin_choose_expr(0, 0., 0) ? : 0] = 0, // OK
+ [__builtin_choose_expr(0, 0, 0.) ? : 0] = 0, // KO
+ [0 ? __builtin_choose_expr(0, 0., 0) : 0] = 0, // OK
+ [0 ? __builtin_choose_expr(0, 0, 0.) : 0] = 0, // KO
+ [1 ? 0 : __builtin_choose_expr(0, 0., 0)] = 0, // OK
+ [1 ? 0 : __builtin_choose_expr(0, 0, 0.)] = 0, // KO
+};
+
+/*
+ * check-name: Expression constness propagation in conditional expressions
+ *
+ * check-error-start
+constexpr-conditional.c:12:13: error: bad constant expression
+constexpr-conditional.c:13:19: error: bad constant expression
+constexpr-conditional.c:14:12: error: bad constant expression
+constexpr-conditional.c:16:42: error: bad constant expression
+constexpr-conditional.c:18:48: error: bad constant expression
+constexpr-conditional.c:20:14: error: bad constant expression
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 07/25] constexpr: add support for tagging arithmetic constant expressions
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (5 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 06/25] constexpr: examine constness of conditionals " Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 08/25] constexpr: add support for tagging address constants Luc Van Oostenryck
` (18 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Arithmetic constant expressions may be either of (6.6(8)):
- integer constant expressions
- floating point constants
or any arithmetic expression build up from them.
Furthermore, casts with arithmetic destination types preserve
arithmetic constness.
Arithmetic constant expressions may be used as initializers for
objects of static storage duration.
Introduce a new constexpr flag : CEF_ACE.
Modify CEF_SET_ICE and CEF_SET_FLOAT to also include that new bit.
Thus, whenever an integer constant expression or a floating point
constant is recognized, it is automatically tagged as an arithmetic
constant expression.
Note that everything has already been set up such that the new flag
propagates nicely from subexpressions to parent expressions at evaluation.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
expression.h | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/expression.h b/expression.h
index c084783c8..67b6a83e3 100644
--- a/expression.h
+++ b/expression.h
@@ -96,16 +96,19 @@ enum constexpr_flag {
/*
* A constant expression in the sense of [6.6]:
* - integer constant expression [6.6(6)]
+ * - arithmetic constant expression [6.6(8)]
*/
CEF_ICE = (1 << 4),
+ CEF_ACE = (1 << 5),
-
- CEF_SET_ICE = (CEF_ICE),
+ /* integer constant expression => arithmetic constant expression */
+ CEF_SET_ICE = (CEF_ICE | CEF_ACE),
/* integer constant => integer constant expression */
CEF_SET_INT = (CEF_INT | CEF_SET_ICE),
- CEF_SET_FLOAT = (CEF_FLOAT),
+ /* floating point constant => arithmetic constant expression */
+ CEF_SET_FLOAT = (CEF_FLOAT | CEF_ACE),
/* enumeration constant => integer constant expression */
CEF_SET_ENUM = (CEF_ENUM | CEF_SET_ICE),
@@ -118,14 +121,13 @@ enum constexpr_flag {
* expression" [6.6] flags.
*/
CEF_CONST_MASK = (CEF_INT | CEF_FLOAT | CEF_CHAR),
-};
-/*
- * not an integer constant expression => neither of integer,
- * enumeration and character constant
- */
-#define CEF_CLR_ICE \
- (CEF_ICE | CEF_INT | CEF_ENUM | CEF_CHAR)
+ /*
+ * not an integer constant expression => neither of integer,
+ * enumeration and character constant
+ */
+ CEF_CLR_ICE = (CEF_ICE | CEF_INT | CEF_ENUM | CEF_CHAR),
+};
enum {
Taint_comma = 1,
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 08/25] constexpr: add support for tagging address constants
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (6 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 07/25] constexpr: add support for tagging arithmetic constant expressions Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 09/25] constexpr: rename handle_simple_initializer() to handle_initializer() Luc Van Oostenryck
` (17 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Address constants [6.6(9)] constitute one of the types of constant
expressions allowed in initializers [6.6(7)] for static storage
duration objects [6.7.8(4)].
Introduce a new flag for tagging expressions which qualify as
being an address constant.
Make sure not to carry over the address constant attribute from
subexpressions for operators that never yield address constants,
i.e. most arithmetic ones, logical ones etc.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 19 ++++++++++++++++++-
expression.h | 2 ++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/evaluate.c b/evaluate.c
index 6d6e462cd..68a2d5ebf 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -890,7 +890,7 @@ static struct symbol *evaluate_logical(struct expression *expr)
/* the result is int [6.5.13(3), 6.5.14(3)] */
expr->ctype = &int_ctype;
expr->flags = expr->left->flags & expr->right->flags;
- expr->flags &= ~CEF_CONST_MASK;
+ expr->flags &= ~(CEF_CONST_MASK | CEF_ADDR);
return &int_ctype;
}
@@ -1007,6 +1007,7 @@ static struct symbol *evaluate_compare(struct expression *expr)
const char *typediff;
expr->flags = left->flags & right->flags & ~CEF_CONST_MASK;
+ expr->flags &= ~CEF_ADDR;
/* Type types? */
if (is_type_type(ltype) && is_type_type(rtype))
@@ -1124,6 +1125,11 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
expr->flags = (expr->conditional->flags & (*true)->flags &
expr->cond_false->flags & ~CEF_CONST_MASK);
+ /*
+ * A conditional operator never yields an address constant
+ * [6.6(9)].
+ */
+ expr->flags &= ~CEF_ADDR;
lclass = classify_type(ltype, <ype);
rclass = classify_type(rtype, &rtype);
@@ -1858,6 +1864,12 @@ static struct symbol *evaluate_preop(struct expression *expr)
case '!':
expr->flags = expr->unop->flags & ~CEF_CONST_MASK;
+ /*
+ * A logical negation never yields an address constant
+ * [6.6(9)].
+ */
+ expr->flags &= ~CEF_ADDR;
+
if (is_safe_type(ctype))
warning(expr->pos, "testing a 'safe expression'");
if (is_float_type(ctype)) {
@@ -2719,6 +2731,11 @@ static int cast_flags(struct expression *expr, struct expression *old)
class = classify_type(expr->ctype, &t);
if (class & TYPE_NUM) {
flags = old->flags & ~CEF_CONST_MASK;
+ /*
+ * Casts to numeric types never result in address
+ * constants [6.6(9)].
+ */
+ flags &= ~CEF_ADDR;
/*
* Cast to float type -> not an integer constant
* expression [6.6(6)].
diff --git a/expression.h b/expression.h
index 67b6a83e3..960f16005 100644
--- a/expression.h
+++ b/expression.h
@@ -97,9 +97,11 @@ enum constexpr_flag {
* A constant expression in the sense of [6.6]:
* - integer constant expression [6.6(6)]
* - arithmetic constant expression [6.6(8)]
+ * - address constant [6.6(9)]
*/
CEF_ICE = (1 << 4),
CEF_ACE = (1 << 5),
+ CEF_ADDR = (1 << 6),
/* integer constant expression => arithmetic constant expression */
CEF_SET_ICE = (CEF_ICE | CEF_ACE),
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 09/25] constexpr: rename handle_simple_initializer() to handle_initializer()
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (7 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 08/25] constexpr: add support for tagging address constants Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 10/25] constexpr: collect storage modifiers of initializers Luc Van Oostenryck
` (16 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
This function, with a quite long name, not only handle
simple initializer but also complex ones.
So, rename it to the shorter and more correct form.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/evaluate.c b/evaluate.c
index 68a2d5ebf..07edda41b 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -2450,7 +2450,7 @@ static struct expression *next_designators(struct expression *old,
return new;
}
-static int handle_simple_initializer(struct expression **ep, int nested,
+static int handle_initializer(struct expression **ep, int nested,
int class, struct symbol *ctype);
/*
@@ -2515,7 +2515,7 @@ found:
else
v = &top->ident_expression;
- if (handle_simple_initializer(v, 1, lclass, top->ctype))
+ if (handle_initializer(v, 1, lclass, top->ctype))
continue;
if (!(lclass & TYPE_COMPOUND)) {
@@ -2607,7 +2607,7 @@ static struct expression *handle_scalar(struct expression *e, int nested)
* { "string", ...} - we need to preserve that string literal recognizable
* until we dig into the inner struct.
*/
-static int handle_simple_initializer(struct expression **ep, int nested,
+static int handle_initializer(struct expression **ep, int nested,
int class, struct symbol *ctype)
{
int is_string = is_string_type(ctype);
@@ -2696,7 +2696,7 @@ static void evaluate_initializer(struct symbol *ctype, struct expression **ep)
{
struct symbol *type;
int class = classify_type(ctype, &type);
- if (!handle_simple_initializer(ep, 0, class, ctype))
+ if (!handle_initializer(ep, 0, class, ctype))
expression_error(*ep, "invalid initializer");
}
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 10/25] constexpr: collect storage modifiers of initializers
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (8 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 09/25] constexpr: rename handle_simple_initializer() to handle_initializer() Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 11/25] constexpr: check static storage duration objects' intializers' constness Luc Van Oostenryck
` (15 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
This is a preparatory step for checking the constness
of initializers of static storage duration objects;
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/evaluate.c b/evaluate.c
index 07edda41b..138ee1dd6 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -2451,13 +2451,13 @@ static struct expression *next_designators(struct expression *old,
}
static int handle_initializer(struct expression **ep, int nested,
- int class, struct symbol *ctype);
+ int class, struct symbol *ctype, unsigned long mods);
/*
* deal with traversing subobjects [6.7.8(17,18,20)]
*/
static void handle_list_initializer(struct expression *expr,
- int class, struct symbol *ctype)
+ int class, struct symbol *ctype, unsigned long mods)
{
struct expression *e, *last = NULL, *top = NULL, *next;
int jumped = 0;
@@ -2515,7 +2515,8 @@ found:
else
v = &top->ident_expression;
- if (handle_initializer(v, 1, lclass, top->ctype))
+ mods |= ctype->ctype.modifiers & MOD_STORAGE;
+ if (handle_initializer(v, 1, lclass, top->ctype, mods))
continue;
if (!(lclass & TYPE_COMPOUND)) {
@@ -2608,7 +2609,7 @@ static struct expression *handle_scalar(struct expression *e, int nested)
* until we dig into the inner struct.
*/
static int handle_initializer(struct expression **ep, int nested,
- int class, struct symbol *ctype)
+ int class, struct symbol *ctype, unsigned long mods)
{
int is_string = is_string_type(ctype);
struct expression *e = *ep, *p;
@@ -2648,7 +2649,7 @@ static int handle_initializer(struct expression **ep, int nested,
goto String;
}
}
- handle_list_initializer(e, class, ctype);
+ handle_list_initializer(e, class, ctype, mods);
return 1;
}
@@ -2696,7 +2697,7 @@ static void evaluate_initializer(struct symbol *ctype, struct expression **ep)
{
struct symbol *type;
int class = classify_type(ctype, &type);
- if (!handle_initializer(ep, 0, class, ctype))
+ if (!handle_initializer(ep, 0, class, ctype, 0))
expression_error(*ep, "invalid initializer");
}
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 11/25] constexpr: check static storage duration objects' intializers' constness
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (9 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 10/25] constexpr: collect storage modifiers of initializers Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 12/25] constexpr: recognize static objects as address constants Luc Van Oostenryck
` (14 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Initializers of static storage duration objects shall be constant
expressions [6.7.8(4)].
Warn if that requirement is not met and the -Wstatic-initializer-not-const
flag has been given on sparse's command line.
Identify static storage duration objects by having either of
MOD_TOPLEVEL or MOD_STATIC set.
Check an initializer's constness at the lowest possible subobject
level, i.e. at the level of the "assignment-expression" production
in [6.7.8].
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 10 ++++++++
lib.c | 2 ++
lib.h | 1 +
sparse.1 | 9 +++++++
validation/constexpr-init.c | 60 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 82 insertions(+)
create mode 100644 validation/constexpr-init.c
diff --git a/evaluate.c b/evaluate.c
index 138ee1dd6..726ec15d3 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -2627,6 +2627,16 @@ static int handle_initializer(struct expression **ep, int nested,
if (!evaluate_expression(e))
return 1;
compatible_assignment_types(e, ctype, ep, "initializer");
+ /*
+ * Initializers for static storage duration objects
+ * shall be constant expressions or a string literal [6.7.8(4)].
+ */
+ mods |= ctype->ctype.modifiers;
+ mods &= (MOD_TOPLEVEL | MOD_STATIC);
+ if (mods && !(e->flags & (CEF_ACE | CEF_ADDR)))
+ if (Wconstexpr_not_const)
+ warning(e->pos, "non-constant initializer for static object");
+
return 1;
}
diff --git a/lib.c b/lib.c
index cf6bea645..04b270dcb 100644
--- a/lib.c
+++ b/lib.c
@@ -219,6 +219,7 @@ int Waddress_space = 1;
int Wbitwise = 1;
int Wcast_to_as = 0;
int Wcast_truncate = 1;
+int Wconstexpr_not_const = 0;
int Wcontext = 1;
int Wdecl = 1;
int Wdeclarationafterstatement = -1;
@@ -471,6 +472,7 @@ static const struct warning {
{ "bitwise", &Wbitwise },
{ "cast-to-as", &Wcast_to_as },
{ "cast-truncate", &Wcast_truncate },
+ { "constexpr-not-const", &Wconstexpr_not_const},
{ "context", &Wcontext },
{ "decl", &Wdecl },
{ "declaration-after-statement", &Wdeclarationafterstatement },
diff --git a/lib.h b/lib.h
index 134e56040..003016ce2 100644
--- a/lib.h
+++ b/lib.h
@@ -105,6 +105,7 @@ extern int Waddress_space;
extern int Wbitwise;
extern int Wcast_to_as;
extern int Wcast_truncate;
+extern int Wconstexpr_not_const;
extern int Wcontext;
extern int Wdecl;
extern int Wdeclarationafterstatement;
diff --git a/sparse.1 b/sparse.1
index 85d6e646b..721b5cfc7 100644
--- a/sparse.1
+++ b/sparse.1
@@ -86,6 +86,15 @@ Sparse issues these warnings by default. To turn them off, use
\fB\-Wno\-cast\-truncate\fR.
.
.TP
+.B \-Wconstexpr-not-const
+Warn if a non-constant expression is encountered when really expecting a
+constant expression instead.
+Currently, this warns when initializing an object of static storage duration
+with an initializer which is not a constant expression.
+
+Sparse does not issue these warnings by default.
+.
+.TP
.B \-Wcontext
Warn about potential errors in synchronization or other delimited contexts.
diff --git a/validation/constexpr-init.c b/validation/constexpr-init.c
new file mode 100644
index 000000000..d7e7a450f
--- /dev/null
+++ b/validation/constexpr-init.c
@@ -0,0 +1,60 @@
+static int a = 1; // OK
+static int b[2] = {1, 1}; // OK
+static void c(void) {}
+
+struct A {
+ int a;
+ int b[2];
+};
+
+struct B {
+ int c;
+ struct A d;
+};
+
+static struct B d= {1, {1, {1, 1}}}; // OK
+static struct B e= {a, {1, {1, 1}}}; // KO
+static struct B f= {1, {a, {1, 1}}}; // KO
+static struct B g= {1, {1, {a, 1}}}; // KO
+static struct B h= {1, {1, {1, a}}}; // KO
+static struct B i= {.c = 1, .d = {.a = 1, .b = {1, 1}}}; // OK
+static struct B j= {.c = a, .d = {.a = 1, .b = {1, 1}}}; // KO
+static struct B k= {.c = 1, .d = {.a = a, .b = {1, 1}}}; // KO
+static struct B l= {.c = 1, .d = {.a = 1, .b = {a, 1}}}; // KO
+static struct B m= {.c = 1, .d = {.a = 1, .b = {1, a}}}; // KO
+
+static int n[] = {a, 1}; // KO
+static int o[] = {1, a}; // KO
+static int p[] = {[0] = a, [1] = 1}; // KO
+static int q[] = {[0] = 1, [1] = a}; // KO
+
+static void r(void) {
+ int a = 0;
+ int b = a; // OK
+}
+
+static void s(void) {
+ int a = 1;
+ static int b = a; // KO
+}
+
+/*
+ * check-name: static storage object initializer constness verification.
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-init.c:16:21: warning: non-constant initializer for static object
+constexpr-init.c:17:25: warning: non-constant initializer for static object
+constexpr-init.c:18:29: warning: non-constant initializer for static object
+constexpr-init.c:19:32: warning: non-constant initializer for static object
+constexpr-init.c:21:26: warning: non-constant initializer for static object
+constexpr-init.c:22:40: warning: non-constant initializer for static object
+constexpr-init.c:23:49: warning: non-constant initializer for static object
+constexpr-init.c:24:52: warning: non-constant initializer for static object
+constexpr-init.c:26:19: warning: non-constant initializer for static object
+constexpr-init.c:27:22: warning: non-constant initializer for static object
+constexpr-init.c:28:25: warning: non-constant initializer for static object
+constexpr-init.c:29:34: warning: non-constant initializer for static object
+constexpr-init.c:38:24: warning: non-constant initializer for static object
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 12/25] constexpr: recognize static objects as address constants
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (10 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 11/25] constexpr: check static storage duration objects' intializers' constness Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 13/25] constexpr: recognize address constants created through casts Luc Van Oostenryck
` (13 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Introduce support for recognizing address constants created either
- explicitly by referencing a static storage duration object by means
of the unary & operator,
- implicitly by the use of an expression of array or function type.
Initially tag an expression as being an address constant at the primary
expression level, i.e. upon encountering a symbol designating an object of
static storage duration in primary_expression().
Carry the address constant flag over to the *-preop wrapped expression
created by evaluate_symbol_expression().
When dereferencing such a *-preop wrapped expression, make
evaluate_addressof() keep any address constant flag for the unwrapped
expression.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 3 ++-
expression.c | 8 ++++++++
validation/constexpr-addr-of-static.c | 36 +++++++++++++++++++++++++++++++++++
3 files changed, 46 insertions(+), 1 deletion(-)
create mode 100644 validation/constexpr-addr-of-static.c
diff --git a/evaluate.c b/evaluate.c
index 726ec15d3..c111f6d19 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -70,9 +70,11 @@ static struct symbol *evaluate_symbol_expression(struct expression *expr)
addr->symbol = sym;
addr->symbol_name = expr->symbol_name;
addr->ctype = &lazy_ptr_ctype; /* Lazy evaluation: we need to do a proper job if somebody does &sym */
+ addr->flags = expr->flags;
expr->type = EXPR_PREOP;
expr->op = '*';
expr->unop = addr;
+ expr->flags = CEF_NONE;
/* The type of a symbol is the symbol itself! */
expr->ctype = sym;
@@ -1689,7 +1691,6 @@ static struct symbol *evaluate_addressof(struct expression *expr)
}
ctype = op->ctype;
*expr = *op->unop;
- expr->flags = CEF_NONE;
if (expr->type == EXPR_SYMBOL) {
struct symbol *sym = expr->symbol;
diff --git a/expression.c b/expression.c
index 7f1eff306..00edd1f99 100644
--- a/expression.c
+++ b/expression.c
@@ -435,6 +435,14 @@ struct token *primary_expression(struct token *token, struct expression **tree)
}
expr->symbol_name = token->ident;
expr->symbol = sym;
+
+ /*
+ * A pointer to an lvalue designating a static storage
+ * duration object is an address constant [6.6(9)].
+ */
+ if (sym && (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC)))
+ expr->flags = CEF_ADDR;
+
token = next;
break;
}
diff --git a/validation/constexpr-addr-of-static.c b/validation/constexpr-addr-of-static.c
new file mode 100644
index 000000000..a3af99ae7
--- /dev/null
+++ b/validation/constexpr-addr-of-static.c
@@ -0,0 +1,36 @@
+static int a = 1;
+static int b[2] = {1, 1};
+static void c(void) {}
+
+static int *d = &a; // OK
+static int *e = d; // KO
+static int *f = b; // OK
+
+static void (*g)(void) = c; // OK
+static void (*h)(void) = &c; // OK
+
+static int *i = &*&a; // OK
+static int *j = &*b; // OK
+static int *k = &*d; // KO
+
+
+static void l(void) {
+ int a = 1;
+ static int *b = &a; // KO
+}
+
+static void m(void) {
+ static int a = 1;
+ static int *b = &a; // OK
+}
+
+/*
+ * check-name: address of static object constness verification.
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-addr-of-static.c:6:17: warning: non-constant initializer for static object
+constexpr-addr-of-static.c:14:19: warning: non-constant initializer for static object
+constexpr-addr-of-static.c:19:26: warning: non-constant initializer for static object
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 13/25] constexpr: recognize address constants created through casts
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (11 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 12/25] constexpr: recognize static objects as address constants Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 14/25] constexpr: recognize address constants created through pointer arithmetic Luc Van Oostenryck
` (12 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
According to 6.6(9), an address constant may get created by casting
an integer constant to pointer type.
Make evaluate_cast() handle this case, that is tag a cast expression
as being an address constant if the target is a integer constant and
the destination is of pointer type.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 7 +++++++
validation/constexpr-pointer-cast.c | 13 +++++++++++++
2 files changed, 20 insertions(+)
create mode 100644 validation/constexpr-pointer-cast.c
diff --git a/evaluate.c b/evaluate.c
index c111f6d19..ce2e52e15 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -2760,6 +2760,13 @@ static int cast_flags(struct expression *expr, struct expression *old)
*/
else if (old->flags & CEF_FLOAT)
flags = CEF_SET_ICE;
+ } else if (class & TYPE_PTR) {
+ /*
+ * Casts of integer literals to pointer type yield
+ * address constants [6.6(9)].
+ */
+ if (old->flags & CEF_INT)
+ flags = CEF_ADDR;
}
return flags;
diff --git a/validation/constexpr-pointer-cast.c b/validation/constexpr-pointer-cast.c
new file mode 100644
index 000000000..d19c10828
--- /dev/null
+++ b/validation/constexpr-pointer-cast.c
@@ -0,0 +1,13 @@
+static int *a = (int*)0; // OK
+static int b = 0;
+static int *c = (int*)b; // KO
+
+
+/*
+ * check-name: integer literal cast to pointer type constness verification.
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-pointer-cast.c:3:18: warning: non-constant initializer for static object
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 14/25] constexpr: recognize address constants created through pointer arithmetic
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (12 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 13/25] constexpr: recognize address constants created through casts Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 15/25] constexpr: recognize members of static compound objects as address constants Luc Van Oostenryck
` (11 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
An address constant +/- an integer constant expression qualifies as an
address constant again.
Furthermore, the array-subscript operator "[]" may be used in the creation
of address constant.
Handle both cases by making evaluate_ptr_add() check whether an integer
constant expression is added to an address constant and tag the result as
being an address constant again if so.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 7 +++++++
validation/constexpr-pointer-arith.c | 28 ++++++++++++++++++++++++++++
2 files changed, 35 insertions(+)
create mode 100644 validation/constexpr-pointer-arith.c
diff --git a/evaluate.c b/evaluate.c
index ce2e52e15..e58d9c373 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -571,6 +571,13 @@ static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *i
classify_type(degenerate(expr->left), &ctype);
base = examine_pointer_target(ctype);
+ /*
+ * An address constant +/- an integer constant expression
+ * yields an address constant again [6.6(7)].
+ */
+ if ((expr->left->flags & CEF_ADDR) && (expr->right->flags & CEF_ICE))
+ expr->flags = CEF_ADDR;
+
if (!base) {
expression_error(expr, "missing type information");
return NULL;
diff --git a/validation/constexpr-pointer-arith.c b/validation/constexpr-pointer-arith.c
new file mode 100644
index 000000000..a92202800
--- /dev/null
+++ b/validation/constexpr-pointer-arith.c
@@ -0,0 +1,28 @@
+static int a = 1;
+static int b[2] = {1, 1};
+
+static int *c = &b[1]; // OK
+static int *d = (int*)0 + 1; // OK
+static int *e = &b[1] + 1; // OK
+static int *f = b + 1; // OK
+static int *g = d + 1; // KO
+static int *h = &a + 1; // OK
+static int *i = &b[1] + 1; // OK
+static int *j = b + 1; // OK
+static int *k = d + 1; // KO
+static int *l = &*&b[1]; // OK
+static int *m = &*(&a + 1); // OK
+static int *n = &*(&b[1] + 1); // OK
+static int *o = &*(b + 1); // OK
+static int *p = &*(d + 1); // KO
+
+/*
+ * check-name: pointer arithmetic constness verification.
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-pointer-arith.c:8:19: warning: non-constant initializer for static object
+constexpr-pointer-arith.c:12:19: warning: non-constant initializer for static object
+constexpr-pointer-arith.c:17:22: warning: non-constant initializer for static object
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 15/25] constexpr: recognize members of static compound objects as address constants
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (13 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 14/25] constexpr: recognize address constants created through pointer arithmetic Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 16/25] constexpr: recognize string literals " Luc Van Oostenryck
` (10 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
According to 6.6(9), the member access operators "." and "->" may be used
in the creation of address constants.
Uses of both operators amount to the creation of EXPR_DEREF expressions
which are eventually fed into evaluate_offset() at evaluation.
Make evaluate_offset() propagate any address constant flag of the object
containing the referenced member to the newly created pointer addition
expression.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 6 ++++++
validation/constexpr-addr-of-static-member.c | 26 ++++++++++++++++++++++++++
2 files changed, 32 insertions(+)
create mode 100644 validation/constexpr-addr-of-static-member.c
diff --git a/evaluate.c b/evaluate.c
index e58d9c373..9a7d432b8 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1962,6 +1962,12 @@ static struct expression *evaluate_offset(struct expression *expr, unsigned long
* we ever take the address of this member dereference..
*/
add->ctype = &lazy_ptr_ctype;
+ /*
+ * The resulting address of a member access through an address
+ * constant is an address constant again [6.6(9)].
+ */
+ add->flags = expr->flags;
+
return add;
}
diff --git a/validation/constexpr-addr-of-static-member.c b/validation/constexpr-addr-of-static-member.c
new file mode 100644
index 000000000..f944f213e
--- /dev/null
+++ b/validation/constexpr-addr-of-static-member.c
@@ -0,0 +1,26 @@
+struct A {
+ int a;
+ int b[2];
+};
+
+struct B {
+ int c;
+ struct A d;
+};
+
+static struct B a= {1, {1, {1, 1}}};
+
+static int *b = &a.d.a; // OK
+static int *c = &(&a.d)->a; // OK
+static int *d = a.d.b; // OK
+static int *e = (&a.d)->b; // OK
+static int *f = &a.d.b[1]; // OK
+static int *g = &(&a.d)->b[1]; // OK
+
+/*
+ * check-name: address of static object's member constness verification.
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 16/25] constexpr: recognize string literals as address constants
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (14 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 15/25] constexpr: recognize members of static compound objects as address constants Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 17/25] constexpr: recognize references to labels " Luc Van Oostenryck
` (9 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Introduce support for recognizing string literals as address constants.
Make evaluate_string() unconditionally tag the *-preop wrapped symbol
expression as being an address constant.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 1 +
validation/constexpr-string.c | 9 +++++++++
2 files changed, 10 insertions(+)
create mode 100644 validation/constexpr-string.c
diff --git a/evaluate.c b/evaluate.c
index 9a7d432b8..cdbc08ef2 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -108,6 +108,7 @@ static struct symbol *evaluate_string(struct expression *expr)
addr->symbol = sym;
addr->ctype = &lazy_ptr_ctype;
+ addr->flags = CEF_ADDR;
expr->type = EXPR_PREOP;
expr->op = '*';
diff --git a/validation/constexpr-string.c b/validation/constexpr-string.c
new file mode 100644
index 000000000..e641a83eb
--- /dev/null
+++ b/validation/constexpr-string.c
@@ -0,0 +1,9 @@
+static char *a = "foobar"; // OK
+
+/*
+ * check-name: string literal constness verification.
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 17/25] constexpr: recognize references to labels as address constants
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (15 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 16/25] constexpr: recognize string literals " Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 18/25] constexpr: examine constness of __builtin_offsetof at evaluation only Luc Van Oostenryck
` (8 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
As an extension, GCC allows labels to be referenced a la
label1:
...
void *ptr = &&label1;
Tag these label references as being address constants allowing them
to be used as initializers for objects of static storage duration.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
expression.c | 1 +
validation/constexpr-labelref.c | 14 ++++++++++++++
2 files changed, 15 insertions(+)
create mode 100644 validation/constexpr-labelref.c
diff --git a/expression.c b/expression.c
index 00edd1f99..241ab7bad 100644
--- a/expression.c
+++ b/expression.c
@@ -681,6 +681,7 @@ static struct token *unary_expression(struct token *token, struct expression **t
sym->ctype.modifiers |= MOD_ADDRESSABLE;
add_symbol(&function_computed_target_list, sym);
}
+ label->flags = CEF_ADDR;
label->label_symbol = sym;
*tree = label;
return token->next->next;
diff --git a/validation/constexpr-labelref.c b/validation/constexpr-labelref.c
new file mode 100644
index 000000000..15b5293ae
--- /dev/null
+++ b/validation/constexpr-labelref.c
@@ -0,0 +1,14 @@
+static void a(void)
+{
+label1:
+ ;
+ static void *b = &&label1;
+}
+
+/*
+ * check-name: label reference constness verification.
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 18/25] constexpr: examine constness of __builtin_offsetof at evaluation only
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (16 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 17/25] constexpr: recognize references to labels " Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 19/25] constexpr: flag builtins constant_p, safe_p and warning as constexprs Luc Van Oostenryck
` (7 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Currently, the determination of a __builtin_offsetof() expressions'
constness flags is done in two steps:
- Several flags are speculatively set at expression parsing time
- and possibly cleared again at evaluation if the member expression
includes a non-const array index like in
__builtin_offsetof(struct A, a.b[non_const_foo])
For consistency with other expression types' evaluation, defer the
determination of a __builtin_offsetof() expression's constness to
evaluation time, too.
Furthermore, carry an array index expression's constness flags
through the implicit cast to size_t type.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 8 ++++++--
expression.c | 3 ---
validation/constexpr-offsetof.c | 21 +++++++++++++++++++++
3 files changed, 27 insertions(+), 5 deletions(-)
create mode 100644 validation/constexpr-offsetof.c
diff --git a/evaluate.c b/evaluate.c
index cdbc08ef2..be72b22b9 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -3056,23 +3056,27 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
} else {
struct expression *idx = expr->index, *m;
struct symbol *i_type = evaluate_expression(idx);
+ unsigned old_idx_flags;
int i_class = classify_type(i_type, &i_type);
+
if (!is_int(i_class)) {
expression_error(expr, "non-integer index");
return NULL;
}
unrestrict(idx, i_class, &i_type);
+ old_idx_flags = idx->flags;
idx = cast_to(idx, size_t_ctype);
+ idx->flags = old_idx_flags;
m = alloc_const_expression(expr->pos,
bits_to_bytes(ctype->bit_size));
m->ctype = size_t_ctype;
- m->flags |= CEF_SET_ICE;
+ m->flags = CEF_SET_INT;
expr->type = EXPR_BINOP;
expr->left = idx;
expr->right = m;
expr->op = '*';
expr->ctype = size_t_ctype;
- expr->flags = m->flags & idx->flags;
+ expr->flags = m->flags & idx->flags & ~CEF_CONST_MASK;
}
}
if (e) {
diff --git a/expression.c b/expression.c
index 241ab7bad..3f1ea2141 100644
--- a/expression.c
+++ b/expression.c
@@ -199,7 +199,6 @@ static struct token *builtin_offsetof_expr(struct token *token,
return expect(token, ')', "at end of __builtin_offset");
case SPECIAL_DEREFERENCE:
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = CEF_SET_ICE;
e->op = '[';
*p = e;
p = &e->down;
@@ -207,7 +206,6 @@ static struct token *builtin_offsetof_expr(struct token *token,
case '.':
token = token->next;
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = CEF_SET_ICE;
e->op = '.';
if (token_type(token) != TOKEN_IDENT) {
sparse_error(token->pos, "Expected member name");
@@ -219,7 +217,6 @@ static struct token *builtin_offsetof_expr(struct token *token,
case '[':
token = token->next;
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = CEF_SET_ICE;
e->op = '[';
token = parse_expression(token, &e->index);
token = expect(token, ']',
diff --git a/validation/constexpr-offsetof.c b/validation/constexpr-offsetof.c
new file mode 100644
index 000000000..d1697b0c5
--- /dev/null
+++ b/validation/constexpr-offsetof.c
@@ -0,0 +1,21 @@
+struct A {
+ int a[1];
+ int b;
+};
+
+extern int c;
+
+static int o[] = {
+ [__builtin_offsetof(struct A, b)] = 0, // OK
+ [__builtin_offsetof(struct A, a[0])] = 0, // OK
+ [__builtin_offsetof(struct A, a[0*0])] = 0, // OK
+ [__builtin_offsetof(struct A, a[c])] = 0 // KO
+};
+
+/*
+ * check-name: __builtin_offsetof() constness verification.
+ *
+ * check-error-start
+constexpr-offsetof.c:12:39: error: bad constant expression
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 19/25] constexpr: flag builtins constant_p, safe_p and warning as constexprs
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (17 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 18/25] constexpr: examine constness of __builtin_offsetof at evaluation only Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 20/25] constexpr: relax some constant expression rules for pointer expressions Luc Van Oostenryck
` (6 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Unconditionally flag the expressions
__builtin_constant_p(),
__builtin_safe_p(),
__builtin_warning()
as being integer constant expressions.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
builtin.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/builtin.c b/builtin.c
index dbb81032b..a427b45ee 100644
--- a/builtin.c
+++ b/builtin.c
@@ -27,9 +27,10 @@
#include "expand.h"
#include "symbol.h"
-static int evaluate_to_integer(struct expression *expr)
+static int evaluate_to_int_const_expr(struct expression *expr)
{
expr->ctype = &int_ctype;
+ expr->flags |= CEF_SET_ICE;
return 1;
}
@@ -152,17 +153,17 @@ static int expand_safe_p(struct expression *expr, int cost)
}
static struct symbol_op constant_p_op = {
- .evaluate = evaluate_to_integer,
+ .evaluate = evaluate_to_int_const_expr,
.expand = expand_constant_p
};
static struct symbol_op safe_p_op = {
- .evaluate = evaluate_to_integer,
+ .evaluate = evaluate_to_int_const_expr,
.expand = expand_safe_p
};
static struct symbol_op warning_op = {
- .evaluate = evaluate_to_integer,
+ .evaluate = evaluate_to_int_const_expr,
.expand = expand_warning
};
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 20/25] constexpr: relax some constant expression rules for pointer expressions
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (18 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 19/25] constexpr: flag builtins constant_p, safe_p and warning as constexprs Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 21/25] constexpr: support compound literals as address constants Luc Van Oostenryck
` (5 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
The official constraints on constant expressions [6.6] are insanely
strict in that they do not allow some constructs commonly used in the
wild.
Relax them by treating
- address constants cast to different pointer type as address constants
again,
- address constants cast to arithmetic type as arithmetic constant
expressions
- conditional expressions whose true and false branches both yield
address constants as address constants,
- and conditional expressions whose condition is an address constant
as an constant expression to the extent their true and false branches
allow.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/evaluate.c b/evaluate.c
index be72b22b9..022c7b5f3 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1136,10 +1136,20 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
expr->flags = (expr->conditional->flags & (*true)->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.
*/
- expr->flags &= ~CEF_ADDR;
+ if (expr->conditional->flags & (CEF_ACE | CEF_ADDR))
+ expr->flags = (*true)->flags & expr->cond_false->flags & ~CEF_CONST_MASK;
lclass = classify_type(ltype, <ype);
rclass = classify_type(rtype, &rtype);
@@ -2762,6 +2772,14 @@ static int cast_flags(struct expression *expr, struct expression *old)
* constants [6.6(9)].
*/
flags &= ~CEF_ADDR;
+
+ /*
+ * As an extension, treat address constants cast to
+ * integer type as an arithmetic constant.
+ */
+ if (old->flags & CEF_ADDR)
+ flags = CEF_ACE;
+
/*
* Cast to float type -> not an integer constant
* expression [6.6(6)].
@@ -2778,8 +2796,15 @@ static int cast_flags(struct expression *expr, struct expression *old)
/*
* Casts of integer literals to pointer type yield
* address constants [6.6(9)].
+ *
+ * As an extension, treat address constants cast to a
+ * different pointer type as address constants again.
+ *
+ * As another extension, treat integer constant
+ * expressions (in contrast to literals) cast to
+ * pointer type as address constants.
*/
- if (old->flags & CEF_INT)
+ if (old->flags & (CEF_ICE | CEF_ADDR))
flags = CEF_ADDR;
}
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 21/25] constexpr: support compound literals as address constants
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (19 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 20/25] constexpr: relax some constant expression rules for pointer expressions Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 22/25] constexpr: treat comparisons between types as integer constexpr Luc Van Oostenryck
` (4 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
Toplevel compound literals have got static storage duration
[6.5.2.5(6)].
This implies that
1. their addresses are address constants [6.6(9)] and
2. their initializers must contain constant expressions only
[6.5.2.5(3), 6.7.8(4)] .
Flag the anonymous symbol created at expression parsing time as having
static storage duration if the compound literal occurs at top level
scope.
Flag the whole expression as being an address constant at evaluation
time if its corresponding anonymous symbol had been previously marked
as having static storage duration.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 2 ++
expression.c | 2 ++
validation/constexpr-compound-literal.c | 19 +++++++++++++++++++
3 files changed, 23 insertions(+)
create mode 100644 validation/constexpr-compound-literal.c
diff --git a/evaluate.c b/evaluate.c
index 022c7b5f3..1ae370c7b 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -2841,6 +2841,8 @@ static struct symbol *evaluate_cast(struct expression *expr)
addr->ctype = &lazy_ptr_ctype; /* Lazy eval */
addr->symbol = sym;
+ if (sym->ctype.modifiers & MOD_TOPLEVEL)
+ addr->flags |= CEF_ADDR;
expr->type = EXPR_PREOP;
expr->op = '*';
diff --git a/expression.c b/expression.c
index 3f1ea2141..e4b770fc0 100644
--- a/expression.c
+++ b/expression.c
@@ -711,6 +711,8 @@ static struct token *cast_expression(struct token *token, struct expression **tr
cast->cast_type = sym;
token = expect(token, ')', "at end of cast operator");
if (match_op(token, '{')) {
+ if (toplevel(block_scope))
+ sym->ctype.modifiers |= MOD_TOPLEVEL;
if (is_force)
warning(sym->pos,
"[force] in compound literal");
diff --git a/validation/constexpr-compound-literal.c b/validation/constexpr-compound-literal.c
new file mode 100644
index 000000000..d7f21ad7a
--- /dev/null
+++ b/validation/constexpr-compound-literal.c
@@ -0,0 +1,19 @@
+static int *a = &(int){ 1 }; // OK
+static int *b = &(int){ *a }; // KO
+
+static void foo(void)
+{
+ int *b = &(int){ 1 }; // OK
+ int *c = &(int){ *a }; // OK
+ static int *d = &(int){ 1 }; // KO
+}
+
+/*
+ * check-name: compound literal address constness verification
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-compound-literal.c:2:25: warning: non-constant initializer for static object
+constexpr-compound-literal.c:8:27: warning: non-constant initializer for static object
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 22/25] constexpr: treat comparisons between types as integer constexpr
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (20 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 21/25] constexpr: support compound literals as address constants Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 23/25] return an error if too few args Luc Van Oostenryck
` (3 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
From: Nicolai Stange <nicstange@gmail.com>
The expression parsing code builds an EXPR_COMPARE expression around two
EXPR_TYPE expressions for __builtin_types_compatible_p().
The EXPR_TYPE expressions are tagged as being integer constant expressions
in order to trick the generic comparison evaluation code into flagging the
result as an integer constant expression again.
Avoid this trickery by making evaluate_compare() unconditionally tag a
comparison between types as an integer constant expression.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 13 +++++++++----
expression.c | 3 ---
validation/constexpr-types-compatible-p.c | 8 ++++++++
3 files changed, 17 insertions(+), 7 deletions(-)
create mode 100644 validation/constexpr-types-compatible-p.c
diff --git a/evaluate.c b/evaluate.c
index 1ae370c7b..46ea10ed8 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1016,16 +1016,21 @@ static struct symbol *evaluate_compare(struct expression *expr)
struct symbol *ctype;
const char *typediff;
- expr->flags = left->flags & right->flags & ~CEF_CONST_MASK;
- expr->flags &= ~CEF_ADDR;
-
/* Type types? */
- if (is_type_type(ltype) && is_type_type(rtype))
+ if (is_type_type(ltype) && is_type_type(rtype)) {
+ /*
+ * __builtin_types_compatible_p() yields an integer
+ * constant expression
+ */
+ expr->flags = CEF_SET_ICE;
goto OK;
+ }
if (is_safe_type(left->ctype) || is_safe_type(right->ctype))
warning(expr->pos, "testing a 'safe expression'");
+ expr->flags = left->flags & right->flags & ~CEF_CONST_MASK & ~CEF_ADDR;
+
/* number on number */
if (lclass & rclass & TYPE_NUM) {
ctype = usual_conversions(expr->op, expr->left, expr->right,
diff --git a/expression.c b/expression.c
index e4b770fc0..e5ebad65b 100644
--- a/expression.c
+++ b/expression.c
@@ -131,7 +131,6 @@ static struct token *parse_type(struct token *token, struct expression **tree)
{
struct symbol *sym;
*tree = alloc_expression(token->pos, EXPR_TYPE);
- (*tree)->flags = CEF_SET_ICE; /* sic */
token = typename(token, &sym, NULL);
if (sym->ident)
sparse_error(token->pos,
@@ -459,8 +458,6 @@ struct token *primary_expression(struct token *token, struct expression **tree)
}
if (token->special == '[' && lookup_type(token->next)) {
expr = alloc_expression(token->pos, EXPR_TYPE);
- /* sic */
- expr->flags = CEF_SET_ICE;
token = typename(token->next, &expr->symbol, NULL);
token = expect(token, ']', "in type expression");
break;
diff --git a/validation/constexpr-types-compatible-p.c b/validation/constexpr-types-compatible-p.c
new file mode 100644
index 000000000..1969bf3bd
--- /dev/null
+++ b/validation/constexpr-types-compatible-p.c
@@ -0,0 +1,8 @@
+static int a[] = {[__builtin_types_compatible_p(int, int)] = 0};
+
+/*
+ * check-name: __builtin_types_compatible_p() constness verification.
+ *
+ * check-error-start
+ * check-error-end
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 23/25] return an error if too few args
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (21 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 22/25] constexpr: treat comparisons between types as integer constexpr Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 24/25] give default return type in evaluate_call() Luc Van Oostenryck
` (2 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
In evaluate_call(), argumenst are evaluated an a diagnostic
is emitted if the number of args is not what is expected.
Good.
However, the processing continues nevertheless.
If too much args were given, this doesn't matter much
but if too few are given we need to check a bit everywhere
for possible NULL args.
Avoid this by returning early an error if there was too few
arguments.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/evaluate.c b/evaluate.c
index 46ea10ed8..0cec215ba 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -3019,10 +3019,12 @@ static struct symbol *evaluate_call(struct expression *expr)
return NULL;
args = expression_list_size(expr->args);
fnargs = symbol_list_size(ctype->arguments);
- if (args < fnargs)
+ if (args < fnargs) {
expression_error(expr,
"not enough arguments for function %s",
show_ident(sym->ident));
+ return NULL;
+ }
if (args > fnargs && !ctype->variadic)
expression_error(expr,
"too many arguments for function %s",
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 24/25] give default return type in evaluate_call()
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (22 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 23/25] return an error if too few args Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 25/25] constexpr: flag __builtin_bswap() as constexpr Luc Van Oostenryck
2017-08-10 12:36 ` [PATCH v4 00/25] improve constexpr handling Christopher Li
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
evaluate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/evaluate.c b/evaluate.c
index 0cec215ba..df6fd5adc 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -3030,11 +3030,11 @@ static struct symbol *evaluate_call(struct expression *expr)
"too many arguments for function %s",
show_ident(sym->ident));
}
+ expr->ctype = ctype->ctype.base_type;
if (sym->type == SYM_NODE) {
if (evaluate_symbol_call(expr))
return expr->ctype;
}
- expr->ctype = ctype->ctype.base_type;
return expr->ctype;
}
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 25/25] constexpr: flag __builtin_bswap() as constexpr
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (23 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 24/25] give default return type in evaluate_call() Luc Van Oostenryck
@ 2017-03-31 1:44 ` Luc Van Oostenryck
2017-08-10 12:36 ` [PATCH v4 00/25] improve constexpr handling Christopher Li
25 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-03-31 1:44 UTC (permalink / raw)
To: linux-sparse; +Cc: Christopher Li, Nicolai Stange, Luc Van Oostenryck
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
builtin.c | 17 +++++++++++++++++
validation/constexpr-pure-builtin.c | 23 +++++++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 validation/constexpr-pure-builtin.c
diff --git a/builtin.c b/builtin.c
index a427b45ee..139448988 100644
--- a/builtin.c
+++ b/builtin.c
@@ -34,6 +34,22 @@ static int evaluate_to_int_const_expr(struct expression *expr)
return 1;
}
+static int evaluate_pure_unop(struct expression *expr)
+{
+ struct expression *arg = first_expression(expr->args);
+ int flags = arg->flags;
+
+ /*
+ * Allow such functions with a constant integer expression
+ * argument to be treated as a *constant* integer.
+ * This allow us to use them in switch() { case ...:
+ */
+ flags |= (flags & CEF_ICE) ? CEF_SET_INT : 0;
+ expr->flags = flags;
+ return 1;
+}
+
+
static int evaluate_expect(struct expression *expr)
{
/* Should we evaluate it to return the type of the first argument? */
@@ -201,6 +217,7 @@ static int expand_bswap(struct expression *expr, int cost)
}
static struct symbol_op bswap_op = {
+ .evaluate = evaluate_pure_unop,
.expand = expand_bswap,
};
diff --git a/validation/constexpr-pure-builtin.c b/validation/constexpr-pure-builtin.c
new file mode 100644
index 000000000..f4cd67eda
--- /dev/null
+++ b/validation/constexpr-pure-builtin.c
@@ -0,0 +1,23 @@
+// requires constant integer expressions
+static int bar[] = {
+ [__builtin_bswap16(0x1234)] = 0, // OK
+ [__builtin_bswap32(0x1234)] = 0, // OK
+ [__builtin_bswap64(0x1234)] = 0, // OK
+};
+
+// requires constant integers
+static int foo(unsigned long long a)
+{
+ switch (a) {
+ case __builtin_bswap16(1 << 8):
+ case __builtin_bswap32(2L << 24):
+ case __builtin_bswap64(3LL << 56):
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+/*
+ * check-name: constness of pure/const builtins
+ */
--
2.12.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v4 00/25] improve constexpr handling
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
` (24 preceding siblings ...)
2017-03-31 1:44 ` [PATCH v4 25/25] constexpr: flag __builtin_bswap() as constexpr Luc Van Oostenryck
@ 2017-08-10 12:36 ` Christopher Li
2017-08-10 22:00 ` Luc Van Oostenryck
25 siblings, 1 reply; 30+ messages in thread
From: Christopher Li @ 2017-08-10 12:36 UTC (permalink / raw)
To: Luc Van Oostenryck; +Cc: Linux-Sparse, Nicolai Stange
On Thu, Mar 30, 2017 at 9:44 PM, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
> Here is a respin of the series originally made and
> submitted by Nicolai Stange.
>
> The goal of this series is to improve the tracking of
> expression constness in the sense of C99 [6.4.4, 6.6]:
> more fine-grained and more correct. A new flag is added
> for a strict mode while by default offering the relaxed
> mode we're used to, for example for kernel compile.
Sorry for the late replay. As I express before, this integer context
will not be part of this release 0.5.1.
Now the RC5 is almost out of the door. I can catch up a bit of
back log I have.
One suggest on the V4 is that, (suggestion, not reason to object
the inclusion of this series. If you prefer, I can merge them as it is
and change them later.)
I would like the manipulate of the bits representation abstract as
higher level function or macros. I have suspicious that bits
representation can be simplify in the future. Wrap them into
higher level function at the call site will be easier to read what
is the intend for this operation.
It also make the change of the underlying bit representation easier,
that is if we do found a simpler representation.
Thanks
Chris
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 00/25] improve constexpr handling
2017-08-10 12:36 ` [PATCH v4 00/25] improve constexpr handling Christopher Li
@ 2017-08-10 22:00 ` Luc Van Oostenryck
2017-08-11 1:24 ` Christopher Li
0 siblings, 1 reply; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-08-10 22:00 UTC (permalink / raw)
To: Christopher Li; +Cc: Linux-Sparse, Nicolai Stange
On Thu, Aug 10, 2017 at 2:36 PM, Christopher Li <sparse@chrisli.org> wrote:
> I would like the manipulate of the bits representation abstract as
> higher level function or macros. I have suspicious that bits
> representation can be simplify in the future. Wrap them into
> higher level function at the call site will be easier to read what
> is the intend for this operation.
>
> It also make the change of the underlying bit representation easier,
> that is if we do found a simpler representation.
It's many months ago so I may not remember the details correctly but ...
The initial version Nicolai posted (or maybe it was the second) *had*
function to abstract the operations and it was, IMO, really not very readable
and I asked him to change to something simpler like simply using
X |= M or X &= ~M when possible.
It's what he did and it was, IMO, much more readable.
Meanwhile, I also tried on my side to have some nice & cleaner bit
representation. It looked promising at first but was deceiving at the end.
So, I think that this series is much more valuable upstreamed than waiting
for some hypothetical super clean abstract layer for those few bits.
Of course, if you have some concrete set of patches making this better,
I would be glad to take a look at it and change my mind.
Otherwise, please consider it for upstreaming directly after the release
and improving the bit representation and the abstraction layer can always
be done later too.
-- Luc
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 00/25] improve constexpr handling
2017-08-10 22:00 ` Luc Van Oostenryck
@ 2017-08-11 1:24 ` Christopher Li
2017-08-11 11:14 ` Luc Van Oostenryck
0 siblings, 1 reply; 30+ messages in thread
From: Christopher Li @ 2017-08-11 1:24 UTC (permalink / raw)
To: Luc Van Oostenryck; +Cc: Linux-Sparse, Nicolai Stange
On Thu, Aug 10, 2017 at 6:00 PM, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
>
> It's many months ago so I may not remember the details correctly but ...
>
> The initial version Nicolai posted (or maybe it was the second) *had*
> function to abstract the operations and it was, IMO, really not very readable
Ok. I can try to dig them out and see the original form.
> and I asked him to change to something simpler like simply using
> X |= M or X &= ~M when possible.
> It's what he did and it was, IMO, much more readable.
>
> Meanwhile, I also tried on my side to have some nice & cleaner bit
> representation. It looked promising at first but was deceiving at the end.
>
> So, I think that this series is much more valuable upstreamed than waiting
> for some hypothetical super clean abstract layer for those few bits.
Completely agree. I want to make them upstream after the release.
No question about it. Even as it is is acceptable for after release.
> Of course, if you have some concrete set of patches making this better,
> I would be glad to take a look at it and change my mind.
> Otherwise, please consider it for upstreaming directly after the release
> and improving the bit representation and the abstraction layer can always
> be done later too.
That is what I mean by "suggestion only". It means I will apply it regardless
the suggestion has been follow or not. Remind me a git pull for it after the
release.
Chris
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 00/25] improve constexpr handling
2017-08-11 1:24 ` Christopher Li
@ 2017-08-11 11:14 ` Luc Van Oostenryck
0 siblings, 0 replies; 30+ messages in thread
From: Luc Van Oostenryck @ 2017-08-11 11:14 UTC (permalink / raw)
To: Christopher Li; +Cc: Linux-Sparse, Nicolai Stange
On Thu, Aug 10, 2017 at 09:24:49PM -0400, Christopher Li wrote:
> On Thu, Aug 10, 2017 at 6:00 PM, Luc Van Oostenryck
> <luc.vanoostenryck@gmail.com> wrote:
> >
> > It's many months ago so I may not remember the details correctly but ...
> >
> > The initial version Nicolai posted (or maybe it was the second) *had*
> > function to abstract the operations and it was, IMO, really not very readable
>
> Ok. I can try to dig them out and see the original form.
>
> > and I asked him to change to something simpler like simply using
> > X |= M or X &= ~M when possible.
> > It's what he did and it was, IMO, much more readable.
> >
> > Meanwhile, I also tried on my side to have some nice & cleaner bit
> > representation. It looked promising at first but was deceiving at the end.
> >
> > So, I think that this series is much more valuable upstreamed than waiting
> > for some hypothetical super clean abstract layer for those few bits.
>
> Completely agree. I want to make them upstream after the release.
> No question about it. Even as it is is acceptable for after release.
Great!
-- Luc
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2017-08-11 11:14 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-03-31 1:44 [PATCH v4 00/25] improve constexpr handling Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 01/25] constexpr: introduce additional expression constness tracking flags Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 02/25] constexpr: init flags at expression allocation Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 03/25] constexpr: examine constness of casts at evaluation only Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 04/25] constexpr: examine constness of binops and alike " Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 05/25] constexpr: examine constness of preops " Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 06/25] constexpr: examine constness of conditionals " Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 07/25] constexpr: add support for tagging arithmetic constant expressions Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 08/25] constexpr: add support for tagging address constants Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 09/25] constexpr: rename handle_simple_initializer() to handle_initializer() Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 10/25] constexpr: collect storage modifiers of initializers Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 11/25] constexpr: check static storage duration objects' intializers' constness Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 12/25] constexpr: recognize static objects as address constants Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 13/25] constexpr: recognize address constants created through casts Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 14/25] constexpr: recognize address constants created through pointer arithmetic Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 15/25] constexpr: recognize members of static compound objects as address constants Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 16/25] constexpr: recognize string literals " Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 17/25] constexpr: recognize references to labels " Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 18/25] constexpr: examine constness of __builtin_offsetof at evaluation only Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 19/25] constexpr: flag builtins constant_p, safe_p and warning as constexprs Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 20/25] constexpr: relax some constant expression rules for pointer expressions Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 21/25] constexpr: support compound literals as address constants Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 22/25] constexpr: treat comparisons between types as integer constexpr Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 23/25] return an error if too few args Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 24/25] give default return type in evaluate_call() Luc Van Oostenryck
2017-03-31 1:44 ` [PATCH v4 25/25] constexpr: flag __builtin_bswap() as constexpr Luc Van Oostenryck
2017-08-10 12:36 ` [PATCH v4 00/25] improve constexpr handling Christopher Li
2017-08-10 22:00 ` Luc Van Oostenryck
2017-08-11 1:24 ` Christopher Li
2017-08-11 11:14 ` Luc Van Oostenryck
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).