diff options
| -rw-r--r-- | allocate.c | 1 | ||||
| -rw-r--r-- | allocate.h | 1 | ||||
| -rw-r--r-- | dissect.c | 8 | ||||
| -rw-r--r-- | evaluate.c | 158 | ||||
| -rw-r--r-- | expand.c | 29 | ||||
| -rw-r--r-- | expression.c | 11 | ||||
| -rw-r--r-- | expression.h | 20 | ||||
| -rw-r--r-- | inline.c | 28 | ||||
| -rw-r--r-- | lib.h | 2 | ||||
| -rw-r--r-- | linearize.c | 48 | ||||
| -rw-r--r-- | linearize.h | 1 | ||||
| -rw-r--r-- | liveness.c | 5 | ||||
| -rw-r--r-- | parse.c | 22 | ||||
| -rw-r--r-- | parse.h | 4 | ||||
| -rw-r--r-- | show-parse.c | 3 | ||||
| -rw-r--r-- | validation/asm-bad0.c | 41 | ||||
| -rw-r--r-- | validation/bad-type-twice0.c | 4 | ||||
| -rw-r--r-- | validation/bad-type-twice1.c | 6 | ||||
| -rw-r--r-- | validation/compare-null-to-int.c | 6 | ||||
| -rw-r--r-- | validation/cond_expr.c | 4 | ||||
| -rw-r--r-- | validation/conditional-type.c | 32 | ||||
| -rw-r--r-- | validation/enum-mismatch.c | 6 | ||||
| -rw-r--r-- | validation/eval/asm-degen.c | 36 | ||||
| -rw-r--r-- | validation/eval/asm-memop.c | 47 | ||||
| -rw-r--r-- | validation/expand/asm0.c | 23 | ||||
| -rw-r--r-- | validation/expand/compound-literal.c | 26 | ||||
| -rw-r--r-- | validation/linear/asm-memop.c | 23 | ||||
| -rw-r--r-- | validation/linear/compound-literal02.c | 1 | ||||
| -rw-r--r-- | validation/static_assert.c | 6 |
29 files changed, 455 insertions, 147 deletions
@@ -141,6 +141,7 @@ ALLOCATOR(ident, "identifiers"); ALLOCATOR(token, "tokens"); ALLOCATOR(context, "contexts"); ALLOCATOR(symbol, "symbols"); +ALLOCATOR(asm_operand, "asmops"); ALLOCATOR(expression, "expressions"); ALLOCATOR(statement, "statements"); ALLOCATOR(string, "strings"); @@ -82,6 +82,7 @@ DECLARE_ALLOCATOR(ident); DECLARE_ALLOCATOR(token); DECLARE_ALLOCATOR(context); DECLARE_ALLOCATOR(symbol); +DECLARE_ALLOCATOR(asm_operand); DECLARE_ALLOCATOR(expression); DECLARE_ALLOCATOR(statement); DECLARE_ALLOCATOR(string); @@ -450,13 +450,9 @@ again: return ret; } -static void do_asm_xputs(usage_t mode, struct expression_list *xputs) +static void do_asm_xputs(usage_t mode, struct asm_operand_list *xputs) { - int nr = 0; - - DO_LIST(xputs, expr, - if (++nr % 3 == 0) - do_expression(U_W_AOF | mode, expr)); + DO_LIST(xputs, op, do_expression(U_W_AOF | mode, op->expr)); } static struct symbol *do_statement(usage_t mode, struct statement *stmt) @@ -283,9 +283,9 @@ warn_for_different_enum_types (struct position pos, return; if (typea->type == SYM_ENUM && typeb->type == SYM_ENUM) { - warning(pos, "mixing different enum types"); - info(pos, " %s versus", show_typename(typea)); - info(pos, " %s", show_typename(typeb)); + warning(pos, "mixing different enum types:"); + info(pos, " %s", show_typename(typea)); + info(pos, " %s", show_typename(typeb)); } } @@ -413,16 +413,16 @@ static struct symbol *bad_expr_type(struct expression *expr) case EXPR_COMPARE: if (!valid_subexpr_type(expr)) break; - sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op)); - info(expr->pos, " left side has type %s", show_typename(expr->left->ctype)); - info(expr->pos, " right side has type %s", show_typename(expr->right->ctype)); + sparse_error(expr->pos, "incompatible types for operation (%s):", show_special(expr->op)); + info(expr->pos, " %s", show_typename(expr->left->ctype)); + info(expr->pos, " %s", show_typename(expr->right->ctype)); break; case EXPR_PREOP: case EXPR_POSTOP: if (!valid_expr_type(expr->unop)) break; - sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op)); - info(expr->pos, " argument has type %s", show_typename(expr->unop->ctype)); + sparse_error(expr->pos, "incompatible type for operation (%s):", show_special(expr->op)); + info(expr->pos, " %s", show_typename(expr->unop->ctype)); break; default: break; @@ -910,8 +910,8 @@ static struct symbol *evaluate_conditional(struct expression *expr, int iterator if (Waddress) warning(expr->pos, "the address of %s will always evaluate as true", "an array"); } else if (!is_scalar_type(ctype)) { - sparse_error(expr->pos, "incorrect type in conditional (non-scalar type)"); - info(expr->pos, " got %s", show_typename(ctype)); + sparse_error(expr->pos, "non-scalar type in conditional:"); + info(expr->pos, " %s", show_typename(ctype)); return NULL; } @@ -2937,6 +2937,7 @@ static struct symbol *evaluate_cast(struct expression *expr) * initializer, in which case we need to pass * the type value down to that initializer rather * than trying to evaluate it as an expression + * (cfr. compound literals: C99 & C11 6.5.2.5). * * A more complex case is when the initializer is * dereferenced as part of a post-fix expression. @@ -3355,9 +3356,6 @@ struct symbol *evaluate_expression(struct expression *expr) case EXPR_SLICE: expression_error(expr, "internal front-end error: SLICE re-evaluated"); return NULL; - case EXPR_ASM_OPERAND: - expression_error(expr, "internal front-end error: ASM_OPERAND evaluated"); - return NULL; } return NULL; } @@ -3497,48 +3495,128 @@ static void evaluate_iterator(struct statement *stmt) evaluate_statement(stmt->iterator_post_statement); } -static void verify_output_constraint(struct expression *expr, const char *constraint) + +static void parse_asm_constraint(struct asm_operand *op) { - switch (*constraint) { - case '=': /* Assignment */ - case '+': /* Update */ + struct expression *constraint = op->constraint; + const char *str = constraint->string->data; + int c; + + switch (str[0]) { + case '+': + op->is_modify = true; + /* fall-through */ + case '=': + op->is_assign = true; + str++; break; - default: - expression_error(expr, "output constraint is not an assignment constraint (\"%s\")", constraint); } + + while ((c = *str++)) { + switch (c) { + case '=': + case '+': + sparse_error(constraint->pos, "invalid ASM constraint '%c'", c); + break; + + case '&': + op->is_earlyclobber = true; + break; + case '%': + op->is_commutative = true; + break; + case 'r': + op->is_register = true; + break; + + case 'm': + case 'o': + case 'V': + case 'Q': + op->is_memory = true; + break; + + case '<': + case '>': + // FIXME: ignored for now + break; + + case ',': + // FIXME: multiple alternative constraints + break; + + case '0' ... '9': + // FIXME: numeric matching constraint? + break; + case '[': + // FIXME: symbolic matching constraint + return; + + default: + // FIXME: arch-specific (and multi-letter) constraints + break; + } + } + + // FIXME: how to deal with multi-constraint? + if (op->is_register) + op->is_memory = 0; } -static void verify_input_constraint(struct expression *expr, const char *constraint) +static void verify_output_constraint(struct asm_operand *op) { - switch (*constraint) { - case '=': /* Assignment */ - case '+': /* Update */ + struct expression *expr = op->constraint; + const char *constraint = expr->string->data; + + if (!op->is_assign) + expression_error(expr, "output constraint is not an assignment constraint (\"%s\")", constraint); +} + +static void verify_input_constraint(struct asm_operand *op) +{ + struct expression *expr = op->constraint; + const char *constraint = expr->string->data; + + if (op->is_assign) expression_error(expr, "input constraint with assignment (\"%s\")", constraint); +} + +static void evaluate_asm_memop(struct asm_operand *op) +{ + if (op->is_memory) { + struct expression *expr = op->expr; + struct expression *addr; + + // implicit addressof + addr = alloc_expression(expr->pos, EXPR_PREOP); + addr->op = '&'; + addr->unop = expr; + + evaluate_addressof(addr); + op->expr = addr; + } else { + evaluate_expression(op->expr); + degenerate(op->expr); } } static void evaluate_asm_statement(struct statement *stmt) { struct expression *expr; - struct expression *op; + struct asm_operand *op; struct symbol *sym; - expr = stmt->asm_string; - if (!expr || expr->type != EXPR_STRING) { - sparse_error(stmt->pos, "need constant string for inline asm"); + if (!stmt->asm_string) return; - } FOR_EACH_PTR(stmt->asm_outputs, op) { /* Identifier */ /* Constraint */ - expr = op->constraint; - if (!expr || expr->type != EXPR_STRING) { - sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string"); - op->constraint = NULL; - } else - verify_output_constraint(expr, expr->string->data); + if (op->constraint) { + parse_asm_constraint(op); + verify_output_constraint(op); + } /* Expression */ expr = op->expr; @@ -3547,22 +3625,22 @@ static void evaluate_asm_statement(struct statement *stmt) if (!lvalue_expression(expr)) warning(expr->pos, "asm output is not an lvalue"); evaluate_assign_to(expr, expr->ctype); + evaluate_asm_memop(op); } END_FOR_EACH_PTR(op); FOR_EACH_PTR(stmt->asm_inputs, op) { /* Identifier */ /* Constraint */ - expr = op->constraint; - if (!expr || expr->type != EXPR_STRING) { - sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string"); - op->constraint = NULL; - } else - verify_input_constraint(expr, expr->string->data); + if (op->constraint) { + parse_asm_constraint(op); + verify_input_constraint(op); + } /* Expression */ if (!evaluate_expression(op->expr)) return; + evaluate_asm_memop(op); } END_FOR_EACH_PTR(op); FOR_EACH_PTR(stmt->asm_clobbers, expr) { @@ -66,6 +66,14 @@ static int expand_symbol_expression(struct expression *expr) expr->taint = 0; return 0; } + + // expand compound literals (C99 & C11 6.5.2.5) + // FIXME: is this the correct way to identify them? + // All compound literals are anonymous but is + // the reverse true? + if (sym->initializer && !expr->symbol_name) + return expand_expression(sym->initializer); + /* The cost of a symbol expression is lower for on-stack symbols */ return (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN)) ? 2 : 1; } @@ -1095,9 +1103,6 @@ static int expand_expression(struct expression *expr) case EXPR_OFFSETOF: expression_error(expr, "internal front-end error: sizeof in expansion?"); return UNSAFE; - case EXPR_ASM_OPERAND: - expression_error(expr, "internal front-end error: ASM_OPERAND in expansion?"); - return UNSAFE; } return SIDE_EFFECTS; } @@ -1167,6 +1172,22 @@ static int expand_if_statement(struct statement *stmt) return SIDE_EFFECTS; } +static int expand_asm_statement(struct statement *stmt) +{ + struct asm_operand *op; + int cost = 0; + + FOR_EACH_PTR(stmt->asm_outputs, op) { + cost += expand_expression(op->expr); + } END_FOR_EACH_PTR(op); + + FOR_EACH_PTR(stmt->asm_inputs, op) { + cost += expand_expression(op->expr); + } END_FOR_EACH_PTR(op); + + return cost; +} + /* * Expanding a compound statement is really just * about adding up the costs of each individual @@ -1257,7 +1278,7 @@ static int expand_statement(struct statement *stmt) case STMT_NONE: break; case STMT_ASM: - /* FIXME! Do the asm parameter evaluation! */ + expand_asm_statement(stmt); break; case STMT_CONTEXT: expand_expression(stmt->expression); diff --git a/expression.c b/expression.c index f955fb15..ffb6cb9d 100644 --- a/expression.c +++ b/expression.c @@ -83,6 +83,17 @@ struct token *parens_expression(struct token *token, struct expression **expr, c return expect(token, ')', where); } +struct token *string_expression(struct token *token, struct expression **expr, const char *where) +{ + struct token *next = primary_expression(token, expr); + + if (!*expr || (*expr)->type != EXPR_STRING) { + sparse_error(token->pos, "string literal expected for %s", where); + *expr = NULL; + } + return next; +} + /* * Handle __func__, __FUNCTION__ and __PRETTY_FUNCTION__ token * conversion diff --git a/expression.h b/expression.h index ed6f4d65..3b79e0f1 100644 --- a/expression.h +++ b/expression.h @@ -64,7 +64,6 @@ enum expression_type { EXPR_FVALUE, EXPR_SLICE, EXPR_OFFSETOF, - EXPR_ASM_OPERAND, }; @@ -136,6 +135,18 @@ enum { Taint_comma = 1, }; /* for expr->taint */ +struct asm_operand { + struct ident *name; + struct expression *constraint; + struct expression *expr; + unsigned int is_assign:1; + unsigned int is_modify:1; + unsigned int is_earlyclobber:1; + unsigned int is_commutative:1; + unsigned int is_register:1; + unsigned int is_memory:1; +}; + struct expression { enum expression_type type:8; unsigned flags:8; @@ -235,12 +246,6 @@ struct expression { struct expression *index; }; }; - // EXPR_ASM_OPERAND - struct { - struct ident *name; - struct expression *constraint; - struct expression *expr; - }; }; }; @@ -270,6 +275,7 @@ struct token *parse_expression(struct token *token, struct expression **tree); struct token *conditional_expression(struct token *token, struct expression **tree); struct token *primary_expression(struct token *token, struct expression **tree); struct token *parens_expression(struct token *token, struct expression **expr, const char *where); +struct token *string_expression(struct token *token, struct expression **expr, const char *where); struct token *assignment_expression(struct token *token, struct expression **tree); extern int expand_symbol(struct symbol *); @@ -274,26 +274,24 @@ static struct expression * copy_expression(struct expression *expr) } break; } - case EXPR_ASM_OPERAND: { - expr = dup_expression(expr); - expr->constraint = copy_expression(expr->constraint); - expr->expr = copy_expression(expr->expr); - break; - } default: warning(expr->pos, "trying to copy expression type %d", expr->type); } return expr; } -static struct expression_list *copy_asm_constraints(struct expression_list *in) +static struct asm_operand_list *copy_asm_operands(struct asm_operand_list *in) { - struct expression_list *out = NULL; - struct expression *expr; - - FOR_EACH_PTR(in, expr) { - add_expression(&out, copy_expression(expr)); - } END_FOR_EACH_PTR(expr); + struct asm_operand_list *out = NULL; + struct asm_operand *old; + + FOR_EACH_PTR(in, old) { + struct asm_operand *new = __alloc_asm_operand(0); + new->name = old->name; + new->constraint = copy_expression(old->constraint); + new->expr = copy_expression(old->expr); + add_ptr_list(&out, new); + } END_FOR_EACH_PTR(old); return out; } @@ -445,8 +443,8 @@ static struct statement *copy_one_statement(struct statement *stmt) } case STMT_ASM: { stmt = dup_statement(stmt); - stmt->asm_inputs = copy_asm_constraints(stmt->asm_inputs); - stmt->asm_outputs = copy_asm_constraints(stmt->asm_outputs); + stmt->asm_inputs = copy_asm_operands(stmt->asm_inputs); + stmt->asm_outputs = copy_asm_operands(stmt->asm_outputs); /* no need to dup "clobbers", since they are all constant strings */ break; } @@ -67,6 +67,7 @@ struct ident; struct token; struct symbol; struct statement; +struct asm_operand; struct expression; struct basic_block; struct entrypoint; @@ -76,6 +77,7 @@ struct pseudo; DECLARE_PTR_LIST(symbol_list, struct symbol); DECLARE_PTR_LIST(statement_list, struct statement); +DECLARE_PTR_LIST(asm_operand_list, struct asm_operand); DECLARE_PTR_LIST(expression_list, struct expression); DECLARE_PTR_LIST(basic_block_list, struct basic_block); DECLARE_PTR_LIST(instruction_list, struct instruction); diff --git a/linearize.c b/linearize.c index 9ed66737..30ed2a30 100644 --- a/linearize.c +++ b/linearize.c @@ -2075,41 +2075,45 @@ static pseudo_t linearize_range(struct entrypoint *ep, struct statement *stmt) ALLOCATOR(asm_rules, "asm rules"); ALLOCATOR(asm_constraint, "asm constraints"); -static void add_asm_input(struct entrypoint *ep, struct instruction *insn, struct expression *expr, - const char *constraint, const struct ident *ident) +static void add_asm_input(struct entrypoint *ep, struct instruction *insn, struct asm_operand *op) { - pseudo_t pseudo = linearize_expression(ep, expr); + pseudo_t pseudo = linearize_expression(ep, op->expr); struct asm_constraint *rule = __alloc_asm_constraint(0); - rule->ident = ident; - rule->constraint = constraint; + rule->ident = op->name; + rule->constraint = op->constraint ? op->constraint->string->data : ""; use_pseudo(insn, pseudo, &rule->pseudo); add_ptr_list(&insn->asm_rules->inputs, rule); } -static void add_asm_output(struct entrypoint *ep, struct instruction *insn, struct expression *expr, - const char *constraint, const struct ident *ident) +static void add_asm_output(struct entrypoint *ep, struct instruction *insn, struct asm_operand *op) { struct access_data ad = { NULL, }; - pseudo_t pseudo = alloc_pseudo(insn); + pseudo_t pseudo; struct asm_constraint *rule; - if (!expr || !linearize_address_gen(ep, expr, &ad)) - return; - linearize_store_gen(ep, pseudo, &ad); + if (op->is_memory) { + pseudo = linearize_expression(ep, op->expr); + } else { + if (!linearize_address_gen(ep, op->expr, &ad)) + return; + pseudo = alloc_pseudo(insn); + linearize_store_gen(ep, pseudo, &ad); + } rule = __alloc_asm_constraint(0); - rule->ident = ident; - rule->constraint = constraint; + rule->is_memory = op->is_memory; + rule->ident = op->name; + rule->constraint = op->constraint ? op->constraint->string->data : ""; use_pseudo(insn, pseudo, &rule->pseudo); add_ptr_list(&insn->asm_rules->outputs, rule); } static pseudo_t linearize_asm_statement(struct entrypoint *ep, struct statement *stmt) { - struct expression *expr; struct instruction *insn; + struct expression *expr; struct asm_rules *rules; - const char *constraint; + struct asm_operand *op; insn = alloc_instruction(OP_ASM, 0); expr = stmt->asm_string; @@ -2123,18 +2127,16 @@ static pseudo_t linearize_asm_statement(struct entrypoint *ep, struct statement insn->asm_rules = rules; /* Gather the inputs.. */ - FOR_EACH_PTR(stmt->asm_inputs, expr) { - constraint = expr->constraint ? expr->constraint->string->data : ""; - add_asm_input(ep, insn, expr->expr, constraint, expr->name); - } END_FOR_EACH_PTR(expr); + FOR_EACH_PTR(stmt->asm_inputs, op) { + add_asm_input(ep, insn, op); + } END_FOR_EACH_PTR(op); add_one_insn(ep, insn); /* Assign the outputs */ - FOR_EACH_PTR(stmt->asm_outputs, expr) { - constraint = expr->constraint ? expr->constraint->string->data : ""; - add_asm_output(ep, insn, expr->expr, constraint, expr->name); - } END_FOR_EACH_PTR(expr); + FOR_EACH_PTR(stmt->asm_outputs, op) { + add_asm_output(ep, insn, op); + } END_FOR_EACH_PTR(op); return VOID; } diff --git a/linearize.h b/linearize.h index 89da3db6..76efd0b4 100644 --- a/linearize.h +++ b/linearize.h @@ -68,6 +68,7 @@ struct asm_constraint { pseudo_t pseudo; const char *constraint; const struct ident *ident; + unsigned int is_memory:1; }; DECLARE_ALLOCATOR(asm_constraint); @@ -39,7 +39,10 @@ static void asm_liveness(struct basic_block *bb, struct instruction *insn, } END_FOR_EACH_PTR(entry); FOR_EACH_PTR(insn->asm_rules->outputs, entry) { - def(bb, entry->pseudo); + if (entry->is_memory) + use(bb, entry->pseudo); + else + def(bb, entry->pseudo); } END_FOR_EACH_PTR(entry); } @@ -2049,22 +2049,23 @@ static struct token *expression_statement(struct token *token, struct expression } static struct token *parse_asm_operands(struct token *token, struct statement *stmt, - struct expression_list **inout) + struct asm_operand_list **inout) { /* Allow empty operands */ if (match_op(token->next, ':') || match_op(token->next, ')')) return token->next; do { - struct expression *op = alloc_expression(token->pos, EXPR_ASM_OPERAND); + struct asm_operand *op = __alloc_asm_operand(0); if (match_op(token->next, '[') && token_type(token->next->next) == TOKEN_IDENT && match_op(token->next->next->next, ']')) { op->name = token->next->next->ident; token = token->next->next->next; } - token = primary_expression(token->next, &op->constraint); + token = token->next; + token = string_expression(token, &op->constraint, "asm constraint"); token = parens_expression(token, &op->expr, "in asm parameter"); - add_expression(inout, op); + add_ptr_list(inout, op); } while (match_op(token, ',')); return token; } @@ -2113,7 +2114,7 @@ static struct token *parse_asm_statement(struct token *token, struct statement * token = token->next; } token = expect(token, '(', "after asm"); - token = parse_expression(token, &stmt->asm_string); + token = string_expression(token, &stmt->asm_string, "inline asm"); if (match_op(token, ':')) token = parse_asm_operands(token, stmt, &stmt->asm_outputs); if (match_op(token, ':')) @@ -2130,7 +2131,7 @@ static struct token *parse_asm_declarator(struct token *token, struct decl_state { struct expression *expr; token = expect(token, '(', "after asm"); - token = parse_expression(token->next, &expr); + token = string_expression(token, &expr, "inline asm"); token = expect(token, ')', "after asm"); return token; } @@ -2144,14 +2145,9 @@ static struct token *parse_static_assert(struct token *token, struct symbol_list if (!cond) sparse_error(token->pos, "Expected constant expression"); token = expect(token, ',', "after conditional expression in _Static_assert"); - token = parse_expression(token, &message); - if (!message || message->type != EXPR_STRING) { - struct position pos; - - pos = message ? message->pos : token->pos; - sparse_error(pos, "bad or missing string literal"); + token = string_expression(token, &message, "_Static_assert()"); + if (!message) cond = NULL; - } token = expect(token, ')', "after diagnostic message in _Static_assert"); token = expect(token, ';', "after _Static_assert()"); @@ -106,8 +106,8 @@ struct statement { }; struct /* asm */ { struct expression *asm_string; - struct expression_list *asm_outputs; - struct expression_list *asm_inputs; + struct asm_operand_list *asm_outputs; + struct asm_operand_list *asm_inputs; struct expression_list *asm_clobbers; struct symbol_list *asm_labels; }; diff --git a/show-parse.c b/show-parse.c index 3aa06e47..37104167 100644 --- a/show-parse.c +++ b/show-parse.c @@ -1185,9 +1185,6 @@ int show_expression(struct expression *expr) case EXPR_TYPE: warning(expr->pos, "unable to show type expression"); return 0; - case EXPR_ASM_OPERAND: - warning(expr->pos, "unable to show asm operand expression"); - return 0; } return 0; } diff --git a/validation/asm-bad0.c b/validation/asm-bad0.c new file mode 100644 index 00000000..aa9bf28d --- /dev/null +++ b/validation/asm-bad0.c @@ -0,0 +1,41 @@ +extern char string[]; +extern int *var; + +static void templ(void) +{ + asm(string); +} + +static void ocons(void) +{ + asm("template" : [out] string (var) : [in] "r" (0)); +} + +static void icons(void) +{ + asm("template" : [out] "=r" (var): [in] string (0)); +} + +static void oexpr(oid) +{ + asm("template" : [out] "=" (var[) : [in] "r" (0)); +} + +static void iexpr(void) +{ + asm("template" : [out] "=r" (var) : [in] "r" (var[)); +} + +/* + * check-name: asm-bad0 + * + * check-error-start +asm-bad0.c:6:13: error: string literal expected for inline asm +asm-bad0.c:11:32: error: string literal expected for asm constraint +asm-bad0.c:16:49: error: string literal expected for asm constraint +asm-bad0.c:21:41: error: Expected ] at end of array dereference +asm-bad0.c:21:41: error: got ) +asm-bad0.c:26:59: error: Expected ] at end of array dereference +asm-bad0.c:26:59: error: got ) + * check-error-end + */ diff --git a/validation/bad-type-twice0.c b/validation/bad-type-twice0.c index 5d107a62..9e834d47 100644 --- a/validation/bad-type-twice0.c +++ b/validation/bad-type-twice0.c @@ -7,7 +7,7 @@ static int foo(a) * check-name: bad-type-twice0 * * check-error-start -bad-type-twice0.c:3:16: error: incorrect type in conditional (non-scalar type) -bad-type-twice0.c:3:16: got incomplete type a +bad-type-twice0.c:3:16: error: non-scalar type in conditional: +bad-type-twice0.c:3:16: incomplete type a * check-error-end */ diff --git a/validation/bad-type-twice1.c b/validation/bad-type-twice1.c index cc81662a..a9ba182c 100644 --- a/validation/bad-type-twice1.c +++ b/validation/bad-type-twice1.c @@ -9,8 +9,8 @@ static unsigned long foo(unsigned long val, void *ref) * check-name: bad-type-twice1 * * check-error-start -bad-type-twice1.c:3:17: error: incompatible types for operation (>=) -bad-type-twice1.c:3:17: left side has type unsigned long val -bad-type-twice1.c:3:17: right side has type void *ref +bad-type-twice1.c:3:17: error: incompatible types for operation (>=): +bad-type-twice1.c:3:17: unsigned long val +bad-type-twice1.c:3:17: void *ref * check-error-end */ diff --git a/validation/compare-null-to-int.c b/validation/compare-null-to-int.c index 08e556b3..336c724d 100644 --- a/validation/compare-null-to-int.c +++ b/validation/compare-null-to-int.c @@ -4,8 +4,8 @@ static unsigned int comparison = (void *)0 == 1; * check-description: Sparse used to allow this. * * check-error-start -compare-null-to-int.c:1:44: error: incompatible types for operation (==) -compare-null-to-int.c:1:44: left side has type void * -compare-null-to-int.c:1:44: right side has type int +compare-null-to-int.c:1:44: error: incompatible types for operation (==): +compare-null-to-int.c:1:44: void * +compare-null-to-int.c:1:44: int * check-error-end */ diff --git a/validation/cond_expr.c b/validation/cond_expr.c index e55711cc..9b8105c1 100644 --- a/validation/cond_expr.c +++ b/validation/cond_expr.c @@ -13,7 +13,7 @@ int a(void) * check-name: Two-argument conditional expression types * * check-error-start -cond_expr.c:10:16: error: incompatible types for operation (~) -cond_expr.c:10:16: argument has type double +cond_expr.c:10:16: error: incompatible type for operation (~): +cond_expr.c:10:16: double * check-error-end */ diff --git a/validation/conditional-type.c b/validation/conditional-type.c index 91267212..6e2da9b5 100644 --- a/validation/conditional-type.c +++ b/validation/conditional-type.c @@ -79,21 +79,21 @@ static int good_if_ptr(void *ptr) * check-name: conditional-type * * check-error-start -conditional-type.c:18:18: error: incorrect type in conditional (non-scalar type) -conditional-type.c:18:18: got void -conditional-type.c:19:13: error: incorrect type in conditional (non-scalar type) -conditional-type.c:19:13: got struct state s -conditional-type.c:24:18: error: incorrect type in conditional (non-scalar type) -conditional-type.c:24:18: got void -conditional-type.c:29:21: error: incorrect type in conditional (non-scalar type) -conditional-type.c:29:21: got void -conditional-type.c:30:16: error: incorrect type in conditional (non-scalar type) -conditional-type.c:30:16: got struct state s -conditional-type.c:34:21: error: incorrect type in conditional (non-scalar type) -conditional-type.c:34:21: got void -conditional-type.c:36:20: error: incorrect type in conditional (non-scalar type) -conditional-type.c:36:20: got void -conditional-type.c:40:21: error: incorrect type in conditional (non-scalar type) -conditional-type.c:40:21: got void +conditional-type.c:18:18: error: non-scalar type in conditional: +conditional-type.c:18:18: void +conditional-type.c:19:13: error: non-scalar type in conditional: +conditional-type.c:19:13: struct state s +conditional-type.c:24:18: error: non-scalar type in conditional: +conditional-type.c:24:18: void +conditional-type.c:29:21: error: non-scalar type in conditional: +conditional-type.c:29:21: void +conditional-type.c:30:16: error: non-scalar type in conditional: +conditional-type.c:30:16: struct state s +conditional-type.c:34:21: error: non-scalar type in conditional: +conditional-type.c:34:21: void +conditional-type.c:36:20: error: non-scalar type in conditional: +conditional-type.c:36:20: void +conditional-type.c:40:21: error: non-scalar type in conditional: +conditional-type.c:40:21: void * check-error-end */ diff --git a/validation/enum-mismatch.c b/validation/enum-mismatch.c index 1bdb1d6c..a6e5d72d 100644 --- a/validation/enum-mismatch.c +++ b/validation/enum-mismatch.c @@ -12,8 +12,8 @@ static enum eb foo(enum ea a) * check-command: sparse -Wenum-mismatch $file * * check-error-start -enum-mismatch.c:7:16: warning: mixing different enum types -enum-mismatch.c:7:16: unsigned int enum ea versus -enum-mismatch.c:7:16: unsigned int enum eb +enum-mismatch.c:7:16: warning: mixing different enum types: +enum-mismatch.c:7:16: unsigned int enum ea +enum-mismatch.c:7:16: unsigned int enum eb * check-error-end */ diff --git a/validation/eval/asm-degen.c b/validation/eval/asm-degen.c new file mode 100644 index 00000000..7bbed925 --- /dev/null +++ b/validation/eval/asm-degen.c @@ -0,0 +1,36 @@ +#ifdef __CHECKER__ +#define __percpu __attribute__((noderef)) +#else +#define __percpu +#endif + +static __percpu int var; +static __percpu int arr[4]; + +static void foo(void) +{ + asm("" :: "r" (var)); +} + +static void bar(void) +{ + asm("" :: "r" (arr)); +} + +static void baz(void) +{ + asm("" :: "m" (var)); +} + +static void qux(void) +{ + asm("" :: "m" (arr)); +} + +/* + * check-name: asm-degen + * + * check-error-start +eval/asm-degen.c:12:24: warning: dereference of noderef expression + * check-error-end + */ diff --git a/validation/eval/asm-memop.c b/validation/eval/asm-memop.c new file mode 100644 index 00000000..33ba0e5a --- /dev/null +++ b/validation/eval/asm-memop.c @@ -0,0 +1,47 @@ +extern int g; + +void fo0(int *p) { asm volatile ("op %0" :: "p" (&g)); } +void fo1(int *p) { asm volatile ("op %0" :: "m" (g)); } + +void fo2(int *p) { asm volatile ("op %0" :: "p" (p)); } +void fo3(int *p) { asm volatile ("op %0" :: "m" (*p)); } + +/* + * check-name: eval-asm-memop + * check-command: test-linearize -Wno-decl $file + * + * check-output-start +fo0: +.L0: + <entry-point> + asm "op %0" + in: "p" (g) + ret + + +fo1: +.L2: + <entry-point> + asm "op %0" + in: "m" (g) + ret + + +fo2: +.L4: + <entry-point> + asm "op %0" + in: "p" (%arg1) + ret + + +fo3: +.L6: + <entry-point> + asm "op %0" + in: "m" (%arg1) + ret + + + * check-output-end + */ diff --git a/validation/expand/asm0.c b/validation/expand/asm0.c new file mode 100644 index 00000000..568a4d19 --- /dev/null +++ b/validation/expand/asm0.c @@ -0,0 +1,23 @@ +static void foo(void) +{ + asm("" :: "i" (42 & 3)); + asm("" :: "i" (__builtin_constant_p(0))); +} + +/* + * check-name: expand-asm0 + * check-command: test-linearize $file + * + * check-output-start +foo: +.L0: + <entry-point> + asm "" + in: "i" ($2) + asm "" + in: "i" ($1) + ret + + + * check-output-end + */ diff --git a/validation/expand/compound-literal.c b/validation/expand/compound-literal.c new file mode 100644 index 00000000..034164bc --- /dev/null +++ b/validation/expand/compound-literal.c @@ -0,0 +1,26 @@ +#define SAME_TYPE(A, B) \ + __builtin_types_compatible_p(A, B) + +struct s { + int i; +}; + +static void foo(struct s *p) +{ + *p = (struct s) { .i = SAME_TYPE(int, int), }; +} + +/* + * check-name: compound-literal + * check-command: test-linearize $file + * + * check-output-start +foo: +.L0: + <entry-point> + store.32 $1 -> 0[%arg1] + ret + + + * check-output-end + */ diff --git a/validation/linear/asm-memop.c b/validation/linear/asm-memop.c new file mode 100644 index 00000000..245c8d0f --- /dev/null +++ b/validation/linear/asm-memop.c @@ -0,0 +1,23 @@ +static int foo(int *p) +{ + asm("op %0" : "=m" (p[0])); + + return p[0]; +} + +/* + * check-name: linear-asm-memop + * check-command: test-linearize $file + * + * check-output-start +foo: +.L0: + <entry-point> + asm "op %0" + out: "=m" (%arg1) + load.32 %r4 <- 0[%arg1] + ret.32 %r4 + + + * check-output-end + */ diff --git a/validation/linear/compound-literal02.c b/validation/linear/compound-literal02.c index 87b98d76..6ed5809e 100644 --- a/validation/linear/compound-literal02.c +++ b/validation/linear/compound-literal02.c @@ -13,7 +13,6 @@ int bar(void) * check-name: compound-literal02.c * check-command: test-linearize -Wno-decl $file * - * check-known-to-fail * check-output-ignore * check-output-contains: ret\\..*\\$6 */ diff --git a/validation/static_assert.c b/validation/static_assert.c index d9e96294..dd5e0c08 100644 --- a/validation/static_assert.c +++ b/validation/static_assert.c @@ -61,11 +61,11 @@ static_assert.c:19:16: error: static assertion failed: "expected assertion failu static_assert.c:22:16: error: bad constant expression static_assert.c:25:16: error: bad constant expression static_assert.c:27:16: error: bad constant expression -static_assert.c:35:19: error: bad or missing string literal +static_assert.c:35:19: error: string literal expected for _Static_assert() static_assert.c:37:18: error: bad constant expression -static_assert.c:52:19: error: bad or missing string literal +static_assert.c:52:19: error: string literal expected for _Static_assert() static_assert.c:53:16: error: Expected constant expression static_assert.c:54:16: error: Expected constant expression -static_assert.c:54:17: error: bad or missing string literal +static_assert.c:54:17: error: string literal expected for _Static_assert() * check-error-end */ |
