aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--allocate.c1
-rw-r--r--allocate.h1
-rw-r--r--dissect.c8
-rw-r--r--evaluate.c158
-rw-r--r--expand.c29
-rw-r--r--expression.c11
-rw-r--r--expression.h20
-rw-r--r--inline.c28
-rw-r--r--lib.h2
-rw-r--r--linearize.c48
-rw-r--r--linearize.h1
-rw-r--r--liveness.c5
-rw-r--r--parse.c22
-rw-r--r--parse.h4
-rw-r--r--show-parse.c3
-rw-r--r--validation/asm-bad0.c41
-rw-r--r--validation/bad-type-twice0.c4
-rw-r--r--validation/bad-type-twice1.c6
-rw-r--r--validation/compare-null-to-int.c6
-rw-r--r--validation/cond_expr.c4
-rw-r--r--validation/conditional-type.c32
-rw-r--r--validation/enum-mismatch.c6
-rw-r--r--validation/eval/asm-degen.c36
-rw-r--r--validation/eval/asm-memop.c47
-rw-r--r--validation/expand/asm0.c23
-rw-r--r--validation/expand/compound-literal.c26
-rw-r--r--validation/linear/asm-memop.c23
-rw-r--r--validation/linear/compound-literal02.c1
-rw-r--r--validation/static_assert.c6
29 files changed, 455 insertions, 147 deletions
diff --git a/allocate.c b/allocate.c
index 152fa896..bef85192 100644
--- a/allocate.c
+++ b/allocate.c
@@ -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");
diff --git a/allocate.h b/allocate.h
index 5137ae93..a6d30537 100644
--- a/allocate.h
+++ b/allocate.h
@@ -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);
diff --git a/dissect.c b/dissect.c
index 5f067eb4..14d57bf5 100644
--- a/dissect.c
+++ b/dissect.c
@@ -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)
diff --git a/evaluate.c b/evaluate.c
index d52fd9f9..919c944c 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -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) {
diff --git a/expand.c b/expand.c
index 455d5bae..d66375f4 100644
--- a/expand.c
+++ b/expand.c
@@ -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 *);
diff --git a/inline.c b/inline.c
index fcc43db5..6f73a305 100644
--- a/inline.c
+++ b/inline.c
@@ -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;
}
diff --git a/lib.h b/lib.h
index 322408be..697c977a 100644
--- a/lib.h
+++ b/lib.h
@@ -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);
diff --git a/liveness.c b/liveness.c
index 93a7cc30..33cd0483 100644
--- a/liveness.c
+++ b/liveness.c
@@ -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);
}
diff --git a/parse.c b/parse.c
index b01c876e..ac795bd7 100644
--- a/parse.c
+++ b/parse.c
@@ -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()");
diff --git a/parse.h b/parse.h
index 505c91c2..0742a2a8 100644
--- a/parse.h
+++ b/parse.h
@@ -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
*/