diff options
| -rw-r--r-- | builtin.c | 9 | ||||
| -rw-r--r-- | evaluate.c | 34 | ||||
| -rw-r--r-- | lib.c | 24 | ||||
| -rw-r--r-- | lib.h | 2 | ||||
| -rw-r--r-- | linearize.c | 6 | ||||
| -rw-r--r-- | parse.c | 65 | ||||
| -rw-r--r-- | token.h | 1 | ||||
| -rw-r--r-- | tokenize.c | 1 | ||||
| -rw-r--r-- | validation/attr-context.c | 40 | ||||
| -rw-r--r-- | validation/check_byte_count-ice.c | 4 | ||||
| -rw-r--r-- | validation/context-stmt.c | 62 | ||||
| -rw-r--r-- | validation/error-at-eof.c | 10 | ||||
| -rw-r--r-- | validation/expand/builtin-expect.c | 101 | ||||
| -rw-r--r-- | validation/goto-reserved.c | 12 | ||||
| -rw-r--r-- | validation/integer-const-expr.c | 85 | ||||
| -rw-r--r-- | validation/vla-sizeof-ice.c | 19 | ||||
| -rw-r--r-- | validation/vla-sizeof0.c | 20 | ||||
| -rw-r--r-- | validation/vla-sizeof1.c | 21 | ||||
| -rw-r--r-- | validation/vla-sizeof2.c | 21 | ||||
| -rw-r--r-- | validation/vla-sizeof3.c | 21 | ||||
| -rw-r--r-- | validation/vla-sizeof4.c | 22 |
21 files changed, 523 insertions, 57 deletions
@@ -82,13 +82,6 @@ error: return 0; } -static int evaluate_expect(struct expression *expr) -{ - /* Should we evaluate it to return the type of the first argument? */ - expr->ctype = &int_ctype; - return 1; -} - static int arguments_choose(struct expression *expr) { return eval_args(expr, 3); @@ -198,7 +191,6 @@ static struct symbol_op warning_op = { }; static struct symbol_op expect_op = { - .evaluate = evaluate_expect, .expand = expand_expect }; @@ -354,6 +346,7 @@ void declare_builtins(void) declare_builtin("__builtin_ctzl", &int_ctype, 0, &long_ctype, NULL); declare_builtin("__builtin_ctzll", &int_ctype, 0, &llong_ctype, NULL); declare_builtin("__builtin_exit", &void_ctype, 0, &int_ctype, NULL); + declare_builtin("__builtin_expect", &long_ctype, 0, &long_ctype ,&long_ctype, NULL); declare_builtin("__builtin_extract_return_addr", &ptr_ctype, 0, &ptr_ctype, NULL); declare_builtin("__builtin_fabs", &double_ctype, 0, &double_ctype, NULL); declare_builtin("__builtin_ffs", &int_ctype, 0, &int_ctype, NULL); @@ -2211,6 +2211,38 @@ static struct symbol *evaluate_sizeof(struct expression *expr) size = bits_in_char; } + if (is_array_type(type) && size < 0) { // VLA, 1-dimension only + struct expression *base, *size; + struct symbol *base_type; + + if (type->type == SYM_NODE) + type = type->ctype.base_type; // strip the SYM_NODE + base_type = get_base_type(type); + if (!base_type) + goto error; + if (base_type->bit_size <= 0) { + base = alloc_expression(expr->pos, EXPR_SIZEOF); + base->cast_type = base_type; + if (!evaluate_sizeof(base)) + goto error; + } else { + base = alloc_expression(expr->pos, EXPR_VALUE); + base->value = bits_to_bytes(base_type->bit_size); + base->ctype = size_t_ctype; + } + size = alloc_expression(expr->pos, EXPR_CAST); + size->cast_type = size_t_ctype; + size->cast_expression = type->array_size; + if (!evaluate_expression(size)) + goto error; + expr->left = size; + expr->right = base; + expr->type = EXPR_BINOP; + expr->op = '*'; + return expr->ctype = size_t_ctype; + } + +error: if ((size < 0) || (size & (bits_in_char - 1))) expression_error(expr, "cannot size expression"); @@ -3593,7 +3625,7 @@ static void evaluate_goto_statement(struct statement *stmt) { struct symbol *label = stmt->goto_label; - if (label && !label->stmt && !lookup_keyword(label->ident, NS_KEYWORD)) + if (label && !label->stmt && label->ident && !lookup_keyword(label->ident, NS_KEYWORD)) sparse_error(stmt->pos, "label '%s' was not declared", show_ident(label->ident)); evaluate_expression(stmt->goto_expression); @@ -70,10 +70,10 @@ struct token *skip_to(struct token *token, int op) return token; } +static struct token bad_token = { .pos.type = TOKEN_BAD }; struct token *expect(struct token *token, int op, const char *where) { if (!match_op(token, op)) { - static struct token bad_token; if (token != &bad_token) { bad_token.next = token; sparse_error(token->pos, "Expected %s %s", show_special(op), where); @@ -86,6 +86,21 @@ struct token *expect(struct token *token, int op, const char *where) return token->next; } +/// +// issue an error message on new parsing errors +// @token: the current token +// @errmsg: the error message +// If the current token is from a previous error, an error message +// has already been issued, so nothing more is done. +// Otherwise, @errmsg is displayed followed by the current token. +void unexpected(struct token *token, const char *errmsg) +{ + if (token == &bad_token) + return; + sparse_error(token->pos, "%s", errmsg); + sparse_error(token->pos, "got %s", show_token(token)); +} + unsigned int hexval(unsigned int c) { int retval = 256; @@ -108,6 +123,10 @@ static void do_warn(const char *type, struct position pos, const char * fmt, va_ static char buffer[512]; const char *name; + /* Shut up warnings if position is bad_token.pos */ + if (pos.type == TOKEN_BAD) + return; + vsprintf(buffer, fmt, args); name = stream_name(pos.stream); @@ -135,6 +154,9 @@ static void do_error(struct position pos, const char * fmt, va_list args) static int errors = 0; die_if_error = 1; show_info = 1; + /* Shut up warnings if position is bad_token.pos */ + if (pos.type == TOKEN_BAD) + return; /* Shut up warnings after an error */ has_error |= ERROR_CURR_PHASE; if (errors > 100) { @@ -83,6 +83,8 @@ typedef struct pseudo *pseudo_t; struct token *skip_to(struct token *, int); struct token *expect(struct token *, int, const char *); +void unexpected(struct token *, const char *errmsg); + #ifdef __GNUC__ #define FORMAT_ATTR(pos) __attribute__ ((__format__ (__printf__, pos, pos+1))) #define NORETURN_ATTR __attribute__ ((__noreturn__)) diff --git a/linearize.c b/linearize.c index 88f6c094..6284d079 100644 --- a/linearize.c +++ b/linearize.c @@ -1777,12 +1777,8 @@ static pseudo_t linearize_context(struct entrypoint *ep, struct statement *stmt) { struct instruction *insn = alloc_instruction(OP_CONTEXT, 0); struct expression *expr = stmt->expression; - int value = 0; - if (expr->type == EXPR_VALUE) - value = expr->value; - - insn->increment = value; + insn->increment = get_expression_value(expr); insn->context_expr = stmt->context; add_one_insn(ep, insn); return VOID; @@ -1133,43 +1133,24 @@ static struct token *attribute_context(struct token *token, struct symbol *attr, { struct context *context = alloc_context(); struct expression *args[3]; - int argc = 0; + int idx = 0; token = expect(token, '(', "after context attribute"); - while (!match_op(token, ')')) { - struct expression *expr = NULL; - token = conditional_expression(token, &expr); - if (!expr) - break; - if (argc < 3) - args[argc++] = expr; - if (!match_op(token, ',')) - break; + token = conditional_expression(token, &args[0]); + token = expect(token, ',', "after context 1st argument"); + token = conditional_expression(token, &args[1]); + if (match_op(token, ',')) { token = token->next; - } - - switch(argc) { - case 0: - sparse_error(token->pos, "expected context input/output values"); - break; - case 1: - context->in = get_expression_value(args[0]); - break; - case 2: - context->in = get_expression_value(args[0]); - context->out = get_expression_value(args[1]); - break; - case 3: + token = conditional_expression(token, &args[2]); + token = expect(token, ')', "after context 3rd argument"); context->context = args[0]; - context->in = get_expression_value(args[1]); - context->out = get_expression_value(args[2]); - break; + idx++; + } else { + token = expect(token, ')', "after context 2nd argument"); } - - if (argc) - add_ptr_list(&ctx->ctype.contexts, context); - - token = expect(token, ')', "after context attribute"); + context->in = get_expression_value(args[idx++]); + context->out = get_expression_value(args[idx++]); + add_ptr_list(&ctx->ctype.contexts, context); return token; } @@ -2357,15 +2338,19 @@ static struct token *parse_goto_statement(struct token *token, struct statement static struct token *parse_context_statement(struct token *token, struct statement *stmt) { stmt->type = STMT_CONTEXT; - token = parse_expression(token->next, &stmt->expression); - if (stmt->expression->type == EXPR_PREOP - && stmt->expression->op == '(' - && stmt->expression->unop->type == EXPR_COMMA) { - struct expression *expr; - expr = stmt->expression->unop; - stmt->context = expr->left; - stmt->expression = expr->right; + token = token->next; + token = expect(token, '(', "after __context__ statement"); + token = assignment_expression(token, &stmt->expression); + if (!stmt->expression) + unexpected(token, "expression expected after '('"); + if (match_op(token, ',')) { + token = token->next; + stmt->context = stmt->expression; + token = assignment_expression(token, &stmt->expression); + if (!stmt->expression) + unexpected(token, "expression expected after ','"); } + token = expect(token, ')', "at end of __context__ statement"); return expect(token, ';', "at end of statement"); } @@ -79,6 +79,7 @@ struct ident { enum token_type { TOKEN_EOF, + TOKEN_BAD, TOKEN_ERROR, TOKEN_IDENT, TOKEN_ZERO_IDENT, @@ -444,6 +444,7 @@ static struct token *mark_eof(stream_t *stream) struct token *end; end = alloc_token(stream); + eof_token_entry.pos = end->pos; token_type(end) = TOKEN_STREAMEND; end->pos.newline = 1; diff --git a/validation/attr-context.c b/validation/attr-context.c new file mode 100644 index 00000000..00e54c66 --- /dev/null +++ b/validation/attr-context.c @@ -0,0 +1,40 @@ +static void a(void) __attribute__((context)); // KO +static void b(void) __attribute__((context())); // KO +static void c(void) __attribute__((context 1)); // KO +static void d(void) __attribute__((context 1,2)); // KO +static void e(void) __attribute__((context (1))); // !!!! +static void f(void) __attribute__((context(0))); // !!!! +static void g(void) __attribute__((context(0,1,2,3))); // KO + +static void h(void) __attribute__((context (1,2))); // OK +static void i(void) __attribute__((context(0,1))); // OK +static void j(void) __attribute__((context(0,1,2))); // OK + +extern int u, v; +static void x(void) __attribute__((context(0,1,v))); +static void y(void) __attribute__((context(0,u,1))); +static void z(void) __attribute__((context(0,u))); + +/* + * check-name: attr-context + * + * check-error-start +attr-context.c:1:43: error: Expected ( after context attribute +attr-context.c:1:43: error: got ) +attr-context.c:2:44: error: Expected , after context 1st argument +attr-context.c:2:44: error: got ) +attr-context.c:3:44: error: Expected ( after context attribute +attr-context.c:3:44: error: got 1 +attr-context.c:4:44: error: Expected ( after context attribute +attr-context.c:4:44: error: got 1 +attr-context.c:5:46: error: Expected , after context 1st argument +attr-context.c:5:46: error: got ) +attr-context.c:6:45: error: Expected , after context 1st argument +attr-context.c:6:45: error: got ) +attr-context.c:7:49: error: Expected ) after context 3rd argument +attr-context.c:7:49: error: got , +attr-context.c:14:48: error: bad constant expression +attr-context.c:15:46: error: bad constant expression +attr-context.c:16:46: error: bad constant expression + * check-error-end + */ diff --git a/validation/check_byte_count-ice.c b/validation/check_byte_count-ice.c index 7b85b963..dae40c67 100644 --- a/validation/check_byte_count-ice.c +++ b/validation/check_byte_count-ice.c @@ -12,8 +12,8 @@ check_byte_count-ice.c:6:0: warning: Newline in string or character constant check_byte_count-ice.c:5:23: warning: multi-character character constant check_byte_count-ice.c:6:1: error: Expected ) in function call check_byte_count-ice.c:6:1: error: got } -builtin:0:0: error: Expected } at end of function -builtin:0:0: error: got end-of-input +check_byte_count-ice.c:20:0: error: Expected } at end of function +check_byte_count-ice.c:20:0: error: got end-of-input check_byte_count-ice.c:5:15: error: not enough arguments for function memset * check-error-end */ diff --git a/validation/context-stmt.c b/validation/context-stmt.c new file mode 100644 index 00000000..2884a8a2 --- /dev/null +++ b/validation/context-stmt.c @@ -0,0 +1,62 @@ +static void foo(int x) +{ + __context__(0); // OK + __context__(x, 0); // OK + __context__ (x, 1); // OK + + __context__(x); // KO: no const expr + __context__(1,x); // KO: no const expr + + __context__; // KO: no expression at all + __context__(; // KO: no expression at all + + __context__ 0; // KO: need parens + __context__ x, 0; // KO: need parens + __context__(x, 0; // KO: unmatched parens + __context__ x, 0); // KO: unmatched parens + __context__(0; // KO: unmatched parens + __context__ 0); // KO: unmatched parens + + __context__(); // KO: no expression at all + __context__(,0); // KO: no expression at all + __context__(x,); // KO: no expression at all + __context__(,); // KO: no expression at all +} + +/* + * check-name: context-stmt + * check-command: sparse -Wno-context $file + * + * check-error-start +context-stmt.c:10:20: error: Expected ( after __context__ statement +context-stmt.c:10:20: error: got ; +context-stmt.c:11:21: error: expression expected after '(' +context-stmt.c:11:21: error: got ; +context-stmt.c:11:21: error: Expected ) at end of __context__ statement +context-stmt.c:11:21: error: got ; +context-stmt.c:13:21: error: Expected ( after __context__ statement +context-stmt.c:13:21: error: got 0 +context-stmt.c:14:21: error: Expected ( after __context__ statement +context-stmt.c:14:21: error: got x +context-stmt.c:15:25: error: Expected ) at end of __context__ statement +context-stmt.c:15:25: error: got ; +context-stmt.c:16:21: error: Expected ( after __context__ statement +context-stmt.c:16:21: error: got x +context-stmt.c:17:22: error: Expected ) at end of __context__ statement +context-stmt.c:17:22: error: got ; +context-stmt.c:18:21: error: Expected ( after __context__ statement +context-stmt.c:18:21: error: got 0 +context-stmt.c:20:21: error: expression expected after '(' +context-stmt.c:20:21: error: got ) +context-stmt.c:21:21: error: expression expected after '(' +context-stmt.c:21:21: error: got , +context-stmt.c:22:23: error: expression expected after ',' +context-stmt.c:22:23: error: got ) +context-stmt.c:23:21: error: expression expected after '(' +context-stmt.c:23:21: error: got , +context-stmt.c:23:22: error: expression expected after ',' +context-stmt.c:23:22: error: got ) +context-stmt.c:7:21: error: bad constant expression +context-stmt.c:8:23: error: bad constant expression + * check-error-end + */ diff --git a/validation/error-at-eof.c b/validation/error-at-eof.c new file mode 100644 index 00000000..7d933651 --- /dev/null +++ b/validation/error-at-eof.c @@ -0,0 +1,10 @@ +/* + * check-name: error-at-eof + * + * check-error-start +error-at-eof.c:11:0: error: Expected ; at end of declaration +error-at-eof.c:11:0: error: got end-of-input + * check-error-end + */ + +int a diff --git a/validation/expand/builtin-expect.c b/validation/expand/builtin-expect.c new file mode 100644 index 00000000..a80176a5 --- /dev/null +++ b/validation/expand/builtin-expect.c @@ -0,0 +1,101 @@ +int flia(long a) +{ + return __builtin_expect(a, 1); +} + +int flic(void) +{ + return __builtin_expect(1L << 32 | 1, 1); +} + +long fila(int a) +{ + return __builtin_expect(a, 1); +} + +long filc(void) +{ + return __builtin_expect(1L << 32 | 1, 1); +} + +long filu(void) +{ + return __builtin_expect(0x80000000U, 1); +} + +long fils(void) +{ + return __builtin_expect((int)0x80000000, 1); +} + +void *fptr(void *a) +{ + return __builtin_expect(a, a); +} + +/* + * check-name: builtin-expect + * check-command: test-linearize -m64 -Wno-decl $file + * + * check-output-start +flia: +.L0: + <entry-point> + scast.32 %r2 <- (64) %arg1 + ret.32 %r2 + + +flic: +.L2: + <entry-point> + ret.32 $1 + + +fila: +.L4: + <entry-point> + scast.64 %r6 <- (32) %arg1 + ret.64 %r6 + + +filc: +.L6: + <entry-point> + ret.64 $0x100000001 + + +filu: +.L8: + <entry-point> + ret.64 $0x80000000 + + +fils: +.L10: + <entry-point> + ret.64 $0xffffffff80000000 + + +fptr: +.L12: + <entry-point> + cast.64 %r12 <- (64) %arg1 + scast.64 %r13 <- (64) %r12 + ret.64 %r13 + + + * check-output-end + * + * check-error-start +expand/builtin-expect.c:33:33: warning: incorrect type in argument 1 (different base types) +expand/builtin-expect.c:33:33: expected long [signed] <noident> +expand/builtin-expect.c:33:33: got void *a +expand/builtin-expect.c:33:36: warning: incorrect type in argument 2 (different base types) +expand/builtin-expect.c:33:36: expected long [signed] <noident> +expand/builtin-expect.c:33:36: got void *a +expand/builtin-expect.c:33:32: warning: incorrect type in return expression (different base types) +expand/builtin-expect.c:33:32: expected void * +expand/builtin-expect.c:33:32: got long +expand/builtin-expect.c:8:42: warning: cast truncates bits from constant value (100000001 becomes 1) + * check-error-end + */ diff --git a/validation/goto-reserved.c b/validation/goto-reserved.c new file mode 100644 index 00000000..fbaf03e1 --- /dev/null +++ b/validation/goto-reserved.c @@ -0,0 +1,12 @@ +static void foo(void) +{ + goto return; +} + +/* + * check-name: goto-reserved + * + * check-error-start +goto-reserved.c:3:14: error: Trying to use reserved word 'return' as identifier + * check-error-end + */ diff --git a/validation/integer-const-expr.c b/validation/integer-const-expr.c new file mode 100644 index 00000000..f41aa806 --- /dev/null +++ b/validation/integer-const-expr.c @@ -0,0 +1,85 @@ +extern void *malloc(unsigned long); + +static inline __attribute__((__const__)) unsigned squarec(unsigned n) +{ + return n*n; +} + +static inline unsigned square(unsigned n) +{ + return n*n; +} + +static inline unsigned long long bignum(void) +{ + return 1000000000000ULL; +} + +static inline __attribute__((__const__)) unsigned long long bignumc(void) +{ + return 1000000000000ULL; +} + +// test if x is an integer constant expression [C99,C11 6.6p6] +#define ICE_P(x) \ + (__builtin_types_compatible_p(typeof(0?((void*)((long)(x)*0l)):(int*)1),int*)) + +#define CHX_P(X) __builtin_choose_expr(ICE_P(X), 1, 0) +#define CST_P(X) __builtin_constant_p(ICE_P(X)) + +#define TEST(R, X) _Static_assert(ICE_P(X) == R, "ICE_P(" #X ") => " #R); \ + _Static_assert(ICE_P(ICE_P(X)), "ICE_P2(" #X ")"); \ + _Static_assert(CHX_P(X) == R, "CHX_P(" #X ") => " #R); \ + _Static_assert(CST_P(X) == 1, "CST_P(" #X ")") + +int main(int argc, char *argv[]) +{ + char fla[3]; + char vla[argc++]; + char **p, **q; + int x = 5, y = 8; + void *v; + + p = &argv[3]; + q = &argv[6]; + + TEST(1, 4); + TEST(1, sizeof(long)); + TEST(1, 5ull - 3u); + TEST(1, 3.2); + TEST(1, sizeof(fla)); + + TEST(0, square(2)); + TEST(0, square(argc)); + TEST(0, squarec(2)); + TEST(0, squarec(argc)); + TEST(0, 1+argc-argc); + TEST(0, 1+argc+argc+1-argc-argc); + TEST(0, bignum() - 1); + TEST(0, 0*bignum()); + TEST(0, 0*bignumc()); + TEST(0, sizeof(vla)); + TEST(0, p); + TEST(0, p < q); + TEST(0, p++); + TEST(0, main); + TEST(0, malloc(8)); + TEST(0, v = malloc(8)); + TEST(0, v); + TEST(0, x++); + TEST(0, y++); + TEST(0, (3, 2, 1)); + TEST(0, ({x++; 0; })); + TEST(0, ({square(y--); 0; })); + TEST(0, (square(x), 3)); + TEST(0, (squarec(x), 3)); + TEST(0, ({squarec(x); 3;})); + TEST(0, ({squarec(x);})); + + return 0; +} + +/* + * check-name: integer-const-expr + * check-command: sparse -Wno-vla $file + */ diff --git a/validation/vla-sizeof-ice.c b/validation/vla-sizeof-ice.c new file mode 100644 index 00000000..472da6a4 --- /dev/null +++ b/validation/vla-sizeof-ice.c @@ -0,0 +1,19 @@ +// credit goes to Martin Uecker for the awesome ICE_P macro + +#define ICE_P(x) \ + (__builtin_types_compatible_p(typeof(0?((void*)((long)(x)*0l)):(int*)1),int*)) + +#define T(x) __builtin_choose_expr(ICE_P(x), 1, 0) +#define TEST(x, r) _Static_assert(T(x) == r, #x " => " #r) + +static void test(int n) +{ + char foo[n++]; + + TEST(sizeof(foo), 0); +} + +/* + * check-name: vla-sizeof-ice + * check-command: sparse -Wno-vla $file + */ diff --git a/validation/vla-sizeof0.c b/validation/vla-sizeof0.c new file mode 100644 index 00000000..a58fd300 --- /dev/null +++ b/validation/vla-sizeof0.c @@ -0,0 +1,20 @@ +#define N 2 +#define T int + +static unsigned int foo(int x) +{ + T a[(1,N)]; + + return sizeof(a) == (N * sizeof(T)); +} + +/* + * check-name: vla-sizeof cte,cte + * check-command: test-linearize -Wvla $file + * + * check-output-ignore + * check-output-contains: ret\\.32 *\\$1 + * + * check-error-start + * check-error-end + */ diff --git a/validation/vla-sizeof1.c b/validation/vla-sizeof1.c new file mode 100644 index 00000000..ed7f5d4e --- /dev/null +++ b/validation/vla-sizeof1.c @@ -0,0 +1,21 @@ +#define N 2 +#define T int + +static unsigned int foo(int x) +{ + T a[(x,N)]; + + return sizeof(a) == (N * sizeof(T)); +} + +/* + * check-name: vla-sizeof var,cte + * check-command: test-linearize -Wvla $file + * + * check-output-ignore + * check-output-contains: ret\\.32 *\\$1 + * + * check-error-start +vla-sizeof1.c:6:15: warning: Variable length array is used. + * check-error-end + */ diff --git a/validation/vla-sizeof2.c b/validation/vla-sizeof2.c new file mode 100644 index 00000000..57927d16 --- /dev/null +++ b/validation/vla-sizeof2.c @@ -0,0 +1,21 @@ +#define N 2 +#define T int + +static unsigned long foo(int x) +{ + T a[x]; + + return sizeof(a) == (x * sizeof(T)); +} + +/* + * check-name: vla-sizeof var + * check-command: test-linearize -Wvla $file + * + * check-output-ignore + * check-output-contains: ret\\..*\\$1 + * + * check-error-start +vla-sizeof2.c:6:13: warning: Variable length array is used. + * check-error-end + */ diff --git a/validation/vla-sizeof3.c b/validation/vla-sizeof3.c new file mode 100644 index 00000000..21edb007 --- /dev/null +++ b/validation/vla-sizeof3.c @@ -0,0 +1,21 @@ +#define N 2UL +#define T int + +static unsigned long foo(int x) +{ + T a[x][N]; + + return sizeof(a) == (N * x * sizeof(T)); +} + +/* + * check-name: vla-sizeof var X cte + * check-command: test-linearize -Wvla $file + * + * check-output-ignore + * check-output-contains: ret\\..*\\$1 + * + * check-error-start +vla-sizeof3.c:6:13: warning: Variable length array is used. + * check-error-end + */ diff --git a/validation/vla-sizeof4.c b/validation/vla-sizeof4.c new file mode 100644 index 00000000..e7478613 --- /dev/null +++ b/validation/vla-sizeof4.c @@ -0,0 +1,22 @@ +#define N 2 +#define T int + +static unsigned long foo(int x, int y) +{ + T a[x][y]; + + return sizeof(a) == (x * (y * sizeof(T))); +} + +/* + * check-name: vla-sizeof var X var + * check-command: test-linearize -Wvla $file + * + * check-output-ignore + * check-output-contains: ret\\..*\\$1 + * + * check-error-start +vla-sizeof4.c:6:16: warning: Variable length array is used. +vla-sizeof4.c:6:13: warning: Variable length array is used. + * check-error-end + */ |
