aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmer@rivosinc.com>2022-08-16 17:33:12 -0700
committerPalmer Dabbelt <palmer@rivosinc.com>2022-08-16 17:33:12 -0700
commit8b49b855df3be25489ef82dbdb3cc913f9c4a4ca (patch)
tree7e3852c3950fae6a46db57b1088c8ce80edfa106
parent53eacc1fa688f066a5426f44fbc85710677fc172 (diff)
parent444345ff84a068d0080493fc56eb8dc9bd19a665 (diff)
downloadsparse-__archive__.tar.gz
Merge remote-tracking branch 'palmer/riscv-zicbom' into __archive____archive__
* palmer/riscv-zicbom: (32 commits) RISC-V: Add support fo the zihintpause extension RISC-V: Add support for the zicbom extension inline: free symbol list after use inline: allocate statement after guards inline: avoid needless intermediate vars inline: declaration of the variadic vars is useless inline: comment about creating node of node on variadics inline: add testcases for inlining of variadics fix "unreplaced" warnings caused by using typeof() on inline functions predefine __ATOMIC_ACQUIRE & friends as weak allow show_token() on TOKEN_ZERO_IDENT fix crash when inlining casts of erroneous expressions cgcc: do not die on '-x assembler' RISC-V: Remove "g" from the extension list RISC-V: Remove the unimplemented ISA extensions RISC-V: Match GCC's semantics for multiple -march instances RISC-V: don't die() on -march errors, just warn cast_value: remove error-prone redundant argument cast_value: assign the new type fix zero/sign extension of integer character constants ...
-rw-r--r--Documentation/release-notes/v0.6.4.rst2
-rw-r--r--builtin.c8
-rwxr-xr-xcgcc12
-rw-r--r--dissect.c61
-rw-r--r--evaluate.c2
-rw-r--r--expand.c10
-rw-r--r--expression.c9
-rw-r--r--expression.h3
-rw-r--r--inline.c25
-rw-r--r--options.c18
-rw-r--r--options.h2
-rw-r--r--parse.c8
-rw-r--r--predefine.c12
-rw-r--r--semind.c1
-rw-r--r--sparse.c2
-rw-r--r--target-riscv.c65
-rw-r--r--test-dissect.c5
-rw-r--r--token.h2
-rw-r--r--tokenize.c2
-rw-r--r--validation/builtin-objsize-self-init.c11
-rw-r--r--validation/byte-count-max.c28
-rw-r--r--validation/char-constant-signed.c9
-rw-r--r--validation/char-constant-unsigned.c9
-rw-r--r--validation/inline-early/bug-bad-token.c15
-rw-r--r--validation/inline-early/unreplaced-abstract.c28
-rw-r--r--validation/inline-early/variadic0.c13
-rw-r--r--validation/label-positioning.c22
-rw-r--r--validation/optim/devirtualize0.c17
28 files changed, 337 insertions, 64 deletions
diff --git a/Documentation/release-notes/v0.6.4.rst b/Documentation/release-notes/v0.6.4.rst
index 387870fa..08830bd8 100644
--- a/Documentation/release-notes/v0.6.4.rst
+++ b/Documentation/release-notes/v0.6.4.rst
@@ -1,4 +1,4 @@
-v0.6.4 (2020-09-06)
+v0.6.4 (2021-09-06)
===================
Fixes:
diff --git a/builtin.c b/builtin.c
index 8e1d2d7e..3a29c3ae 100644
--- a/builtin.c
+++ b/builtin.c
@@ -546,11 +546,19 @@ static int expand_object_size(struct expression *expr, int cost)
// a deref is just intermediate variable
// and so the offset needs to be zeroed.
if (arg->op == '*') {
+ struct expression *parent = arg;
arg = arg->unop;
off = 0;
switch (arg->type) {
case EXPR_SYMBOL:
arg = arg->symbol->initializer;
+ if (arg == parent) {
+ // stop at self-initialized vars
+ // and do not expand them.
+ arg = NULL;
+ val = -1;
+ break;
+ }
continue;
default:
break;
diff --git a/cgcc b/cgcc
index 9c78ee63..618ba08a 100755
--- a/cgcc
+++ b/cgcc
@@ -42,11 +42,10 @@ while (@ARGV) {
$nargs = 1;
}
- # Ignore the extension if '-x c' is given.
+ # We don't want to run the checker on non-C files.
if ($_ eq '-x') {
die ("$0: missing argument for $_") if !@ARGV;
- die ("$0: invalid argument for $_") if $ARGV[0] ne 'c';
- $do_check = 1;
+ $do_check = ($ARGV[0] eq 'c');
$nargs = 1;
}
@@ -292,6 +291,9 @@ sub add_specs {
} elsif ($spec eq 'aarch64') {
return (' --arch=aarch64' .
&float_types (1, 1, 36, [24,8], [53,11], [113,15]));
+ } elsif ($spec eq 'xtensa') {
+ return (' --arch=xtensa' .
+ &float_types (1, 1, 21, [24,8], [53,11], [53,11]));
} elsif ($spec eq 'host_os_specs') {
my $os = `uname -s`;
chomp $os;
@@ -319,6 +321,8 @@ sub add_specs {
return &add_specs ('x86_64') . ' -mx32';
} elsif ($gccmachine =~ '^x86_64-') {
return &add_specs ('x86_64');
+ } elsif ($gccmachine =~ '^xtensa-') {
+ return &add_specs ('xtensa');
}
# fall back to uname -m to determine the specifics.
@@ -348,6 +352,8 @@ sub add_specs {
return &add_specs ('arm');
} elsif ($arch =~ /^(aarch64)$/i) {
return &add_specs ('aarch64');
+ } elsif ($arch =~ /^(xtensa)$/i) {
+ return &add_specs ('xtensa');
}
} else {
die "$0: invalid specs: $spec\n";
diff --git a/dissect.c b/dissect.c
index 582e8fc3..300d5ca9 100644
--- a/dissect.c
+++ b/dissect.c
@@ -610,6 +610,16 @@ static struct symbol *do_initializer(struct symbol *type, struct expression *exp
return type;
}
+static inline bool is_macro(struct symbol *sym)
+{
+ return (sym->namespace == NS_MACRO || sym->namespace == NS_UNDEF);
+}
+
+static inline bool is_typedef(struct symbol *sym)
+{
+ return (sym->namespace == NS_TYPEDEF);
+}
+
static inline struct symbol *do_symbol(struct symbol *sym)
{
struct symbol *type = base_type(sym);
@@ -652,9 +662,58 @@ static void do_sym_list(struct symbol_list *list)
DO_LIST(list, sym, do_symbol(sym));
}
+static inline bool valid_namespace(enum namespace ns)
+{
+ return (ns == NS_TYPEDEF || ns == NS_MACRO || ns == NS_UNDEF || ns == NS_STRUCT || ns == NS_SYMBOL);
+}
+
+static void do_file(char *file)
+{
+ struct symbol_list *res = sparse_keep_tokens(file);
+
+ if (!dissect_show_all_symbols) {
+ do_sym_list(res);
+ goto end;
+ }
+
+ DO_LIST(file_scope->symbols, sym,
+ if (input_streams[sym->pos.stream].fd != -1 && valid_namespace(sym->namespace)) {
+ if (is_typedef(sym)) {
+ sym->kind = 't';
+ reporter->r_symdef(sym);
+ continue;
+ }
+
+ if (is_macro(sym)) {
+ sym->kind = 'd';
+ reporter->r_symdef(sym);
+ continue;
+ }
+
+ if (sym->type == SYM_STRUCT || sym->type == SYM_UNION) {
+ sym->ctype.base_type = sym;
+ examine_sym_node(sym, NULL);
+ continue;
+ }
+
+ do_symbol(sym);
+ }
+ );
+
+ DO_LIST(global_scope->symbols, sym,
+ if (input_streams[sym->pos.stream].fd != -1 && valid_namespace(sym->namespace)) {
+ do_symbol(sym);
+ }
+ );
+
+end:
+ /* Drop the tokens for this file after parsing */
+ clear_token_alloc();
+}
+
void dissect(struct reporter *rep, struct string_list *filelist)
{
reporter = rep;
- DO_LIST(filelist, file, do_sym_list(__sparse(file)));
+ DO_LIST(filelist, file, do_file(file));
}
diff --git a/evaluate.c b/evaluate.c
index 61f59ee3..fe716f63 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -3555,7 +3555,7 @@ static struct symbol *evaluate_symbol(struct symbol *sym)
current_fn = sym;
examine_fn_arguments(base_type);
- if (!base_type->stmt && base_type->inline_stmt)
+ if (!base_type->stmt && base_type->inline_stmt && sym->definition)
uninline(sym);
if (base_type->stmt)
evaluate_statement(base_type->stmt);
diff --git a/expand.c b/expand.c
index c4f806de..f14e7181 100644
--- a/expand.c
+++ b/expand.c
@@ -94,9 +94,9 @@ static long long get_longlong(struct expression *expr)
return (value & andmask) | ormask;
}
-void cast_value(struct expression *expr, struct symbol *newtype,
- struct expression *old, struct symbol *oldtype)
+void cast_value(struct expression *expr, struct symbol *newtype, struct expression *old)
{
+ struct symbol *oldtype = old->ctype;
int old_size = oldtype->bit_size;
int new_size = newtype->bit_size;
long long value, mask, signmask;
@@ -110,11 +110,13 @@ void cast_value(struct expression *expr, struct symbol *newtype,
expr->taint = old->taint;
if (old_size == new_size) {
expr->value = old->value;
+ expr->ctype = newtype;
return;
}
// expand it to the full "long long" value
value = get_longlong(old);
+ expr->ctype = newtype;
Int:
// _Bool requires a zero test rather than truncation.
@@ -153,6 +155,7 @@ Float:
value = (long long)old->fvalue;
expr->type = EXPR_VALUE;
expr->taint = 0;
+ expr->ctype = newtype;
goto Int;
}
@@ -168,6 +171,7 @@ Float:
expr->fvalue = (float)expr->fvalue;
}
expr->type = EXPR_FVALUE;
+ expr->ctype = newtype;
}
/* Return true if constant shift size is valid */
@@ -872,7 +876,7 @@ static int expand_cast(struct expression *expr)
/* Simplify normal integer casts.. */
if (target->type == EXPR_VALUE || target->type == EXPR_FVALUE) {
- cast_value(expr, expr->ctype, target, target->ctype);
+ cast_value(expr, expr->ctype, target);
return 0;
}
return cost + 1;
diff --git a/expression.c b/expression.c
index 221d7780..727e7056 100644
--- a/expression.c
+++ b/expression.c
@@ -427,8 +427,15 @@ struct token *primary_expression(struct token *token, struct expression **tree)
case TOKEN_CHAR ... TOKEN_WIDE_CHAR_EMBEDDED_3:
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);
+
+ // TODO: handle 'u8', 'u' & 'U' prefixes.
+ if (token_type(token) < TOKEN_WIDE_CHAR) {
+ expr->ctype = &char_ctype;
+ cast_value(expr, &int_ctype, expr);
+ } else {
+ expr->ctype = wchar_ctype;
+ }
token = token->next;
break;
diff --git a/expression.h b/expression.h
index f733c076..8bf40d32 100644
--- a/expression.h
+++ b/expression.h
@@ -337,7 +337,6 @@ struct token *compound_statement(struct token *, struct statement *);
#define constant_expression(token,tree) conditional_expression(token, tree)
/* Cast folding of constant values.. */
-void cast_value(struct expression *expr, struct symbol *newtype,
- struct expression *old, struct symbol *oldtype);
+void cast_value(struct expression *expr, struct symbol *newtype, struct expression *old);
#endif
diff --git a/inline.c b/inline.c
index eceef8ba..a7ab73d3 100644
--- a/inline.c
+++ b/inline.c
@@ -155,6 +155,8 @@ static struct expression * copy_expression(struct expression *expr)
/* Cast/sizeof/__alignof__ */
case EXPR_CAST:
+ if (!expr->cast_expression)
+ return NULL;
if (expr->cast_expression->type == EXPR_INITIALIZER) {
struct expression *cast = expr->cast_expression;
struct symbol *sym = expr->cast_type;
@@ -514,9 +516,8 @@ int inline_function(struct expression *expr, struct symbol *sym)
{
struct symbol_list * fn_symbol_list;
struct symbol *fn = sym->ctype.base_type;
- struct expression_list *arg_list = expr->args;
- struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
- struct symbol_list *name_list, *arg_decl;
+ struct statement *stmt;
+ struct symbol_list *arg_decl;
struct symbol *name;
struct expression *arg;
@@ -527,8 +528,7 @@ int inline_function(struct expression *expr, struct symbol *sym)
if (fn->expanding)
return 0;
- name_list = fn->arguments;
-
+ stmt = alloc_statement(expr->pos, STMT_COMPOUND);
expr->type = EXPR_STATEMENT;
expr->statement = stmt;
expr->ctype = fn->ctype.base_type;
@@ -536,18 +536,22 @@ int inline_function(struct expression *expr, struct symbol *sym)
fn_symbol_list = create_symbol_list(sym->inline_symbol_list);
arg_decl = NULL;
- PREPARE_PTR_LIST(name_list, name);
- FOR_EACH_PTR(arg_list, arg) {
+ PREPARE_PTR_LIST(fn->arguments, name);
+ FOR_EACH_PTR(expr->args, arg) {
struct symbol *a = alloc_symbol(arg->pos, SYM_NODE);
- a->ctype.base_type = arg->ctype;
if (name) {
*a = *name;
set_replace(name, a);
add_symbol(&fn_symbol_list, a);
+ a->initializer = arg;
+ add_symbol(&arg_decl, a);
+ } else {
+ // This may create a node of a node but it will
+ // be resolved later when the corresponding
+ // STMT_DECLARATION will be evaluated.
+ a->ctype.base_type = arg->ctype;
}
- a->initializer = arg;
- add_symbol(&arg_decl, a);
NEXT_PTR_LIST(name);
} END_FOR_EACH_PTR(arg);
@@ -563,6 +567,7 @@ int inline_function(struct expression *expr, struct symbol *sym)
stmt->inline_fn = sym;
unset_replace_list(fn_symbol_list);
+ free_ptr_list(&fn_symbol_list);
return 1;
}
diff --git a/options.c b/options.c
index 41a98240..54fa7bd3 100644
--- a/options.c
+++ b/options.c
@@ -64,6 +64,8 @@ int dbg_postorder = 0;
int dump_macro_defs = 0;
int dump_macros_only = 0;
+int dissect_show_all_symbols = 0;
+
unsigned long fdump_ir;
int fhosted = 1;
unsigned int fmax_errors = 100;
@@ -679,6 +681,19 @@ static const struct flag mflags[] = {
static char **handle_switch_m(char *arg, char **next)
{
+ if (!strcmp(arg, "meabi") && next[1] && next[1][0] != '-') {
+ // clang has such an option with syntax: -meabi <arg>
+ // It's used by the kernel for armv7.
+ // GCC has the same option but with no argument.
+ // Parse it here to consume the possible argument.
+ static const char *valid[] = { "gnu", "4", "5", "default", NULL };
+ int i;
+ for (i = 0; valid[i]; i++) {
+ if (!strcmp(next[1], valid[i]))
+ return ++next;
+ }
+ }
+
if (!strcmp(arg, "multiarch-dir")) {
return handle_multiarch_dir(arg, next);
} else {
@@ -952,6 +967,9 @@ static char **handle_param(char *arg, char **next)
if (!value)
die("missing argument for --param option");
+ if (!strcmp(value, "dissect-show-all-symbols"))
+ dissect_show_all_symbols = 1;
+
return next;
}
diff --git a/options.h b/options.h
index 0aec8764..c2a9551a 100644
--- a/options.h
+++ b/options.h
@@ -70,6 +70,8 @@ extern int dbg_postorder;
extern int dump_macro_defs;
extern int dump_macros_only;
+extern int dissect_show_all_symbols;
+
extern unsigned long fdump_ir;
extern int fhosted;
extern unsigned int fmax_errors;
diff --git a/parse.c b/parse.c
index bc1c0602..3d6fef7c 100644
--- a/parse.c
+++ b/parse.c
@@ -903,8 +903,7 @@ static void cast_enum_list(struct symbol_list *list, struct symbol *base_type)
expr->ctype = &int_ctype;
continue;
}
- cast_value(expr, base_type, expr, ctype);
- expr->ctype = base_type;
+ cast_value(expr, base_type, expr);
} END_FOR_EACH_PTR(sym);
}
@@ -2329,6 +2328,11 @@ static inline struct token *case_statement(struct token *token, struct statement
stmt->type = STMT_CASE;
token = expect(token, ':', "after default/case");
add_case_statement(stmt);
+ if (match_op(token, '}')) {
+ warning(token->pos, "statement expected after case label");
+ stmt->case_statement = alloc_statement(token->pos, STMT_NONE);
+ return token;
+ }
return statement(token, &stmt->case_statement);
}
diff --git a/predefine.c b/predefine.c
index 98e38a04..5b0f0caf 100644
--- a/predefine.c
+++ b/predefine.c
@@ -179,12 +179,12 @@ void predefined_macros(void)
if (arch_target->has_int128)
predefined_sizeof("INT128", "", 128);
- predefine("__ATOMIC_RELAXED", 0, "0");
- predefine("__ATOMIC_CONSUME", 0, "1");
- predefine("__ATOMIC_ACQUIRE", 0, "3");
- predefine("__ATOMIC_RELEASE", 0, "4");
- predefine("__ATOMIC_ACQ_REL", 0, "7");
- predefine("__ATOMIC_SEQ_CST", 0, "8");
+ predefine("__ATOMIC_RELAXED", 1, "0");
+ predefine("__ATOMIC_CONSUME", 1, "1");
+ predefine("__ATOMIC_ACQUIRE", 1, "3");
+ predefine("__ATOMIC_RELEASE", 1, "4");
+ predefine("__ATOMIC_ACQ_REL", 1, "7");
+ predefine("__ATOMIC_SEQ_CST", 1, "8");
predefine("__ORDER_LITTLE_ENDIAN__", 1, "1234");
predefine("__ORDER_BIG_ENDIAN__", 1, "4321");
diff --git a/semind.c b/semind.c
index 911fc747..ad8003ba 100644
--- a/semind.c
+++ b/semind.c
@@ -329,6 +329,7 @@ done:
optind--;
sparse_initialize(argc - optind, argv + optind, &semind_filelist);
+ dissect_show_all_symbols = 1;
}
static void parse_cmdline_rm(int argc, char **argv)
diff --git a/sparse.c b/sparse.c
index 9d62d4fe..e7cc6f55 100644
--- a/sparse.c
+++ b/sparse.c
@@ -165,7 +165,7 @@ static void check_byte_count(struct instruction *insn, pseudo_t count)
static void check_memset(struct instruction *insn)
{
- check_byte_count(insn, ptr_list_nth(insn->arguments, 3));
+ check_byte_count(insn, ptr_list_nth(insn->arguments, 2));
}
#define check_memcpy check_memset
diff --git a/target-riscv.c b/target-riscv.c
index ff4dfba3..23d28d0e 100644
--- a/target-riscv.c
+++ b/target-riscv.c
@@ -5,20 +5,22 @@
#include <string.h>
#include <stdio.h>
-#define RISCV_32BIT (1 << 0)
-#define RISCV_64BIT (1 << 1)
-#define RISCV_MUL (1 << 2)
-#define RISCV_DIV (1 << 3)
-#define RISCV_ATOMIC (1 << 4)
-#define RISCV_FLOAT (1 << 5)
-#define RISCV_DOUBLE (1 << 6)
-#define RISCV_FDIV (1 << 7)
-#define RISCV_COMP (1 << 8)
-#define RISCV_EMBD (1 << 9)
-#define RISCV_FPU (RISCV_FLOAT|RISCV_DOUBLE|RISCV_FDIV)
-#define RISCV_GENERIC (RISCV_MUL|RISCV_DIV|RISCV_ATOMIC|RISCV_FPU)
-#define RISCV_ZICSR (1 << 10)
-#define RISCV_ZIFENCEI (1 << 11)
+#define RISCV_32BIT (1 << 0)
+#define RISCV_64BIT (1 << 1)
+#define RISCV_MUL (1 << 2)
+#define RISCV_DIV (1 << 3)
+#define RISCV_ATOMIC (1 << 4)
+#define RISCV_FLOAT (1 << 5)
+#define RISCV_DOUBLE (1 << 6)
+#define RISCV_FDIV (1 << 7)
+#define RISCV_COMP (1 << 8)
+#define RISCV_EMBD (1 << 9)
+#define RISCV_FPU (RISCV_FLOAT|RISCV_DOUBLE|RISCV_FDIV)
+#define RISCV_GENERIC (RISCV_MUL|RISCV_DIV|RISCV_ATOMIC|RISCV_FPU)
+#define RISCV_ZICSR (1 << 10)
+#define RISCV_ZIFENCEI (1 << 11)
+#define RISCV_ZICBOM (1 << 12)
+#define RISCV_ZIHINTPAUSE (1 << 13)
static unsigned int riscv_flags;
@@ -34,37 +36,34 @@ static void parse_march_riscv(const char *arg)
{ "rv64i", RISCV_64BIT },
{ "rv64g", RISCV_64BIT|RISCV_GENERIC },
}, extensions[] = {
- { "m", RISCV_MUL|RISCV_DIV },
- { "a", RISCV_ATOMIC },
- { "f", RISCV_FLOAT|RISCV_FDIV|RISCV_ZICSR },
- { "d", RISCV_DOUBLE|RISCV_FDIV|RISCV_ZICSR },
- { "c", RISCV_COMP },
- { "_zicsr", RISCV_ZICSR },
- { "_zifencei", RISCV_ZIFENCEI },
+ { "m", RISCV_MUL|RISCV_DIV },
+ { "a", RISCV_ATOMIC },
+ { "f", RISCV_FLOAT|RISCV_FDIV|RISCV_ZICSR },
+ { "d", RISCV_DOUBLE|RISCV_FDIV|RISCV_ZICSR },
+ { "c", RISCV_COMP },
+ { "_zicsr", RISCV_ZICSR },
+ { "_zifencei", RISCV_ZIFENCEI },
+ { "_zicbom", RISCV_ZICBOM },
+ { "_zihintpause", RISCV_ZIHINTPAUSE },
};
int i;
+ // Each -march=.. options entirely overrides previous ones
+ riscv_flags = 0;
+
for (i = 0; i < ARRAY_SIZE(basic_sets); i++) {
const char *pat = basic_sets[i].pattern;
size_t len = strlen(pat);
if (!strncmp(arg, pat, len)) {
- riscv_flags = basic_sets[i].flags;
+ riscv_flags |= basic_sets[i].flags;
arg += len;
goto ext;
}
}
unknown:
- /*
- * This behaves like do_warn() / do_error(), but we don't have a
- * position so it's just inline here.
- */
- fflush(stdout);
- fprintf(stderr, "%s: invalid argument to '-march': '%s'\n",
- Wsparse_error == FLAG_ON ? "error" : "warning", arg);
- if (Wsparse_error == FLAG_ON)
- has_error |= ERROR_CURR_PHASE;
+ fprintf(stderr, "WARNING: invalid argument to '-march': '%s'\n", arg);
return;
ext:
@@ -136,6 +135,10 @@ static void predefine_riscv(const struct target *self)
predefine("__riscv_zicsr", 1, "1");
if (riscv_flags & RISCV_ZIFENCEI)
predefine("__riscv_zifencei", 1, "1");
+ if (riscv_flags & RISCV_ZICBOM)
+ predefine("__riscv_zicbom", 1, "1");
+ if (riscv_flags & RISCV_ZIHINTPAUSE)
+ predefine("__riscv_zihintpause", 1, "1");
if (cmodel)
predefine_strong("__riscv_cmodel_%s", cmodel);
diff --git a/test-dissect.c b/test-dissect.c
index 58b3e633..65b205f8 100644
--- a/test-dissect.c
+++ b/test-dissect.c
@@ -57,11 +57,14 @@ static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym)
show_typename(sym->ctype.base_type));
switch (sym->kind) {
+ case 'd':
+ break;
case 's':
if (sym->type == SYM_STRUCT || sym->type == SYM_UNION)
break;
goto err;
-
+ case 't':
+ break;
case 'f':
if (sym->type != SYM_BAD && sym->ctype.base_type->type != SYM_FN)
goto err;
diff --git a/token.h b/token.h
index bccac0e4..9000e0cb 100644
--- a/token.h
+++ b/token.h
@@ -201,7 +201,7 @@ struct token {
static inline struct token *containing_token(struct token **p)
{
- void *addr = (char *)p - ((char *)&((struct token *)0)->next - (char *)0);
+ void *addr = (char *)p - offsetof(struct token, next);
return addr;
}
diff --git a/tokenize.c b/tokenize.c
index ea710543..fdaea370 100644
--- a/tokenize.c
+++ b/tokenize.c
@@ -201,6 +201,7 @@ const char *show_token(const struct token *token)
return "end-of-input";
case TOKEN_IDENT:
+ case TOKEN_ZERO_IDENT:
return show_ident(token->ident);
case TOKEN_NUMBER:
@@ -259,6 +260,7 @@ const char *quote_token(const struct token *token)
return "syntax error";
case TOKEN_IDENT:
+ case TOKEN_ZERO_IDENT:
return show_ident(token->ident);
case TOKEN_NUMBER:
diff --git a/validation/builtin-objsize-self-init.c b/validation/builtin-objsize-self-init.c
new file mode 100644
index 00000000..77e3da43
--- /dev/null
+++ b/validation/builtin-objsize-self-init.c
@@ -0,0 +1,11 @@
+static void f(void)
+{
+ void *param = param;
+ __builtin_object_size(param, 0);
+}
+
+/*
+ * check-name: builtin-objsize-self-init
+ * check-timeout:
+ * check-error-end
+ */
diff --git a/validation/byte-count-max.c b/validation/byte-count-max.c
new file mode 100644
index 00000000..0555a505
--- /dev/null
+++ b/validation/byte-count-max.c
@@ -0,0 +1,28 @@
+typedef unsigned long int size_t;
+typedef unsigned long ulong;
+
+extern void *memset(void *s, int c, size_t n);
+extern void *memcpy(void *dest, void *src, size_t n);
+extern ulong copy_to_user(void *to, const void *from, ulong count);
+extern ulong copy_from_user(void *to, const void *from, ulong count);
+
+static void func (char *s)
+{
+ char d[250000];
+
+ memset(d, 0, 250000);
+ memcpy(d, s, 250000);
+ copy_to_user(s, d, 250000);
+ copy_from_user(d, s, 250000);
+}
+
+/*
+ * check-name: byte-count-max
+ *
+ * check-error-start
+byte-count-max.c:13:15: warning: memset with byte count of 250000
+byte-count-max.c:14:15: warning: memcpy with byte count of 250000
+byte-count-max.c:15:21: warning: copy_to_user with byte count of 250000
+byte-count-max.c:16:23: warning: copy_from_user with byte count of 250000
+ * check-error-end
+ */
diff --git a/validation/char-constant-signed.c b/validation/char-constant-signed.c
new file mode 100644
index 00000000..be0fd5ce
--- /dev/null
+++ b/validation/char-constant-signed.c
@@ -0,0 +1,9 @@
+int test(void) { return '\377' == -1; }
+
+/*
+ * check-name: char-constant-signed
+ * check-command: test-linearize -Wno-decl -fsigned-char $file
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/char-constant-unsigned.c b/validation/char-constant-unsigned.c
new file mode 100644
index 00000000..d5642b16
--- /dev/null
+++ b/validation/char-constant-unsigned.c
@@ -0,0 +1,9 @@
+int test(void) { return '\377' == 255; }
+
+/*
+ * check-name: char-constant-unsigned
+ * check-command: test-linearize -Wno-decl -funsigned-char $file
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/inline-early/bug-bad-token.c b/validation/inline-early/bug-bad-token.c
new file mode 100644
index 00000000..9049bdb4
--- /dev/null
+++ b/validation/inline-early/bug-bad-token.c
@@ -0,0 +1,15 @@
+inline void fun(int x)
+{
+ (typeof(@)) x;
+}
+
+void foo(void)
+{
+ fun;
+}
+
+/*
+ * check-name: bug-bad-token
+ * check-exit-value: 0
+ * check-error-ignore
+ */
diff --git a/validation/inline-early/unreplaced-abstract.c b/validation/inline-early/unreplaced-abstract.c
new file mode 100644
index 00000000..e38cd668
--- /dev/null
+++ b/validation/inline-early/unreplaced-abstract.c
@@ -0,0 +1,28 @@
+static inline void f0(void) { }
+static inline long f1(long a) { return a + 1;}
+
+_Static_assert([typeof(f0)] != [typeof(f1)]);
+
+
+static inline void g0(void) { }
+static inline long g1(long a) { return a + 1;}
+
+extern long goo(long a);
+long goo(long a)
+{
+ g0();
+ return g1(a);
+}
+
+_Static_assert([typeof(g0)] != [typeof(g1)]);
+
+extern long moo(long a);
+long moo(long a)
+{
+ typeof(f1) *f = g1;
+ return f(a);
+}
+
+/*
+ * check-name: unreplaced-abstract
+ */
diff --git a/validation/inline-early/variadic0.c b/validation/inline-early/variadic0.c
new file mode 100644
index 00000000..566e129f
--- /dev/null
+++ b/validation/inline-early/variadic0.c
@@ -0,0 +1,13 @@
+static inline void fun(const char *fmt, ...)
+{
+}
+
+void main(void)
+{
+ fun("abc", 0); // will be a SYM_BASETYPE
+ fun("ijk", (const int)1); // will be a SYM_NODE
+}
+
+/*
+ * check-name: variadic0
+ */
diff --git a/validation/label-positioning.c b/validation/label-positioning.c
new file mode 100644
index 00000000..583661ca
--- /dev/null
+++ b/validation/label-positioning.c
@@ -0,0 +1,22 @@
+extern int someval(void);
+
+static void func (int x)
+{
+ if (x > someval())
+ goto end;
+ switch (x) { case 0: }
+ switch (x) { case 1 ... 9: }
+ switch (x) { default: }
+end:
+}
+
+/*
+ * check-name: label-positioning
+ *
+ * check-error-start
+label-positioning.c:7:30: warning: statement expected after case label
+label-positioning.c:8:36: warning: statement expected after case label
+label-positioning.c:9:31: warning: statement expected after case label
+label-positioning.c:11:1: warning: statement expected after label
+ * check-error-end
+ */
diff --git a/validation/optim/devirtualize0.c b/validation/optim/devirtualize0.c
new file mode 100644
index 00000000..7079e790
--- /dev/null
+++ b/validation/optim/devirtualize0.c
@@ -0,0 +1,17 @@
+static inline long f1(long x) { return x + 1;}
+
+extern long foo(long a);
+long foo(long a)
+{
+ typeof(f1) *f = f1;
+ return f(a);
+}
+
+/*
+ * check-name: devirtualize0
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: call\\.
+ */