aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--Documentation/api.rst1
-rw-r--r--Makefile1
-rw-r--r--builtin.c100
-rw-r--r--ident-list.h6
-rw-r--r--lib.c183
-rw-r--r--lib.h4
-rw-r--r--pre-process.c255
-rw-r--r--symbol.c9
-rw-r--r--symbol.h5
-rw-r--r--tokenize.c9
-rw-r--r--utils.c17
-rw-r--r--utils.h25
-rw-r--r--validation/builtin-overflow.c246
-rw-r--r--validation/preprocessor/base-file.c17
-rw-r--r--validation/preprocessor/base-file.h2
-rw-r--r--validation/preprocessor/builtin.c17
-rw-r--r--validation/preprocessor/dynamic.c37
-rw-r--r--validation/preprocessor/has-builtin.c43
-rw-r--r--validation/preprocessor/include-level.c14
-rw-r--r--validation/preprocessor/include-level.h1
20 files changed, 820 insertions, 172 deletions
diff --git a/Documentation/api.rst b/Documentation/api.rst
index d1a1d3ca..1270551c 100644
--- a/Documentation/api.rst
+++ b/Documentation/api.rst
@@ -9,6 +9,7 @@ Utilities
~~~~~~~~~
.. c:autodoc:: ptrlist.c
+.. c:autodoc:: utils.h
Parsing
~~~~~~~
diff --git a/Makefile b/Makefile
index c89f2c85..0b6c32cf 100644
--- a/Makefile
+++ b/Makefile
@@ -61,6 +61,7 @@ LIB_OBJS += symbol.o
LIB_OBJS += target.o
LIB_OBJS += tokenize.o
LIB_OBJS += unssa.o
+LIB_OBJS += utils.o
PROGRAMS :=
PROGRAMS += compile
diff --git a/builtin.c b/builtin.c
index 7f9ff358..221c9899 100644
--- a/builtin.c
+++ b/builtin.c
@@ -82,7 +82,7 @@ error:
return 0;
}
-static int arguments_choose(struct expression *expr)
+static int args_triadic(struct expression *expr)
{
return eval_args(expr, 3);
}
@@ -195,8 +195,8 @@ static struct symbol_op expect_op = {
};
static struct symbol_op choose_op = {
+ .args = args_triadic,
.evaluate = evaluate_choose,
- .args = arguments_choose,
};
/* The argument is constant and valid if the cost is zero */
@@ -251,6 +251,71 @@ static struct symbol_op fp_unop_op = {
};
+static int evaluate_overflow_gen(struct expression *expr, int ptr)
+{
+ struct expression *arg;
+ int n = 0;
+
+ /* there will be exactly 3; we'd already verified that */
+ FOR_EACH_PTR(expr->args, arg) {
+ struct symbol *type;
+
+ n++;
+ if (!arg || !(type = arg->ctype))
+ return 0;
+ // 1st & 2nd args must be a basic integer type
+ // 3rd arg must be a pointer to such a type.
+ if (n == 3 && ptr) {
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ if (!type)
+ return 0;
+ if (type->type != SYM_PTR)
+ goto err;
+ type = type->ctype.base_type;
+ if (!type)
+ return 0;
+ }
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ if (!type)
+ return 0;
+ if (type->ctype.base_type != &int_type || type == &bool_ctype)
+ goto err;
+ } END_FOR_EACH_PTR(arg);
+
+ // the builtin returns a bool
+ expr->ctype = &bool_ctype;
+ return 1;
+
+err:
+ sparse_error(arg->pos, "invalid type for argument %d:", n);
+ info(arg->pos, " %s", show_typename(arg->ctype));
+ expr->ctype = &bad_ctype;
+ return 0;
+}
+
+static int evaluate_overflow(struct expression *expr)
+{
+ return evaluate_overflow_gen(expr, 1);
+}
+
+static struct symbol_op overflow_op = {
+ .args = args_triadic,
+ .evaluate = evaluate_overflow,
+};
+
+static int evaluate_overflow_p(struct expression *expr)
+{
+ return evaluate_overflow_gen(expr, 0);
+}
+
+static struct symbol_op overflow_p_op = {
+ .args = args_triadic,
+ .evaluate = evaluate_overflow_p,
+};
+
+
/*
* Builtin functions
*/
@@ -275,6 +340,12 @@ static struct sym_init {
{ "__builtin_isnan", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
{ "__builtin_isnormal", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
{ "__builtin_signbit", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+ { "__builtin_add_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+ { "__builtin_sub_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+ { "__builtin_mul_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+ { "__builtin_add_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
+ { "__builtin_sub_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
+ { "__builtin_mul_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
{ NULL, NULL, 0 }
};
@@ -289,6 +360,7 @@ void init_builtins(int stream)
sym->ctype.base_type = ptr->base_type;
sym->ctype.modifiers = ptr->modifiers;
sym->op = ptr->op;
+ sym->builtin = 1;
}
}
@@ -302,6 +374,7 @@ static void declare_builtin(const char *name, struct symbol *rtype, int variadic
sym->ctype.base_type = fun;
sym->ctype.modifiers = MOD_TOPLEVEL;
+ sym->builtin = 1;
fun->ctype.base_type = rtype;
fun->variadic = variadic;
@@ -397,9 +470,18 @@ void declare_builtins(void)
declare_builtin("__builtin_realloc", &ptr_ctype, 0, &ptr_ctype, size_t_ctype, NULL);
declare_builtin("__builtin_return_address", &ptr_ctype, 0, &uint_ctype, NULL);
declare_builtin("__builtin_rindex", &string_ctype, 0, &const_string_ctype, &int_ctype, NULL);
+ declare_builtin("__builtin_sadd_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+ declare_builtin("__builtin_saddl_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+ declare_builtin("__builtin_saddll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
declare_builtin("__builtin_signbit", &int_ctype, 1, NULL);
+ declare_builtin("__builtin_smul_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+ declare_builtin("__builtin_smull_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+ declare_builtin("__builtin_smulll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
declare_builtin("__builtin_snprintf", &int_ctype, 1, &string_ctype, size_t_ctype, &const_string_ctype, NULL);
declare_builtin("__builtin_sprintf", &int_ctype, 1, &string_ctype, &const_string_ctype, NULL);
+ declare_builtin("__builtin_ssub_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+ declare_builtin("__builtin_ssubl_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+ declare_builtin("__builtin_ssubll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
declare_builtin("__builtin_stpcpy", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
declare_builtin("__builtin_stpncpy", &string_ctype, 0, &const_string_ctype, &const_string_ctype, size_t_ctype, NULL);
declare_builtin("__builtin_strcasecmp", &int_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
@@ -422,7 +504,16 @@ void declare_builtins(void)
declare_builtin("__builtin_strspn", size_t_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
declare_builtin("__builtin_strstr", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
declare_builtin("__builtin_trap", &void_ctype, 0, NULL);
+ declare_builtin("__builtin_uadd_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+ declare_builtin("__builtin_uaddl_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+ declare_builtin("__builtin_uaddll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
+ declare_builtin("__builtin_umul_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+ declare_builtin("__builtin_umull_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+ declare_builtin("__builtin_umulll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
declare_builtin("__builtin_unreachable", &void_ctype, 0, NULL);
+ declare_builtin("__builtin_usub_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+ declare_builtin("__builtin_usubl_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+ declare_builtin("__builtin_usubll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
declare_builtin("__builtin_va_arg_pack_len", size_t_ctype, 0, NULL);
declare_builtin("__builtin_vprintf", &int_ctype, 0, &const_string_ctype, va_list_ctype, NULL);
declare_builtin("__builtin_vsnprintf", &int_ctype, 0, &string_ctype, size_t_ctype, &const_string_ctype, va_list_ctype, NULL);
@@ -459,4 +550,9 @@ void declare_builtins(void)
declare_builtin("__sync_synchronize", &void_ctype, 0, NULL);
declare_builtin("__sync_val_compare_and_swap", &int_ctype, 1, &ptr_ctype, NULL);
declare_builtin("__sync_xor_and_fetch", &int_ctype, 1, &ptr_ctype, NULL);
+
+ // Blackfin-specific stuff
+ declare_builtin("__builtin_bfin_csync", &void_ctype, 0, NULL);
+ declare_builtin("__builtin_bfin_ssync", &void_ctype, 0, NULL);
+ declare_builtin("__builtin_bfin_norm_fr1x32", &int_ctype, 0, &int_ctype, NULL);
}
diff --git a/ident-list.h b/ident-list.h
index 2f1fecb4..a37a4a1b 100644
--- a/ident-list.h
+++ b/ident-list.h
@@ -59,16 +59,12 @@ IDENT_RESERVED(__label__);
* sparse. */
IDENT(defined);
IDENT(once);
+IDENT(__has_builtin);
__IDENT(pragma_ident, "__pragma__", 0);
__IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0);
-__IDENT(__LINE___ident, "__LINE__", 0);
-__IDENT(__FILE___ident, "__FILE__", 0);
-__IDENT(__DATE___ident, "__DATE__", 0);
-__IDENT(__TIME___ident, "__TIME__", 0);
__IDENT(__func___ident, "__func__", 0);
__IDENT(__FUNCTION___ident, "__FUNCTION__", 0);
__IDENT(__PRETTY_FUNCTION___ident, "__PRETTY_FUNCTION__", 0);
-__IDENT(__COUNTER___ident, "__COUNTER__", 0);
/* Sparse commands */
IDENT_RESERVED(__context__);
diff --git a/lib.c b/lib.c
index c451a88c..4692fe6d 100644
--- a/lib.c
+++ b/lib.c
@@ -60,6 +60,8 @@ int gcc_major = __GNUC__;
int gcc_minor = __GNUC_MINOR__;
int gcc_patchlevel = __GNUC_PATCHLEVEL__;
+const char *base_filename;
+
static const char *gcc_base_dir = GCC_BASE;
static const char *multiarch_dir = MULTIARCH_TRIPLET;
@@ -475,8 +477,8 @@ static void handle_arch_m64_finalize(void)
switch (arch_m64) {
case ARCH_X32:
max_int_alignment = 8;
- add_pre_buffer("#weak_define __ILP32__ 1\n");
- add_pre_buffer("#weak_define _ILP32 1\n");
+ predefine("__ILP32__", 1, "1");
+ predefine("_ILP32", 1, "1");
goto case_x86_64;
case ARCH_LP32:
/* default values */
@@ -486,15 +488,15 @@ static void handle_arch_m64_finalize(void)
max_int_alignment = 8;
size_t_ctype = &ulong_ctype;
ssize_t_ctype = &long_ctype;
- add_pre_buffer("#weak_define __LP64__ 1\n");
- add_pre_buffer("#weak_define _LP64 1\n");
+ predefine("__LP64__", 1, "1");
+ predefine("_LP64", 1, "1");
goto case_64bit_common;
case ARCH_LLP64:
bits_in_long = 32;
max_int_alignment = 8;
size_t_ctype = &ullong_ctype;
ssize_t_ctype = &llong_ctype;
- add_pre_buffer("#weak_define __LLP64__ 1\n");
+ predefine("__LLP64__", 1, "1");
goto case_64bit_common;
case_64bit_common:
bits_in_pointer = 64;
@@ -502,8 +504,8 @@ static void handle_arch_m64_finalize(void)
/* fall through */
case_x86_64:
#if defined(__x86_64__) || defined(__x86_64)
- add_pre_buffer("#weak_define __x86_64__ 1\n");
- add_pre_buffer("#weak_define __x86_64 1\n");
+ predefine("__x86_64__", 1, "1");
+ predefine("__x86_64", 1, "1");
#endif
break;
}
@@ -1109,14 +1111,19 @@ static char **handle_switch(char *arg, char **next)
static void predefined_sizeof(const char *name, unsigned bits)
{
- add_pre_buffer("#weak_define __SIZEOF_%s__ %d\n", name, bits/8);
+ char buf[32];
+
+ snprintf(buf, sizeof(buf), "__SIZEOF_%s__", name);
+ predefine(buf, 1, "%d", bits/8);
}
static void predefined_max(const char *name, const char *suffix, unsigned bits)
{
unsigned long long max = (1ULL << (bits - 1 )) - 1;
+ char buf[32];
- add_pre_buffer("#weak_define __%s_MAX__ %#llx%s\n", name, max, suffix);
+ snprintf(buf, sizeof(buf), "__%s_MAX__", name);
+ predefine(buf, 1, "%#llx%s", max, suffix);
}
static void predefined_type_size(const char *name, const char *suffix, unsigned bits)
@@ -1127,13 +1134,50 @@ static void predefined_type_size(const char *name, const char *suffix, unsigned
static void predefined_macros(void)
{
- add_pre_buffer("#define __CHECKER__ 1\n");
+ predefine("__CHECKER__", 0, "1");
+ predefine("__GNUC__", 1, "%d", gcc_major);
+ predefine("__GNUC_MINOR__", 1, "%d", gcc_minor);
+ predefine("__GNUC_PATCHLEVEL__", 1, "%d", gcc_patchlevel);
+
+ predefine("__STDC__", 1, "1");
+ switch (standard) {
+ case STANDARD_C89:
+ predefine("__STRICT_ANSI__", 1, "1");
+ break;
+
+ case STANDARD_C94:
+ predefine("__STDC_VERSION__", 1, "199409L");
+ predefine("__STRICT_ANSI__", 1, "1");
+ break;
+
+ case STANDARD_C99:
+ predefine("__STDC_VERSION__", 1, "199901L");
+ predefine("__STRICT_ANSI__", 1, "1");
+ break;
+
+ case STANDARD_GNU89:
+ default:
+ break;
+
+ case STANDARD_GNU99:
+ predefine("__STDC_VERSION__", 1, "199901L");
+ break;
+
+ case STANDARD_C11:
+ predefine("__STRICT_ANSI__", 1, "1");
+ case STANDARD_GNU11:
+ predefine("__STDC_NO_ATOMICS__", 1, "1");
+ predefine("__STDC_NO_COMPLEX__", 1, "1");
+ predefine("__STDC_NO_THREADS__", 1, "1");
+ predefine("__STDC_VERSION__", 1, "201112L");
+ break;
+ }
predefined_sizeof("SHORT", bits_in_short);
predefined_max("SHRT", "", bits_in_short);
predefined_max("SCHAR", "", bits_in_char);
predefined_max("WCHAR", "", bits_in_wchar);
- add_pre_buffer("#weak_define __CHAR_BIT__ %d\n", bits_in_char);
+ predefine("__CHAR_BIT__", 1, "%d", bits_in_char);
predefined_type_size("INT", "", bits_in_int);
predefined_type_size("LONG", "L", bits_in_long);
@@ -1149,52 +1193,30 @@ static void predefined_macros(void)
predefined_sizeof("DOUBLE", bits_in_double);
predefined_sizeof("LONG_DOUBLE", bits_in_longdouble);
- add_pre_buffer("#weak_define __%s_ENDIAN__ 1\n",
- arch_big_endian ? "BIG" : "LITTLE");
-
- add_pre_buffer("#weak_define __ORDER_LITTLE_ENDIAN__ 1234\n");
- add_pre_buffer("#weak_define __ORDER_BIG_ENDIAN__ 4321\n");
- add_pre_buffer("#weak_define __ORDER_PDP_ENDIAN__ 3412\n");
- add_pre_buffer("#weak_define __BYTE_ORDER__ __ORDER_%s_ENDIAN__\n",
- arch_big_endian ? "BIG" : "LITTLE");
-}
+ predefine("__ORDER_LITTLE_ENDIAN__", 1, "1234");
+ predefine("__ORDER_BIG_ENDIAN__", 1, "4321");
+ predefine("__ORDER_PDP_ENDIAN__", 1, "3412");
+ if (arch_big_endian) {
+ predefine("__BIG_ENDIAN__", 1, "1");
+ predefine("__BYTE_ORDER__", 1, "__ORDER_BIG_ENDIAN__");
+ } else {
+ predefine("__LITTLE_ENDIAN__", 1, "1");
+ predefine("__BYTE_ORDER__", 1, "__ORDER_LITTLE_ENDIAN__");
+ }
-static void declare_builtin_functions(void)
-{
- /* Note:
- * Most builtin functions are declared in builtin.c:declare_builtins().
- * Some are also defined in builtin:init_builtins().
- */
+ if (optimize_level)
+ predefine("__OPTIMIZE__", 0, "1");
+ if (optimize_size)
+ predefine("__OPTIMIZE_SIZE__", 0, "1");
- /* Add Blackfin-specific stuff */
- add_pre_buffer(
- "#ifdef __bfin__\n"
- "extern void __builtin_bfin_csync(void);\n"
- "extern void __builtin_bfin_ssync(void);\n"
- "extern int __builtin_bfin_norm_fr1x32(int);\n"
- "#endif\n"
- );
+ // Temporary hacks
+ predefine("__extension__", 0, NULL);
+ predefine("__pragma__", 0, NULL);
}
static void create_builtin_stream(void)
{
- add_pre_buffer("#weak_define __GNUC__ %d\n", gcc_major);
- add_pre_buffer("#weak_define __GNUC_MINOR__ %d\n", gcc_minor);
- add_pre_buffer("#weak_define __GNUC_PATCHLEVEL__ %d\n", gcc_patchlevel);
-
- /* add the multiarch include directories, if any */
- if (multiarch_dir && *multiarch_dir) {
- add_pre_buffer("#add_system \"/usr/include/%s\"\n", multiarch_dir);
- add_pre_buffer("#add_system \"/usr/local/include/%s\"\n", multiarch_dir);
- }
-
- /* We add compiler headers path here because we have to parse
- * the arguments to get it, falling back to default. */
- add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir);
- add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
-
- add_pre_buffer("#define __extension__\n");
- add_pre_buffer("#define __pragma__\n");
+ // Temporary hack
add_pre_buffer("#define _Pragma(x)\n");
// gcc defines __SIZE_TYPE__ to be size_t. For linux/i86 and
@@ -1206,44 +1228,20 @@ static void create_builtin_stream(void)
add_pre_buffer("#weak_define __SIZE_TYPE__ long unsigned int\n");
else
add_pre_buffer("#weak_define __SIZE_TYPE__ unsigned int\n");
- add_pre_buffer("#weak_define __STDC__ 1\n");
-
- switch (standard)
- {
- case STANDARD_C89:
- add_pre_buffer("#weak_define __STRICT_ANSI__\n");
- break;
-
- case STANDARD_C94:
- add_pre_buffer("#weak_define __STDC_VERSION__ 199409L\n");
- add_pre_buffer("#weak_define __STRICT_ANSI__\n");
- break;
- case STANDARD_C99:
- add_pre_buffer("#weak_define __STDC_VERSION__ 199901L\n");
- add_pre_buffer("#weak_define __STRICT_ANSI__\n");
- break;
-
- case STANDARD_GNU89:
- break;
-
- case STANDARD_GNU99:
- add_pre_buffer("#weak_define __STDC_VERSION__ 199901L\n");
- break;
-
- case STANDARD_C11:
- add_pre_buffer("#weak_define __STRICT_ANSI__ 1\n");
- case STANDARD_GNU11:
- add_pre_buffer("#weak_define __STDC_NO_ATOMICS__ 1\n");
- add_pre_buffer("#weak_define __STDC_NO_COMPLEX__ 1\n");
- add_pre_buffer("#weak_define __STDC_NO_THREADS__ 1\n");
- add_pre_buffer("#weak_define __STDC_VERSION__ 201112L\n");
- break;
- default:
- assert (0);
+ /* add the multiarch include directories, if any */
+ if (multiarch_dir && *multiarch_dir) {
+ add_pre_buffer("#add_system \"/usr/include/%s\"\n", multiarch_dir);
+ add_pre_buffer("#add_system \"/usr/local/include/%s\"\n", multiarch_dir);
}
+ /* We add compiler headers path here because we have to parse
+ * the arguments to get it, falling back to default. */
+ add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir);
+ add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
+
+ add_pre_buffer("#define __has_builtin(x) 0\n");
add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
@@ -1255,14 +1253,6 @@ static void create_builtin_stream(void)
add_pre_buffer("#define __builtin_va_end(arg)\n");
add_pre_buffer("#define __builtin_ms_va_end(arg)\n");
add_pre_buffer("#define __builtin_va_arg_pack()\n");
-
- /* FIXME! We need to do these as special magic macros at expansion time! */
- add_pre_buffer("#define __BASE_FILE__ \"base_file.c\"\n");
-
- if (optimize_level)
- add_pre_buffer("#define __OPTIMIZE__ 1\n");
- if (optimize_size)
- add_pre_buffer("#define __OPTIMIZE_SIZE__ 1\n");
}
static struct symbol_list *sparse_tokenstream(struct token *token)
@@ -1314,6 +1304,7 @@ static struct symbol_list *sparse_file(const char *filename)
if (fd < 0)
die("No such file: %s", filename);
}
+ base_filename = filename;
// Tokenize the input stream
token = tokenize(filename, fd, NULL, includepath);
@@ -1375,11 +1366,9 @@ struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list
// Initialize type system
init_ctype();
- declare_builtins();
- create_builtin_stream();
predefined_macros();
- if (!preprocess_only)
- declare_builtin_functions();
+ create_builtin_stream();
+ declare_builtins();
list = sparse_initial();
diff --git a/lib.h b/lib.h
index d7bd3651..c9a55b60 100644
--- a/lib.h
+++ b/lib.h
@@ -33,6 +33,7 @@
#include "compat.h"
#include "ptrlist.h"
+#include "utils.h"
#define DO_STRINGIFY(x) #x
#define STRINGIFY(x) DO_STRINGIFY(x)
@@ -46,6 +47,8 @@ extern int die_if_error;
extern int repeat_phase;
extern int gcc_major, gcc_minor, gcc_patchlevel;
+extern const char *base_filename;
+
extern unsigned int hexval(unsigned int c);
struct position {
@@ -127,6 +130,7 @@ enum phase {
extern void add_pre_buffer(const char *fmt, ...) FORMAT_ATTR(1);
+extern void predefine(const char *name, int weak, const char *fmt, ...) FORMAT_ATTR(3);
extern int preprocess_only;
diff --git a/pre-process.c b/pre-process.c
index 7d335ab0..da4b7acd 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -47,6 +47,7 @@
static struct ident_list *macros; // only needed for -dD
static int false_nesting = 0;
static int counter_macro = 0; // __COUNTER__ expansion
+static int include_level = 0;
#define INCLUDEPATHS 300
const char *includepath[INCLUDEPATHS+1] = {
@@ -145,48 +146,89 @@ static int token_defined(struct token *token)
return 0;
}
-static void replace_with_defined(struct token *token)
+static void replace_with_bool(struct token *token, bool val)
{
static const char *string[] = { "0", "1" };
- int defined = token_defined(token);
token_type(token) = TOKEN_NUMBER;
- token->number = string[defined];
+ token->number = string[val];
+}
+
+static void replace_with_defined(struct token *token)
+{
+ replace_with_bool(token, token_defined(token));
+}
+
+static void replace_with_has_builtin(struct token *token)
+{
+ struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL);
+ replace_with_bool(token, sym && sym->builtin);
+}
+
+static void expand_line(struct token *token)
+{
+ replace_with_integer(token, token->pos.line);
+}
+
+static void expand_file(struct token *token)
+{
+ replace_with_string(token, stream_name(token->pos.stream));
+}
+
+static void expand_basefile(struct token *token)
+{
+ replace_with_string(token, base_filename);
+}
+
+static time_t t = 0;
+static void expand_date(struct token *token)
+{
+ static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
+
+ if (!t)
+ time(&t);
+ strftime(buffer, 12, "%b %e %Y", localtime(&t));
+ replace_with_string(token, buffer);
+}
+
+static void expand_time(struct token *token)
+{
+ static char buffer[9]; /* __TIME__: 2 + ':' + 2 + ':' + 2 + '\0' */
+
+ if (!t)
+ time(&t);
+ strftime(buffer, 9, "%T", localtime(&t));
+ replace_with_string(token, buffer);
+}
+
+static void expand_counter(struct token *token)
+{
+ replace_with_integer(token, counter_macro++);
+}
+
+static void expand_include_level(struct token *token)
+{
+ replace_with_integer(token, include_level - 1);
}
static int expand_one_symbol(struct token **list)
{
struct token *token = *list;
struct symbol *sym;
- static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
- static time_t t = 0;
if (token->pos.noexpand)
return 1;
sym = lookup_macro(token->ident);
- if (sym) {
+ if (!sym)
+ return 1;
+ if (sym->expander) {
+ sym->expander(token);
+ return 1;
+ } else {
sym->used_in = file_scope;
return expand(list, sym);
}
- if (token->ident == &__LINE___ident) {
- replace_with_integer(token, token->pos.line);
- } else if (token->ident == &__FILE___ident) {
- replace_with_string(token, stream_name(token->pos.stream));
- } else if (token->ident == &__DATE___ident) {
- if (!t)
- time(&t);
- strftime(buffer, 12, "%b %e %Y", localtime(&t));
- replace_with_string(token, buffer);
- } else if (token->ident == &__TIME___ident) {
- if (!t)
- time(&t);
- strftime(buffer, 9, "%T", localtime(&t));
- replace_with_string(token, buffer);
- } else if (token->ident == &__COUNTER___ident) {
- replace_with_integer(token, counter_macro++);
- }
- return 1;
}
static inline struct token *scan_next(struct token **where)
@@ -511,13 +553,10 @@ static int merge(struct token *left, struct token *right)
left->pos.noexpand = 0;
return 1;
- case TOKEN_NUMBER: {
- char *number = __alloc_bytes(strlen(buffer) + 1);
- memcpy(number, buffer, strlen(buffer) + 1);
+ case TOKEN_NUMBER:
token_type(left) = TOKEN_NUMBER; /* could be . + num */
- left->number = number;
+ left->number = xstrdup(buffer);
return 1;
- }
case TOKEN_SPECIAL:
if (buffer[2] && buffer[3])
@@ -868,8 +907,7 @@ static int try_include(const char *path, const char *filename, int flen, struct
return 1;
fd = open(fullname, O_RDONLY);
if (fd >= 0) {
- char * streamname = __alloc_bytes(plen + flen);
- memcpy(streamname, fullname, plen + flen);
+ char *streamname = xmemdup(fullname, plen + flen);
*where = tokenize(streamname, fd, *where, next_path);
close(fd);
return 1;
@@ -1299,40 +1337,16 @@ Earg:
return NULL;
}
-static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
+static int do_define(struct position pos, struct token *token, struct ident *name,
+ struct token *arglist, struct token *expansion, int attr)
{
- struct token *arglist, *expansion;
- struct token *left = token->next;
struct symbol *sym;
- struct ident *name;
- int ret;
-
- if (token_type(left) != TOKEN_IDENT) {
- sparse_error(token->pos, "expected identifier to 'define'");
- return 1;
- }
-
- name = left->ident;
-
- arglist = NULL;
- expansion = left->next;
- if (!expansion->pos.whitespace) {
- if (match_op(expansion, '(')) {
- arglist = expansion;
- expansion = parse_arguments(expansion);
- if (!expansion)
- return 1;
- } else if (!eof_token(expansion)) {
- warning(expansion->pos,
- "no whitespace before object-like macro body");
- }
- }
+ int ret = 1;
expansion = parse_expansion(expansion, arglist, name);
if (!expansion)
return 1;
- ret = 1;
sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
if (sym) {
int clean;
@@ -1347,7 +1361,7 @@ static int do_handle_define(struct stream *stream, struct token **line, struct t
ret = 0;
if ((clean && attr == SYM_ATTR_NORMAL)
|| sym->used_in == file_scope) {
- warning(left->pos, "preprocessor token %.*s redefined",
+ warning(pos, "preprocessor token %.*s redefined",
name->len, name->name);
info(sym->pos, "this was the original definition");
}
@@ -1356,7 +1370,7 @@ static int do_handle_define(struct stream *stream, struct token **line, struct t
}
if (!sym || sym->scope != file_scope) {
- sym = alloc_symbol(left->pos, SYM_NODE);
+ sym = alloc_symbol(pos, SYM_NODE);
bind_symbol(sym, name, NS_MACRO);
add_ident(&macros, name);
ret = 0;
@@ -1365,7 +1379,8 @@ static int do_handle_define(struct stream *stream, struct token **line, struct t
if (!ret) {
sym->expansion = expansion;
sym->arglist = arglist;
- __free_token(token); /* Free the "define" token, but not the rest of the line */
+ if (token) /* Free the "define" token, but not the rest of the line */
+ __free_token(token);
}
sym->namespace = NS_MACRO;
@@ -1375,6 +1390,74 @@ out:
return ret;
}
+///
+// predefine a macro with a printf-formatted value
+// @name: the name of the macro
+// @weak: 0/1 for a normal or a weak define
+// @fmt: the printf format followed by it's arguments.
+//
+// The type of the value is automatically infered:
+// TOKEN_NUMBER if it starts by a digit, TOKEN_IDENT otherwise.
+// If @fmt is null or empty, the macro is defined with an empty definition.
+void predefine(const char *name, int weak, const char *fmt, ...)
+{
+ struct ident *ident = built_in_ident(name);
+ struct token *value = &eof_token_entry;
+ int attr = weak ? SYM_ATTR_WEAK : SYM_ATTR_NORMAL;
+
+ if (fmt && fmt[0]) {
+ static char buf[256];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ value = __alloc_token(0);
+ if (isdigit(buf[0])) {
+ token_type(value) = TOKEN_NUMBER;
+ value->number = xstrdup(buf);
+ } else {
+ token_type(value) = TOKEN_IDENT;
+ value->ident = built_in_ident(buf);
+ }
+ value->pos.whitespace = 1;
+ value->next = &eof_token_entry;
+ }
+
+ do_define(value->pos, NULL, ident, NULL, value, attr);
+}
+
+static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
+{
+ struct token *arglist, *expansion;
+ struct token *left = token->next;
+ struct ident *name;
+
+ if (token_type(left) != TOKEN_IDENT) {
+ sparse_error(token->pos, "expected identifier to 'define'");
+ return 1;
+ }
+
+ name = left->ident;
+
+ arglist = NULL;
+ expansion = left->next;
+ if (!expansion->pos.whitespace) {
+ if (match_op(expansion, '(')) {
+ arglist = expansion;
+ expansion = parse_arguments(expansion);
+ if (!expansion)
+ return 1;
+ } else if (!eof_token(expansion)) {
+ warning(expansion->pos,
+ "no whitespace before object-like macro body");
+ }
+ }
+
+ return do_define(left->pos, token, name, arglist, expansion, attr);
+}
+
static int handle_define(struct stream *stream, struct token **line, struct token *token)
{
return do_handle_define(stream, line, token, SYM_ATTR_NORMAL);
@@ -1505,6 +1588,10 @@ static int expression_value(struct token **where)
state = 1;
beginning = list;
break;
+ } else if (p->ident == &__has_builtin_ident) {
+ state = 4;
+ beginning = list;
+ break;
}
if (!expand_one_symbol(list))
continue;
@@ -1535,6 +1622,33 @@ static int expression_value(struct token **where)
sparse_error(p->pos, "missing ')' after \"defined\"");
*list = p->next;
continue;
+
+ // __has_builtin(xyz)
+ case 4:
+ if (match_op(p, '(')) {
+ state = 5;
+ } else {
+ sparse_error(p->pos, "missing '(' after \"__has_builtin\"");
+ state = 0;
+ }
+ *beginning = p;
+ break;
+ case 5:
+ if (token_type(p) != TOKEN_IDENT) {
+ sparse_error(p->pos, "identifier expected");
+ state = 0;
+ break;
+ }
+ if (!match_op(p->next, ')'))
+ sparse_error(p->pos, "missing ')' after \"__has_builtin\"");
+ state = 6;
+ replace_with_has_builtin(p);
+ *beginning = p;
+ break;
+ case 6:
+ state = 0;
+ *list = p->next;
+ continue;
}
list = &p->next;
}
@@ -1891,6 +2005,18 @@ static void init_preprocessor(void)
{ "if", handle_if },
{ "elif", handle_elif },
};
+ static struct {
+ const char *name;
+ void (*expander)(struct token *);
+ } dynamic[] = {
+ { "__LINE__", expand_line },
+ { "__FILE__", expand_file },
+ { "__BASE_FILE__", expand_basefile },
+ { "__DATE__", expand_date },
+ { "__TIME__", expand_time },
+ { "__COUNTER__", expand_counter },
+ { "__INCLUDE_LEVEL__", expand_include_level },
+ };
for (i = 0; i < ARRAY_SIZE(normal); i++) {
struct symbol *sym;
@@ -1904,6 +2030,11 @@ static void init_preprocessor(void)
sym->handler = special[i].handler;
sym->normal = 0;
}
+ for (i = 0; i < ARRAY_SIZE(dynamic); i++) {
+ struct symbol *sym;
+ sym = create_symbol(stream, dynamic[i].name, SYM_NODE, NS_MACRO);
+ sym->expander = dynamic[i].expander;
+ }
counter_macro = 0;
}
@@ -1985,9 +2116,11 @@ static void do_preprocess(struct token **list)
if (!stream->dirty)
stream->constant = CONSTANT_FILE_YES;
*list = next->next;
+ include_level--;
continue;
case TOKEN_STREAMBEGIN:
*list = next->next;
+ include_level++;
continue;
default:
diff --git a/symbol.c b/symbol.c
index 4484eb5b..2dcabe85 100644
--- a/symbol.c
+++ b/symbol.c
@@ -697,6 +697,9 @@ struct symbol bool_ctype, void_ctype, type_ctype,
string_ctype, ptr_ctype, lazy_ptr_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_ctype;
+struct symbol int_ptr_ctype, uint_ptr_ctype;
+struct symbol long_ptr_ctype, ulong_ptr_ctype;
+struct symbol llong_ptr_ctype, ullong_ptr_ctype;
struct symbol float32_ctype, float32x_ctype;
struct symbol float64_ctype, float64x_ctype;
struct symbol float128_ctype;
@@ -779,6 +782,12 @@ static const struct ctype_declare {
{ &null_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype },
{ &label_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype },
{ &lazy_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype },
+ { &int_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &int_ctype },
+ { &uint_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &uint_ctype },
+ { &long_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &long_ctype },
+ { &ulong_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &ulong_ctype },
+ { &llong_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &llong_ctype },
+ { &ullong_ptr_ctype,SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &ullong_ctype },
{ &const_void_ctype, SYM_NODE, MOD_CONST, NULL, NULL, &void_ctype },
{ &const_char_ctype, SYM_NODE, MOD_CONST, &bits_in_char, &max_int_alignment, &char_ctype },
diff --git a/symbol.h b/symbol.h
index 4edb4404..6d23503f 100644
--- a/symbol.h
+++ b/symbol.h
@@ -155,6 +155,7 @@ struct symbol {
struct token *expansion;
struct token *arglist;
struct scope *used_in;
+ void (*expander)(struct token *);
};
struct /* NS_PREPROCESSOR */ {
int (*handler)(struct stream *, struct token **, struct token *);
@@ -173,6 +174,7 @@ struct symbol {
designated_init:1,
forced_arg:1,
accessed:1,
+ builtin:1,
transparent_union:1;
struct expression *array_size;
struct ctype ctype;
@@ -267,6 +269,9 @@ extern struct symbol bool_ctype, void_ctype, type_ctype,
string_ctype, ptr_ctype, lazy_ptr_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_ctype;
+extern struct symbol int_ptr_ctype, uint_ptr_ctype;
+extern struct symbol long_ptr_ctype, ulong_ptr_ctype;
+extern struct symbol llong_ptr_ctype, ullong_ptr_ctype;
extern struct symbol float32_ctype, float32x_ctype;
extern struct symbol float64_ctype, float64x_ctype;
extern struct symbol float128_ctype;
diff --git a/tokenize.c b/tokenize.c
index 1118786f..fa7890d3 100644
--- a/tokenize.c
+++ b/tokenize.c
@@ -528,8 +528,7 @@ static int get_one_number(int c, int next, stream_t *stream)
{
struct token *token;
static char buffer[4095];
- char *p = buffer, *buf, *buffer_end = buffer + sizeof (buffer);
- int len;
+ char *p = buffer, *buffer_end = buffer + sizeof (buffer);
*p++ = c;
for (;;) {
@@ -557,13 +556,9 @@ static int get_one_number(int c, int next, stream_t *stream)
}
*p++ = 0;
- len = p - buffer;
- buf = __alloc_bytes(len);
- memcpy(buf, buffer, len);
-
token = stream->token;
token_type(token) = TOKEN_NUMBER;
- token->number = buf;
+ token->number = xmemdup(buffer, p - buffer);
add_token(stream);
return next;
diff --git a/utils.c b/utils.c
new file mode 100644
index 00000000..4945e1ca
--- /dev/null
+++ b/utils.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: MIT
+// Copyright (C) 2018 Luc Van Oostenryck
+
+#include "utils.h"
+#include "allocate.h"
+#include <string.h>
+
+
+void *xmemdup(const void *src, size_t len)
+{
+ return memcpy(__alloc_bytes(len), src, len);
+}
+
+char *xstrdup(const char *src)
+{
+ return xmemdup(src, strlen(src) + 1);
+}
diff --git a/utils.h b/utils.h
new file mode 100644
index 00000000..38749be2
--- /dev/null
+++ b/utils.h
@@ -0,0 +1,25 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+///
+// Miscellaneous utilities
+// -----------------------
+
+#include <stddef.h>
+
+///
+// duplicate a memory buffer in a newly allocated buffer.
+// @src: a pointer to the memory buffer to be duplicated
+// @len: the size of the memory buffer to be duplicated
+// @return: a pointer to a copy of @src allocated via
+// :func:`__alloc_bytes()`.
+void *xmemdup(const void *src, size_t len);
+
+///
+// duplicate a null-terminated string in a newly allocated buffer.
+// @src: a pointer to string to be duplicated
+// @return: a pointer to a copy of @str allocated via
+// :func:`__alloc_bytes()`.
+char *xstrdup(const char *src);
+
+#endif
diff --git a/validation/builtin-overflow.c b/validation/builtin-overflow.c
new file mode 100644
index 00000000..867eb42f
--- /dev/null
+++ b/validation/builtin-overflow.c
@@ -0,0 +1,246 @@
+enum e { OK };
+typedef _Bool bool;
+
+static int test(int i, long l, long long ll, enum e e, bool b, void *p)
+{
+ int rc = 0;
+
+ // should be OK
+ rc += __builtin_add_overflow(i, i, &i);
+ rc += __builtin_add_overflow(l, i, &i);
+ rc += __builtin_add_overflow(i, l, &i);
+ rc += __builtin_add_overflow(i, i, &l);
+ rc += __builtin_add_overflow(ll, i, &i);
+ rc += __builtin_add_overflow(i, ll, &i);
+ rc += __builtin_add_overflow(i, i, &ll);
+
+ rc += __builtin_add_overflow_p(i, i, i);
+ rc += __builtin_add_overflow_p(l, i, i);
+ rc += __builtin_add_overflow_p(i, l, i);
+ rc += __builtin_add_overflow_p(i, i, l);
+ rc += __builtin_add_overflow_p(ll, i, i);
+ rc += __builtin_add_overflow_p(i, ll, i);
+ rc += __builtin_add_overflow_p(i, i, ll);
+
+ rc += __builtin_sub_overflow(i, i, &i);
+ rc += __builtin_sub_overflow(l, i, &i);
+ rc += __builtin_sub_overflow(i, l, &i);
+ rc += __builtin_sub_overflow(i, i, &l);
+ rc += __builtin_sub_overflow(ll, i, &i);
+ rc += __builtin_sub_overflow(i, ll, &i);
+ rc += __builtin_sub_overflow(i, i, &ll);
+
+ rc += __builtin_sub_overflow_p(i, i, i);
+ rc += __builtin_sub_overflow_p(l, i, i);
+ rc += __builtin_sub_overflow_p(i, l, i);
+ rc += __builtin_sub_overflow_p(i, i, l);
+ rc += __builtin_sub_overflow_p(ll, i, i);
+ rc += __builtin_sub_overflow_p(i, ll, i);
+ rc += __builtin_sub_overflow_p(i, i, ll);
+
+ rc += __builtin_mul_overflow(i, i, &i);
+ rc += __builtin_mul_overflow(l, i, &i);
+ rc += __builtin_mul_overflow(i, l, &i);
+ rc += __builtin_mul_overflow(i, i, &l);
+ rc += __builtin_mul_overflow(ll, i, &i);
+ rc += __builtin_mul_overflow(i, ll, &i);
+ rc += __builtin_mul_overflow(i, i, &ll);
+
+ rc += __builtin_mul_overflow_p(i, i, i);
+ rc += __builtin_mul_overflow_p(l, i, i);
+ rc += __builtin_mul_overflow_p(i, l, i);
+ rc += __builtin_mul_overflow_p(i, i, l);
+ rc += __builtin_mul_overflow_p(ll, i, i);
+ rc += __builtin_mul_overflow_p(i, ll, i);
+ rc += __builtin_mul_overflow_p(i, i, ll);
+
+ // should be KO
+ rc += __builtin_add_overflow();
+ rc += __builtin_add_overflow(i);
+ rc += __builtin_add_overflow(i, i);
+ rc += __builtin_add_overflow(i, i, &i, i);
+ rc += __builtin_add_overflow(e, i, &i);
+ rc += __builtin_add_overflow(i, e, &i);
+ rc += __builtin_add_overflow(i, i, &e);
+ rc += __builtin_add_overflow(b, i, &i);
+ rc += __builtin_add_overflow(i, b, &i);
+ rc += __builtin_add_overflow(i, i, &b);
+ rc += __builtin_add_overflow(i, i, p);
+
+ rc += __builtin_add_overflow_p();
+ rc += __builtin_add_overflow_p(i);
+ rc += __builtin_add_overflow_p(i, i);
+ rc += __builtin_add_overflow_p(i, i, i, i);
+ rc += __builtin_add_overflow_p(e, i, i);
+ rc += __builtin_add_overflow_p(i, e, i);
+ rc += __builtin_add_overflow_p(i, i, e);
+ rc += __builtin_add_overflow_p(b, i, i);
+ rc += __builtin_add_overflow_p(i, b, i);
+ rc += __builtin_add_overflow_p(i, i, b);
+ rc += __builtin_add_overflow_p(i, i, p);
+
+ rc += __builtin_sub_overflow();
+ rc += __builtin_sub_overflow(i);
+ rc += __builtin_sub_overflow(i, i);
+ rc += __builtin_sub_overflow(i, i, &i, i);
+ rc += __builtin_sub_overflow(e, i, &i);
+ rc += __builtin_sub_overflow(i, e, &i);
+ rc += __builtin_sub_overflow(i, i, &e);
+ rc += __builtin_sub_overflow(b, i, &i);
+ rc += __builtin_sub_overflow(i, b, &i);
+ rc += __builtin_sub_overflow(i, i, &b);
+ rc += __builtin_sub_overflow(i, i, p);
+
+ rc += __builtin_sub_overflow_p();
+ rc += __builtin_sub_overflow_p(i);
+ rc += __builtin_sub_overflow_p(i, i);
+ rc += __builtin_sub_overflow_p(i, i, i, i);
+ rc += __builtin_sub_overflow_p(e, i, i);
+ rc += __builtin_sub_overflow_p(i, e, i);
+ rc += __builtin_sub_overflow_p(i, i, e);
+ rc += __builtin_sub_overflow_p(b, i, i);
+ rc += __builtin_sub_overflow_p(i, b, i);
+ rc += __builtin_sub_overflow_p(i, i, b);
+ rc += __builtin_sub_overflow_p(i, i, p);
+
+ rc += __builtin_mul_overflow();
+ rc += __builtin_mul_overflow(i);
+ rc += __builtin_mul_overflow(i, i);
+ rc += __builtin_mul_overflow(i, i, &i, i);
+ rc += __builtin_mul_overflow(e, i, &i);
+ rc += __builtin_mul_overflow(i, e, &i);
+ rc += __builtin_mul_overflow(i, i, &e);
+ rc += __builtin_mul_overflow(b, i, &i);
+ rc += __builtin_mul_overflow(i, b, &i);
+ rc += __builtin_mul_overflow(i, i, &b);
+ rc += __builtin_mul_overflow(i, i, p);
+
+ rc += __builtin_mul_overflow_p();
+ rc += __builtin_mul_overflow_p(i);
+ rc += __builtin_mul_overflow_p(i, i);
+ rc += __builtin_mul_overflow_p(i, i, i, i);
+ rc += __builtin_mul_overflow_p(e, i, i);
+ rc += __builtin_mul_overflow_p(i, e, i);
+ rc += __builtin_mul_overflow_p(i, i, e);
+ rc += __builtin_mul_overflow_p(b, i, i);
+ rc += __builtin_mul_overflow_p(i, b, i);
+ rc += __builtin_mul_overflow_p(i, i, b);
+ rc += __builtin_mul_overflow_p(i, i, p);
+
+ return rc;
+}
+
+/*
+ * check-name: builtin-overflow
+ *
+ * check-error-start
+builtin-overflow.c:58:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:59:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:60:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:61:37: error: too many arguments for __builtin_add_overflow
+builtin-overflow.c:62:38: error: invalid type for argument 1:
+builtin-overflow.c:62:38: int enum e [signed] e
+builtin-overflow.c:63:41: error: invalid type for argument 2:
+builtin-overflow.c:63:41: int enum e [signed] e
+builtin-overflow.c:64:45: error: invalid type for argument 3:
+builtin-overflow.c:64:45: int enum e *<noident>
+builtin-overflow.c:65:38: error: invalid type for argument 1:
+builtin-overflow.c:65:38: bool [unsigned] [usertype] b
+builtin-overflow.c:66:41: error: invalid type for argument 2:
+builtin-overflow.c:66:41: bool [unsigned] [usertype] b
+builtin-overflow.c:67:45: error: invalid type for argument 3:
+builtin-overflow.c:67:45: bool *<noident>
+builtin-overflow.c:68:44: error: invalid type for argument 3:
+builtin-overflow.c:68:44: void *p
+builtin-overflow.c:70:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:71:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:72:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:73:39: error: too many arguments for __builtin_add_overflow_p
+builtin-overflow.c:74:40: error: invalid type for argument 1:
+builtin-overflow.c:74:40: int enum e [signed] [addressable] e
+builtin-overflow.c:75:43: error: invalid type for argument 2:
+builtin-overflow.c:75:43: int enum e [signed] [addressable] e
+builtin-overflow.c:76:46: error: invalid type for argument 3:
+builtin-overflow.c:76:46: int enum e [signed] [addressable] e
+builtin-overflow.c:77:40: error: invalid type for argument 1:
+builtin-overflow.c:77:40: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:78:43: error: invalid type for argument 2:
+builtin-overflow.c:78:43: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:79:46: error: invalid type for argument 3:
+builtin-overflow.c:79:46: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:80:46: error: invalid type for argument 3:
+builtin-overflow.c:80:46: void *p
+builtin-overflow.c:82:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:83:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:84:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:85:37: error: too many arguments for __builtin_sub_overflow
+builtin-overflow.c:86:38: error: invalid type for argument 1:
+builtin-overflow.c:86:38: int enum e [signed] [addressable] e
+builtin-overflow.c:87:41: error: invalid type for argument 2:
+builtin-overflow.c:87:41: int enum e [signed] [addressable] e
+builtin-overflow.c:88:45: error: invalid type for argument 3:
+builtin-overflow.c:88:45: int enum e *<noident>
+builtin-overflow.c:89:38: error: invalid type for argument 1:
+builtin-overflow.c:89:38: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:90:41: error: invalid type for argument 2:
+builtin-overflow.c:90:41: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:91:45: error: invalid type for argument 3:
+builtin-overflow.c:91:45: bool *<noident>
+builtin-overflow.c:92:44: error: invalid type for argument 3:
+builtin-overflow.c:92:44: void *p
+builtin-overflow.c:94:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:95:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:96:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:97:39: error: too many arguments for __builtin_sub_overflow_p
+builtin-overflow.c:98:40: error: invalid type for argument 1:
+builtin-overflow.c:98:40: int enum e [signed] [addressable] e
+builtin-overflow.c:99:43: error: invalid type for argument 2:
+builtin-overflow.c:99:43: int enum e [signed] [addressable] e
+builtin-overflow.c:100:46: error: invalid type for argument 3:
+builtin-overflow.c:100:46: int enum e [signed] [addressable] e
+builtin-overflow.c:101:40: error: invalid type for argument 1:
+builtin-overflow.c:101:40: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:102:43: error: invalid type for argument 2:
+builtin-overflow.c:102:43: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:103:46: error: invalid type for argument 3:
+builtin-overflow.c:103:46: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:104:46: error: invalid type for argument 3:
+builtin-overflow.c:104:46: void *p
+builtin-overflow.c:106:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:107:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:108:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:109:37: error: too many arguments for __builtin_mul_overflow
+builtin-overflow.c:110:38: error: invalid type for argument 1:
+builtin-overflow.c:110:38: int enum e [signed] [addressable] e
+builtin-overflow.c:111:41: error: invalid type for argument 2:
+builtin-overflow.c:111:41: int enum e [signed] [addressable] e
+builtin-overflow.c:112:45: error: invalid type for argument 3:
+builtin-overflow.c:112:45: int enum e *<noident>
+builtin-overflow.c:113:38: error: invalid type for argument 1:
+builtin-overflow.c:113:38: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:114:41: error: invalid type for argument 2:
+builtin-overflow.c:114:41: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:115:45: error: invalid type for argument 3:
+builtin-overflow.c:115:45: bool *<noident>
+builtin-overflow.c:116:44: error: invalid type for argument 3:
+builtin-overflow.c:116:44: void *p
+builtin-overflow.c:118:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:119:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:120:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:121:39: error: too many arguments for __builtin_mul_overflow_p
+builtin-overflow.c:122:40: error: invalid type for argument 1:
+builtin-overflow.c:122:40: int enum e [signed] [addressable] e
+builtin-overflow.c:123:43: error: invalid type for argument 2:
+builtin-overflow.c:123:43: int enum e [signed] [addressable] e
+builtin-overflow.c:124:46: error: invalid type for argument 3:
+builtin-overflow.c:124:46: int enum e [signed] [addressable] e
+builtin-overflow.c:125:40: error: invalid type for argument 1:
+builtin-overflow.c:125:40: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:126:43: error: invalid type for argument 2:
+builtin-overflow.c:126:43: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:127:46: error: invalid type for argument 3:
+builtin-overflow.c:127:46: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:128:46: error: invalid type for argument 3:
+builtin-overflow.c:128:46: void *p
+ * check-error-end
+ */
diff --git a/validation/preprocessor/base-file.c b/validation/preprocessor/base-file.c
new file mode 100644
index 00000000..61a290cb
--- /dev/null
+++ b/validation/preprocessor/base-file.c
@@ -0,0 +1,17 @@
+__FILE__
+__BASE_FILE__
+
+#include "base-file.h"
+
+/*
+ * check-name: base file
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"preprocessor/base-file.c"
+"preprocessor/base-file.c"
+"preprocessor/base-file.h"
+"preprocessor/base-file.c"
+ * check-output-end
+ */
diff --git a/validation/preprocessor/base-file.h b/validation/preprocessor/base-file.h
new file mode 100644
index 00000000..018b16c5
--- /dev/null
+++ b/validation/preprocessor/base-file.h
@@ -0,0 +1,2 @@
+__FILE__
+__BASE_FILE__
diff --git a/validation/preprocessor/builtin.c b/validation/preprocessor/builtin.c
new file mode 100644
index 00000000..6c3aa176
--- /dev/null
+++ b/validation/preprocessor/builtin.c
@@ -0,0 +1,17 @@
+__CHECKER__
+F(__CHECKER__,__CHECKER__)
+S(#__CHECKER__)
+const char str[] = "__CHECKER__";
+
+/*
+ * check-name: builtin
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+1
+F(1,1)
+S(#1)
+const char str[] = "__CHECKER__";
+ * check-output-end
+ */
diff --git a/validation/preprocessor/dynamic.c b/validation/preprocessor/dynamic.c
new file mode 100644
index 00000000..f791ba39
--- /dev/null
+++ b/validation/preprocessor/dynamic.c
@@ -0,0 +1,37 @@
+#if defined(__LINE__)
+__LINE__
+#endif
+#if defined(__FILE__)
+__FILE__
+#endif
+#if defined(__BASE_FILE__)
+__BASE_FILE__
+#endif
+#if defined(__DATE__)
+date
+#endif
+#if defined(__TIME__)
+time
+#endif
+#if defined(__COUNTER__)
+counter
+#endif
+#if defined(__INCLUDE_LEVEL__)
+__INCLUDE_LEVEL__
+#endif
+
+/*
+ * check-name: dynamic-macros
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+2
+"preprocessor/dynamic.c"
+"preprocessor/dynamic.c"
+date
+time
+counter
+0
+ * check-output-end
+ */
diff --git a/validation/preprocessor/has-builtin.c b/validation/preprocessor/has-builtin.c
new file mode 100644
index 00000000..03272fc9
--- /dev/null
+++ b/validation/preprocessor/has-builtin.c
@@ -0,0 +1,43 @@
+#ifndef __has_builtin
+__has_builtin()??? Quesako?
+#define __has_builtin(x) 0
+#else
+"has __has_builtin(), yeah!"
+#endif
+
+#if __has_builtin(nothing)
+#error "not a builtin!"
+#endif
+
+#if __has_builtin(__builtin_offsetof) \
+ || __has_builtin(__builtin_types_compatible_p)
+#error "builtin ops are not builtin functions!"
+#endif
+
+#if __has_builtin(__builtin_va_list) \
+ || __has_builtin(__builtin_ms_va_list)
+#error "builtin types are not builtin functions!"
+#endif
+
+#if __has_builtin(__builtin_abs)
+abs
+#endif
+
+#if __has_builtin(__builtin_constant_p)
+constant_p
+#endif
+
+123 __has_builtin(abc) def
+
+/*
+ * check-name: has-builtin
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"has __has_builtin(), yeah!"
+abs
+constant_p
+123 0 def
+ * check-output-end
+ */
diff --git a/validation/preprocessor/include-level.c b/validation/preprocessor/include-level.c
new file mode 100644
index 00000000..b5e5e603
--- /dev/null
+++ b/validation/preprocessor/include-level.c
@@ -0,0 +1,14 @@
+__FILE__: __INCLUDE_LEVEL__
+
+#include "include-level.h"
+
+/*
+ * check-name: include-level
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"preprocessor/include-level.c": 0
+"preprocessor/include-level.h": 1
+ * check-output-end
+ */
diff --git a/validation/preprocessor/include-level.h b/validation/preprocessor/include-level.h
new file mode 100644
index 00000000..cbc10182
--- /dev/null
+++ b/validation/preprocessor/include-level.h
@@ -0,0 +1 @@
+__FILE__: __INCLUDE_LEVEL__