aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--.gitignore1
-rw-r--r--Makefile4
-rwxr-xr-xcgcc2
-rw-r--r--evaluate.c34
-rw-r--r--expand.c28
-rw-r--r--gcc-attr-list.h1
-rw-r--r--linearize.c8
-rw-r--r--parse.c20
-rw-r--r--sparse.115
-rw-r--r--symbol.h4
-rw-r--r--validation/Waddress-space-all-attr.c14
-rw-r--r--validation/Waddress-space-from.c63
-rw-r--r--validation/Waddress-space-strict.c1
-rw-r--r--validation/Wcast-to-as.c36
-rw-r--r--validation/constexpr-constcond.c10
-rw-r--r--validation/constexpr-shift.c12
-rw-r--r--validation/enum-sign-extend.c12
-rw-r--r--validation/eval-bad-assign1.c14
-rw-r--r--validation/eval-bad-assign2.c22
-rw-r--r--validation/expand/bad-shift.c64
-rw-r--r--validation/ioc-typecheck.c4
21 files changed, 321 insertions, 48 deletions
diff --git a/.gitignore b/.gitignore
index 5569f98b..7565fd56 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
*.so
.*.swp
*.pyc
+*~
# generated
version.h
diff --git a/Makefile b/Makefile
index a1d86c52..7e8c2abc 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.6.0
+VERSION=0.6.1-rc1
########################################################################
# The following variables can be overwritten from the command line
@@ -165,7 +165,7 @@ ifeq ($(shell expr "$(LLVM_VERSION)" : '[3-9]\.'),2)
LLVM_PROGS := sparse-llvm
$(LLVM_PROGS): LD := g++
LLVM_LDFLAGS := $(shell $(LLVM_CONFIG) --ldflags)
-LLVM_CFLAGS := -I$(shell $(LLVM_CONFIG) --includedir)
+LLVM_CFLAGS := $(shell $(LLVM_CONFIG) --cppflags)
LLVM_LIBS := $(shell $(LLVM_CONFIG) --libs)
LLVM_LIBS += $(shell $(LLVM_CONFIG) --system-libs 2>/dev/null)
LLVM_LIBS += $(shell $(LLVM_CONFIG) --cxxflags | grep -F -q -e '-stdlib=libc++' && echo -lc++)
diff --git a/cgcc b/cgcc
index add35cba..122f6e27 100755
--- a/cgcc
+++ b/cgcc
@@ -52,7 +52,7 @@ while (@ARGV) {
$m32 = 1 if /^-m32$/;
$m64 = 1 if /^-m64$/;
- $gendeps = 1 if /^-(M|MM|MD|MMD)$/;
+ $gendeps = 1 if /^-(M|MM)$/;
if (/^-target=(.*)$/) {
$check .= &add_specs ($1);
diff --git a/evaluate.c b/evaluate.c
index 15726069..919c944c 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1178,20 +1178,22 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
expr->flags = (expr->conditional->flags & (*cond)->flags &
expr->cond_false->flags & ~CEF_CONST_MASK);
/*
- * A conditional operator yields a particular constant
- * expression type only if all of its three subexpressions are
- * of that type [6.6(6), 6.6(8)].
- * As an extension, relax this restriction by allowing any
- * constant expression type for the condition expression.
- *
- * A conditional operator never yields an address constant
- * [6.6(9)].
- * However, as an extension, if the condition is any constant
- * expression, and the true and false expressions are both
- * address constants, mark the result as an address constant.
+ * In the standard, it is defined that an integer constant expression
+ * shall only have operands that are themselves constant [6.6(6)].
+ * While this definition is very clear for expressions that need all
+ * their operands to be evaluated, for conditional expressions with a
+ * constant condition things are much less obvious.
+ * So, as an extension, do the same as GCC seems to do:
+ * Consider a conditional expression with a constant condition
+ * as having the same constantness as the argument corresponding
+ * to the truth value (including in the case of address constants
+ * which are defined more stricly [6.6(9)]).
*/
- if (expr->conditional->flags & (CEF_ACE | CEF_ADDR))
- expr->flags = (*cond)->flags & expr->cond_false->flags & ~CEF_CONST_MASK;
+ if (expr->conditional->flags & (CEF_ACE | CEF_ADDR)) {
+ int is_true = expr_truth_value(expr->conditional);
+ struct expression *arg = is_true ? *cond : expr->cond_false;
+ expr->flags = arg->flags & ~CEF_CONST_MASK;
+ }
lclass = classify_type(ltype, &ltype);
rclass = classify_type(rtype, &rtype);
@@ -3016,14 +3018,14 @@ static struct symbol *evaluate_cast(struct expression *expr)
}
}
- if (ttype == &ulong_ctype && !Wcast_from_as)
+ if ((ttype == &ulong_ctype || ttype == uintptr_ctype) && !Wcast_from_as)
tas = &bad_address_space;
else if (tclass == TYPE_PTR) {
examine_pointer_target(ttype);
tas = ttype->ctype.as;
}
- if (stype == &ulong_ctype && !Wcast_from_as)
+ if ((stype == &ulong_ctype || stype == uintptr_ctype))
sas = &bad_address_space;
else if (sclass == TYPE_PTR) {
examine_pointer_target(stype);
@@ -3385,7 +3387,7 @@ void check_duplicates(struct symbol *sym)
}
if (!declared) {
unsigned long mod = sym->ctype.modifiers;
- if (mod & (MOD_STATIC | MOD_REGISTER))
+ if (mod & (MOD_STATIC | MOD_REGISTER | MOD_EXT_VISIBLE))
return;
if (!(mod & MOD_TOPLEVEL))
return;
diff --git a/expand.c b/expand.c
index ac6686e4..d66375f4 100644
--- a/expand.c
+++ b/expand.c
@@ -47,6 +47,11 @@
static int expand_expression(struct expression *);
static int expand_statement(struct statement *);
+
+// If set, don't issue a warning on divide-by-0, invalid shift, ...
+// and don't mark the expression as erroneous but leave it as-is.
+// This allows testing some characteristics of the expression
+// without creating any side-effects (e.g.: is_zero_constant()).
static int conservative;
static int expand_symbol_expression(struct expression *expr)
@@ -166,19 +171,14 @@ Float:
expr->type = EXPR_FVALUE;
}
-static void check_shift_count(struct expression *expr, struct expression *right)
+static void warn_shift_count(struct expression *expr, struct symbol *ctype, long long count)
{
- struct symbol *ctype = expr->ctype;
- long long count = get_longlong(right);
-
if (count < 0) {
if (!Wshift_count_negative)
return;
warning(expr->pos, "shift count is negative (%lld)", count);
return;
}
- if (count < ctype->bit_size)
- return;
if (ctype->type == SYM_NODE)
ctype = ctype->ctype.base_type;
@@ -187,6 +187,19 @@ static void check_shift_count(struct expression *expr, struct expression *right)
warning(expr->pos, "shift too big (%llu) for type %s", count, show_typename(ctype));
}
+/* Return true if constant shift size is valid */
+static bool check_shift_count(struct expression *expr, struct expression *right)
+{
+ struct symbol *ctype = expr->ctype;
+ long long count = get_longlong(right);
+
+ if (count >= 0 && count < ctype->bit_size)
+ return true;
+ if (!conservative)
+ warn_shift_count(expr, ctype, count);
+ return false;
+}
+
/*
* CAREFUL! We need to get the size and sign of the
* result right!
@@ -205,9 +218,8 @@ static int simplify_int_binop(struct expression *expr, struct symbol *ctype)
return 0;
r = right->value;
if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
- if (conservative)
+ if (!check_shift_count(expr, right))
return 0;
- check_shift_count(expr, right);
}
if (left->type != EXPR_VALUE)
return 0;
diff --git a/gcc-attr-list.h b/gcc-attr-list.h
index 8da31435..c7800175 100644
--- a/gcc-attr-list.h
+++ b/gcc-attr-list.h
@@ -42,7 +42,6 @@ GCC_ATTR(either)
GCC_ATTR(error)
GCC_ATTR(exception)
GCC_ATTR(exception_handler)
-GCC_ATTR(externally_visible)
GCC_ATTR(far)
GCC_ATTR(fast_interrupt)
GCC_ATTR(fastcall)
diff --git a/linearize.c b/linearize.c
index 09b1c7ee..30ed2a30 100644
--- a/linearize.c
+++ b/linearize.c
@@ -1764,7 +1764,7 @@ static pseudo_t linearize_cond_branch(struct entrypoint *ep, struct expression *
{
pseudo_t cond;
- if (!expr || !bb_reachable(ep->active))
+ if (!expr || !valid_type(expr->ctype) || !bb_reachable(ep->active))
return VOID;
switch (expr->type) {
@@ -1864,7 +1864,7 @@ static void linearize_argument(struct entrypoint *ep, struct symbol *arg, int nr
static pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr)
{
- if (!expr)
+ if (!expr || !valid_type(expr->ctype))
return VOID;
current_pos = expr->pos;
@@ -2419,6 +2419,10 @@ static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stm
bb_true = alloc_basic_block(ep, stmt->pos);
bb_false = endif = alloc_basic_block(ep, stmt->pos);
+ // If the condition is invalid, the following
+ // statement(s) are not evaluated.
+ if (!cond || !valid_type(cond->ctype))
+ return VOID;
linearize_cond_branch(ep, cond, bb_true, bb_false);
set_activeblock(ep, bb_true);
diff --git a/parse.c b/parse.c
index d132a15a..ac795bd7 100644
--- a/parse.c
+++ b/parse.c
@@ -82,6 +82,7 @@ typedef struct token *attr_t(struct token *, struct symbol *,
static attr_t
attribute_packed, attribute_aligned, attribute_modifier,
+ attribute_ext_visible,
attribute_bitwise,
attribute_address_space, attribute_context,
attribute_designated_init,
@@ -373,6 +374,10 @@ static struct symbol_op attr_mod_op = {
.attribute = attribute_modifier,
};
+static struct symbol_op ext_visible_op = {
+ .attribute = attribute_ext_visible,
+};
+
static struct symbol_op attr_bitwise_op = {
.attribute = attribute_bitwise,
};
@@ -562,6 +567,8 @@ static struct init_keyword {
{"const", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op },
{"__const", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op },
{"__const__", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op },
+ {"externally_visible", NS_KEYWORD, .op = &ext_visible_op },
+ {"__externally_visible__", NS_KEYWORD, .op = &ext_visible_op },
{ "mode", NS_KEYWORD, .op = &mode_op },
{ "__mode__", NS_KEYWORD, .op = &mode_op },
@@ -890,10 +897,8 @@ static void cast_enum_list(struct symbol_list *list, struct symbol *base_type)
expr->ctype = &int_ctype;
continue;
}
- expr->ctype = base_type;
- if (ctype->bit_size == base_type->bit_size)
- continue;
cast_value(expr, base_type, expr, ctype);
+ expr->ctype = base_type;
} END_FOR_EACH_PTR(sym);
}
@@ -1106,6 +1111,12 @@ static struct token *attribute_modifier(struct token *token, struct symbol *attr
return token;
}
+static struct token *attribute_ext_visible(struct token *token, struct symbol *attr, struct decl_state *ctx)
+{
+ ctx->is_ext_visible = 1;
+ return token;
+}
+
static struct token *attribute_bitwise(struct token *token, struct symbol *attr, struct decl_state *ctx)
{
if (Wbitwise)
@@ -1343,7 +1354,8 @@ static unsigned long storage_modifiers(struct decl_state *ctx)
[SRegister] = MOD_REGISTER
};
return mod[ctx->storage_class] | (ctx->is_inline ? MOD_INLINE : 0)
- | (ctx->is_tls ? MOD_TLS : 0);
+ | (ctx->is_tls ? MOD_TLS : 0)
+ | (ctx->is_ext_visible ? MOD_EXT_VISIBLE : 0);
}
static void set_storage_class(struct position *pos, struct decl_state *ctx, int class)
diff --git a/sparse.1 b/sparse.1
index fae6196b..beb48442 100644
--- a/sparse.1
+++ b/sparse.1
@@ -41,9 +41,16 @@ Sparse allows an extended attribute
on pointers, which designates a pointer target in address space \fIid\fR (an
identifier or a constant integer).
With \fB\-Waddress\-space\fR, Sparse treats pointers with
-identical target types but different address spaces as distinct types. To
-override this warning, such as for functions which convert pointers between
-address spaces, use a type that includes \fB__attribute__((force))\fR.
+identical target types but different address spaces as distinct types and
+will warn accordingly.
+
+Sparse will also warn on casts which remove the address space (casts to an
+integer type or to a plain pointer type). An exception to this is when the
+destination type is \fBuintptr_t\fR (or \fBunsigned long\fR) since such casts
+are often used to "get a pointer value representation in an integer type" and
+such values are independent of the address space.
+
+To override these warnings, use a type that includes \fB__attribute__((force))\fR.
Sparse issues these warnings by default. To turn them off, use
\fB\-Wno\-address\-space\fR.
@@ -97,6 +104,8 @@ Sparse does not issues these warnings by default.
Warn about casts which add an address space to a pointer type.
A cast that includes \fB__attribute__((force))\fR will suppress this warning.
+No warning is generated if the original type is \fBuintptr_t\fR
+(or \fBunsigned long\fR).
Sparse does not issue these warnings by default.
.
diff --git a/symbol.h b/symbol.h
index 51e1c867..ac43b314 100644
--- a/symbol.h
+++ b/symbol.h
@@ -110,6 +110,7 @@ struct decl_state {
struct ident **ident;
struct symbol_op *mode;
unsigned char prefer_abstract, is_inline, storage_class, is_tls;
+ unsigned char is_ext_visible;
};
struct symbol_op {
@@ -237,6 +238,7 @@ struct symbol {
#define MOD_NOCAST 0x04000000
#define MOD_NODEREF 0x08000000
#define MOD_NORETURN 0x10000000
+#define MOD_EXT_VISIBLE 0x20000000
#define MOD_ACCESS (MOD_ASSIGNED | MOD_ADDRESSABLE)
@@ -246,7 +248,7 @@ struct symbol {
#define MOD_LONG_ALL (MOD_LONG | MOD_LONGLONG | MOD_LONGLONGLONG)
#define MOD_SPECIFIER (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL | MOD_SIGNEDNESS)
#define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL)
-#define MOD_IGNORE (MOD_STORAGE | MOD_ACCESS | MOD_USERTYPE | MOD_EXPLICITLY_SIGNED)
+#define MOD_IGNORE (MOD_STORAGE | MOD_ACCESS | MOD_USERTYPE | MOD_EXPLICITLY_SIGNED | MOD_EXT_VISIBLE)
#define MOD_QUALIFIER (MOD_CONST | MOD_VOLATILE | MOD_RESTRICT | MOD_ATOMIC)
#define MOD_PTRINHERIT (MOD_QUALIFIER | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST)
/* modifiers preserved by typeof() operator */
diff --git a/validation/Waddress-space-all-attr.c b/validation/Waddress-space-all-attr.c
index 5b2d0f92..b0c17693 100644
--- a/validation/Waddress-space-all-attr.c
+++ b/validation/Waddress-space-all-attr.c
@@ -13,27 +13,27 @@ static void expl(obj_t __kernel *k, obj_t __iomem *o,
obj_t __user *p, obj_t __percpu *pc,
obj_t __rcu *r)
{
- (ulong)(k);
+ (ulong)(k); (__UINTPTR_TYPE__)(k);
(void *)(k);
(obj_t*)(k);
(obj_t __kernel*)(k);
- (ulong)(o);
+ (ulong)(o); (__UINTPTR_TYPE__)(o);
(void *)(o);
(obj_t*)(o);
(obj_t __iomem*)(o);
- (ulong)(p);
+ (ulong)(p); (__UINTPTR_TYPE__)(p);
(void *)(p);
(obj_t*)(p);
(obj_t __user*)(p);
- (ulong)(pc);
+ (ulong)(pc); (__UINTPTR_TYPE__)(pc);
(void *)(pc);
(obj_t*)(pc);
(obj_t __percpu*)(pc);
- (ulong)(r);
+ (ulong)(r); (__UINTPTR_TYPE__)(r);
(void *)(r);
(obj_t*)(r);
(obj_t __rcu*)(r);
@@ -45,15 +45,19 @@ static void expl(obj_t __kernel *k, obj_t __iomem *o,
*
* check-error-start
Waddress-space-all-attr.c:21:10: warning: cast removes address space '<asn:2>' of expression
+Waddress-space-all-attr.c:21:22: warning: cast removes address space '<asn:2>' of expression
Waddress-space-all-attr.c:22:10: warning: cast removes address space '<asn:2>' of expression
Waddress-space-all-attr.c:23:10: warning: cast removes address space '<asn:2>' of expression
Waddress-space-all-attr.c:26:10: warning: cast removes address space '<asn:1>' of expression
+Waddress-space-all-attr.c:26:22: warning: cast removes address space '<asn:1>' of expression
Waddress-space-all-attr.c:27:10: warning: cast removes address space '<asn:1>' of expression
Waddress-space-all-attr.c:28:10: warning: cast removes address space '<asn:1>' of expression
Waddress-space-all-attr.c:31:10: warning: cast removes address space '<asn:3>' of expression
+Waddress-space-all-attr.c:31:23: warning: cast removes address space '<asn:3>' of expression
Waddress-space-all-attr.c:32:10: warning: cast removes address space '<asn:3>' of expression
Waddress-space-all-attr.c:33:10: warning: cast removes address space '<asn:3>' of expression
Waddress-space-all-attr.c:36:10: warning: cast removes address space '<asn:4>' of expression
+Waddress-space-all-attr.c:36:22: warning: cast removes address space '<asn:4>' of expression
Waddress-space-all-attr.c:37:10: warning: cast removes address space '<asn:4>' of expression
Waddress-space-all-attr.c:38:10: warning: cast removes address space '<asn:4>' of expression
* check-error-end
diff --git a/validation/Waddress-space-from.c b/validation/Waddress-space-from.c
new file mode 100644
index 00000000..317a205b
--- /dev/null
+++ b/validation/Waddress-space-from.c
@@ -0,0 +1,63 @@
+
+#define __kernel __attribute__((address_space(0)))
+#define __user __attribute__((address_space(__user)))
+#define __iomem __attribute__((address_space(__iomem)))
+#define __percpu __attribute__((address_space(__percpu)))
+#define __rcu __attribute__((address_space(__rcu)))
+
+
+typedef struct s obj_t;
+
+static void expl(obj_t __kernel *k, obj_t __iomem *o,
+ obj_t __user *p, obj_t __percpu *pc,
+ obj_t __rcu *r)
+{
+ (__UINTPTR_TYPE__)(k); // OK
+ (unsigned long)(k); // OK
+ (void *)(k); // OK
+ (obj_t*)(k); // OK
+ (obj_t __kernel*)(k); // OK
+
+ (__UINTPTR_TYPE__)(o); // OK
+ (unsigned long)(o); // OK
+ (void *)(o);
+ (obj_t*)(o);
+ (obj_t __iomem*)(o); // OK
+
+ (__UINTPTR_TYPE__)(p); // OK
+ (unsigned long)(p); // OK
+ (void *)(p);
+ (obj_t*)(p);
+ (obj_t __user*)(p); // OK
+
+ (__UINTPTR_TYPE__)(pc); // OK
+ (unsigned long)(pc); // OK
+ (void *)(pc);
+ (obj_t*)(pc);
+ (obj_t __percpu*)(pc); // OK
+
+ (__UINTPTR_TYPE__)(r); // OK
+ (unsigned long)(r); // OK
+ (void *)(r);
+ (obj_t*)(r);
+ (obj_t __rcu*)(r); // OK
+}
+
+/*
+ * check-name: Waddress-space-from
+ * check-command: sparse -Wno-cast-from-as $file
+ * check-description: Test the removal of AS from a pointer but only
+ * in the non-strict variant where casts to ulong (or uintptr_t)
+ * are allowed.
+ *
+ * check-error-start
+Waddress-space-from.c:23:10: warning: cast removes address space '__iomem' of expression
+Waddress-space-from.c:24:10: warning: cast removes address space '__iomem' of expression
+Waddress-space-from.c:29:10: warning: cast removes address space '__user' of expression
+Waddress-space-from.c:30:10: warning: cast removes address space '__user' of expression
+Waddress-space-from.c:35:10: warning: cast removes address space '__percpu' of expression
+Waddress-space-from.c:36:10: warning: cast removes address space '__percpu' of expression
+Waddress-space-from.c:41:10: warning: cast removes address space '__rcu' of expression
+Waddress-space-from.c:42:10: warning: cast removes address space '__rcu' of expression
+ * check-error-end
+ */
diff --git a/validation/Waddress-space-strict.c b/validation/Waddress-space-strict.c
index 7987eb1d..a1c5b277 100644
--- a/validation/Waddress-space-strict.c
+++ b/validation/Waddress-space-strict.c
@@ -27,7 +27,6 @@ static void expl(ulong u, void *v, obj_t *o, obj_t __user *p)
* check-command: sparse -Wcast-from-as -Wcast-to-as $file
*
* check-error-start
-Waddress-space-strict.c:9:10: warning: cast adds address space '<asn:1>' to expression
Waddress-space-strict.c:12:10: warning: cast adds address space '<asn:1>' to expression
Waddress-space-strict.c:17:10: warning: cast adds address space '<asn:1>' to expression
Waddress-space-strict.c:19:10: warning: cast removes address space '<asn:1>' of expression
diff --git a/validation/Wcast-to-as.c b/validation/Wcast-to-as.c
new file mode 100644
index 00000000..8c512091
--- /dev/null
+++ b/validation/Wcast-to-as.c
@@ -0,0 +1,36 @@
+#define __user __attribute__((address_space(1)))
+
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef unsigned long ulong;
+typedef struct s obj_t;
+
+static void expl(ulong u, uintptr_t uip, void *v, obj_t *o, obj_t __user *p)
+{
+ (obj_t*)(u);
+ (obj_t __user*)(u);
+
+ (obj_t*)(uip);
+ (obj_t __user*)(uip);
+
+ (obj_t*)(v);
+ (obj_t __user*)(v);
+
+ (ulong)(o);
+ (void *)(o);
+ (obj_t*)(o);
+ (obj_t __user*)(o);
+
+ (ulong)(p);
+ (obj_t __user*)(p);
+
+}
+
+/*
+ * check-name: cast-to-as
+ * check-command: sparse -Wcast-to-as $file
+ *
+ * check-error-start
+Wcast-to-as.c:16:10: warning: cast adds address space '<asn:1>' to expression
+Wcast-to-as.c:21:10: warning: cast adds address space '<asn:1>' to expression
+ * check-error-end
+ */
diff --git a/validation/constexpr-constcond.c b/validation/constexpr-constcond.c
new file mode 100644
index 00000000..d98da3dc
--- /dev/null
+++ b/validation/constexpr-constcond.c
@@ -0,0 +1,10 @@
+extern int var;
+
+static int a[] = {
+ [0 ? var : 1] = 0,
+ [1 ? 2 : var] = 0,
+};
+
+/*
+ * check-name: constexprness in constant conditionals
+ */
diff --git a/validation/constexpr-shift.c b/validation/constexpr-shift.c
new file mode 100644
index 00000000..df01b74e
--- /dev/null
+++ b/validation/constexpr-shift.c
@@ -0,0 +1,12 @@
+#define __is_constexpr(x) \
+ (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
+
+static void test(int x) {
+ static int b[] = {
+ [__builtin_choose_expr(__is_constexpr(1 << 1), 1, x)] = 0,
+ };
+}
+
+/*
+ * check-name: constexpr-shift
+ */
diff --git a/validation/enum-sign-extend.c b/validation/enum-sign-extend.c
new file mode 100644
index 00000000..d852c934
--- /dev/null
+++ b/validation/enum-sign-extend.c
@@ -0,0 +1,12 @@
+enum num {
+ a = 0x80000000,
+ b = -1,
+};
+
+_Static_assert([typeof(b)] == [long], "type");
+_Static_assert(b == -1L, "value");
+
+/*
+ * check-name: enum-sign-extend
+ * check-command: sparse -m64 $file
+ */
diff --git a/validation/eval-bad-assign1.c b/validation/eval-bad-assign1.c
new file mode 100644
index 00000000..57138c7a
--- /dev/null
+++ b/validation/eval-bad-assign1.c
@@ -0,0 +1,14 @@
+static void kos(int *r, int a)
+{
+ r = ({ __builtin_types_compatible_p(int, int); });
+}
+
+/*
+ * check-name: eval-bad-assign1
+ *
+ * check-error-start
+eval-bad-assign1.c:3:11: warning: incorrect type in assignment (different base types)
+eval-bad-assign1.c:3:11: expected int *r
+eval-bad-assign1.c:3:11: got int
+ * check-error-end
+ */
diff --git a/validation/eval-bad-assign2.c b/validation/eval-bad-assign2.c
new file mode 100644
index 00000000..4d08cb90
--- /dev/null
+++ b/validation/eval-bad-assign2.c
@@ -0,0 +1,22 @@
+struct s {
+ char c[1];
+};
+
+struct s fun(void);
+
+
+static void foo(void)
+{
+ char c[1];
+ c = fun().c;
+}
+
+/*
+ * check-name: eval-bad-assign2
+ *
+ * check-error-start
+eval-bad-assign2.c:11:11: warning: incorrect type in assignment (invalid types)
+eval-bad-assign2.c:11:11: expected char c[1]
+eval-bad-assign2.c:11:11: got char *
+ * check-error-end
+ */
diff --git a/validation/expand/bad-shift.c b/validation/expand/bad-shift.c
new file mode 100644
index 00000000..22c4341f
--- /dev/null
+++ b/validation/expand/bad-shift.c
@@ -0,0 +1,64 @@
+#define MAX (sizeof(int) * __CHAR_BIT__)
+
+static int lmax(int a)
+{
+ return 1 << MAX;
+}
+
+static int lneg(int a)
+{
+ return 1 << -1;
+}
+
+static int rmax(int a)
+{
+ return 1 >> MAX;
+}
+
+static int rneg(int a)
+{
+ return 1 >> -1;
+}
+
+/*
+ * check-name: bad-shift
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+lmax:
+.L0:
+ <entry-point>
+ shl.32 %r1 <- $1, $32
+ ret.32 %r1
+
+
+lneg:
+.L2:
+ <entry-point>
+ shl.32 %r3 <- $1, $0xffffffff
+ ret.32 %r3
+
+
+rmax:
+.L4:
+ <entry-point>
+ asr.32 %r5 <- $1, $32
+ ret.32 %r5
+
+
+rneg:
+.L6:
+ <entry-point>
+ asr.32 %r7 <- $1, $0xffffffff
+ ret.32 %r7
+
+
+ * check-output-end
+ *
+ * check-error-start
+expand/bad-shift.c:5:18: warning: shift too big (32) for type int
+expand/bad-shift.c:10:18: warning: shift count is negative (-1)
+expand/bad-shift.c:15:18: warning: shift too big (32) for type int
+expand/bad-shift.c:20:18: warning: shift count is negative (-1)
+ * check-error-end
+ */
diff --git a/validation/ioc-typecheck.c b/validation/ioc-typecheck.c
index 34b37d31..7780773b 100644
--- a/validation/ioc-typecheck.c
+++ b/validation/ioc-typecheck.c
@@ -4,8 +4,4 @@ static unsigned iocnrs[] = {
};
/*
* check-name: integer constant & conditional expression
- * check-known-to-fail
- *
- * check-error-start
- * check-error-end
*/