From: Johannes Berg <johannes@xxxxxxxxxxxxxxxx> But still allow having a standalone symbol as the context expression, also evaluate the context change/requirement directly in the parser and pass them up as integers. Also fixes a number of bugs e.g. in the expression copier and a segfault when the default context is used as such: __context__(1,1); Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx> --- evaluate.c | 9 ++++++++- expand.c | 2 +- inline.c | 19 ++++++++++++------- linearize.c | 17 +++-------------- parse.c | 22 +++++++++++++--------- parse.h | 6 ++++-- validation/context.c | 28 ++++++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 34 deletions(-) diff --git a/evaluate.c b/evaluate.c index f976645..0c86295 100644 --- a/evaluate.c +++ b/evaluate.c @@ -3364,7 +3364,14 @@ struct symbol *evaluate_statement(struct statement *stmt) evaluate_asm_statement(stmt); return NULL; case STMT_CONTEXT: - evaluate_expression(stmt->expression); + /* + * If this is an unknown symbol accept it as-is + * as a context name. + */ + if (stmt->context && + (stmt->context->type != EXPR_SYMBOL || + stmt->context->symbol)) + evaluate_expression(stmt->context); return NULL; case STMT_RANGE: evaluate_expression(stmt->range_expression); diff --git a/expand.c b/expand.c index 3e962d1..dece314 100644 --- a/expand.c +++ b/expand.c @@ -1169,7 +1169,7 @@ static int expand_statement(struct statement *stmt) /* FIXME! Do the asm parameter evaluation! */ break; case STMT_CONTEXT: - expand_expression(stmt->expression); + expand_expression(stmt->context); break; case STMT_RANGE: expand_expression(stmt->range_expression); diff --git a/inline.c b/inline.c index 09d176a..3e984c3 100644 --- a/inline.c +++ b/inline.c @@ -328,7 +328,18 @@ static struct statement *copy_one_statement(struct statement *stmt) stmt = newstmt; break; } - case STMT_CONTEXT: + case STMT_CONTEXT: { + struct expression *expr = copy_expression(stmt->context); + struct statement *newstmt; + if (expr == stmt->context) + break; + newstmt = dup_statement(stmt); + newstmt->context = expr; + newstmt->change = stmt->change; + newstmt->required = stmt->required; + stmt = newstmt; + break; + } case STMT_EXPRESSION: { struct expression *expr = copy_expression(stmt->expression); struct statement *newstmt; @@ -336,12 +347,6 @@ static struct statement *copy_one_statement(struct statement *stmt) break; newstmt = dup_statement(stmt); newstmt->expression = expr; - if (stmt->required) { - expr = copy_expression(stmt->required); - if (expr == stmt->required) - break; - newstmt->required = expr; - } stmt = newstmt; break; } diff --git a/linearize.c b/linearize.c index 9f5628a..8e9775d 100644 --- a/linearize.c +++ b/linearize.c @@ -1755,22 +1755,11 @@ static pseudo_t linearize_inlined_call(struct entrypoint *ep, struct statement * static pseudo_t linearize_context(struct entrypoint *ep, struct statement *stmt) { struct instruction *insn = alloc_instruction(OP_CONTEXT, 0); - struct expression *expr = stmt->expression; - int value = 0; - if (expr->type == EXPR_VALUE) - value = expr->value; + insn->increment = stmt->change; + insn->inc_false = stmt->change; - insn->increment = value; - insn->inc_false = value; - - expr = stmt->required; - value = 0; - - if (expr && expr->type == EXPR_VALUE) - value = expr->value; - - insn->required = value; + insn->required = stmt->required; insn->exact = stmt->exact; insn->context_expr = stmt->context; diff --git a/parse.c b/parse.c index 2ac3d0e..fdb7efb 100644 --- a/parse.c +++ b/parse.c @@ -1860,9 +1860,7 @@ static struct token *_parse_context_statement(struct token *token, struct statem token = token->next; } - stmt->expression = args[0]; stmt->context = NULL; - stmt->exact = exact; switch (argc) { @@ -1870,21 +1868,27 @@ static struct token *_parse_context_statement(struct token *token, struct statem sparse_error(token->pos, "__context__ statement needs argument(s)"); return token; case 1: - /* already done */ + stmt->change = get_expression_value(args[0]); break; case 2: - if (args[0]->type != STMT_EXPRESSION) { + /* + * We should actually check whether we can evalulate + * it as a constant expression and if so use as the + * 'change' value. I hope nobody gives a calculation + * for the number. + */ + if (args[0]->type != EXPR_VALUE) { stmt->context = args[0]; - stmt->expression = args[1]; + stmt->change = get_expression_value(args[1]); } else { - stmt->expression = args[0]; - stmt->required = args[1]; + stmt->change = get_expression_value(args[0]); + stmt->required = get_expression_value(args[1]); } break; case 3: stmt->context = args[0]; - stmt->expression = args[1]; - stmt->required = args[2]; + stmt->change = get_expression_value(args[1]); + stmt->required = get_expression_value(args[2]); break; default: sparse_error(token->pos, "too many arguments for __context__ statement"); diff --git a/parse.h b/parse.h index ae50720..fe714b6 100644 --- a/parse.h +++ b/parse.h @@ -39,10 +39,12 @@ struct statement { struct symbol *label; struct statement *label_statement; }; - struct { /* __context__ */ + struct { /* expression */ struct expression *expression; + }; + struct { /* __context__ */ struct expression *context; - struct expression *required; + int change, required; int exact; }; struct /* return_statement */ { diff --git a/validation/context.c b/validation/context.c index e8bb125..2c32ef3 100644 --- a/validation/context.c +++ b/validation/context.c @@ -395,6 +395,32 @@ static void good_require_caller(void) __context__(TEST,-1,1); } +static void areq(void) __attribute__((context(1,2))) +{ + __context__(1,1); +} + +static void good_reqlock(void) +{ + a(); + areq(); + r(); + r(); +} + +static void warn_reqlock(void) +{ + areq(); + r(); +} + + +static void dummy1(void) __attribute__((context(p,0,1))) +{ + void *p; + __context__(p,1); +} + /* * check-name: Check -Wcontext * @@ -433,5 +459,7 @@ context.c:360:10: warning: context problem in 'warn_huge_switch': 'r' expected d context.c:360:10: default context: wanted >= 1, got 0 context.c:380:12: warning: context imbalance in 'warn_conditional': wrong count at exit context.c:380:12: default context: wanted 0, got 1 +context.c:413:6: warning: context problem in 'warn_reqlock': 'areq' expected different context +context.c:413:6: default context: wanted >= 1, got 0 * check-error-end */ -- 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