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@xxxxxxxxx> --- 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 300bfbe..91f89f4 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->constexpr_flags = expr->constexpr_flags; expr->type = EXPR_PREOP; expr->op = '*'; expr->unop = addr; + expr->constexpr_flags = CONSTEXPR_FLAG_NONE; /* The type of a symbol is the symbol itself! */ expr->ctype = sym; @@ -1682,7 +1684,6 @@ static struct symbol *evaluate_addressof(struct expression *expr) } ctype = op->ctype; *expr = *op->unop; - expr->constexpr_flags = CONSTEXPR_FLAG_NONE; if (expr->type == EXPR_SYMBOL) { struct symbol *sym = expr->symbol; diff --git a/expression.c b/expression.c index b2d5eb4..11fb9cd 100644 --- a/expression.c +++ b/expression.c @@ -440,6 +440,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->constexpr_flags = CONSTEXPR_FLAG_ADDR_CONST; + token = next; break; } diff --git a/validation/constexpr-addr-of-static.c b/validation/constexpr-addr-of-static.c new file mode 100644 index 0000000..a3af99a --- /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.7.0 -- To unsubscribe from this list: send the line "unsubscribe linux-sparse" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html