diff --git a/ast/ast.c2 b/ast/ast.c2 index 994c7abfc..da6d55fdd 100644 --- a/ast/ast.c2 +++ b/ast/ast.c2 @@ -45,7 +45,11 @@ public type AST struct @(opaque) { attr_table.Table* attrs; } +#if ARCH_32BIT +static_assert(132, sizeof(AST)); +#else static_assert(144+64, sizeof(AST)); +#endif fn AST* AST.create(string_pool.Pool* auxPool, u32 name, Module* mod, bool is_interface, bool is_generated) { AST* a = stdlib.calloc(1, sizeof(AST)); diff --git a/ast/member_expr.c2 b/ast/member_expr.c2 index 444c71827..e25743b70 100644 --- a/ast/member_expr.c2 +++ b/ast/member_expr.c2 @@ -57,7 +57,11 @@ type MemberRef union { usize bits; } +#if ARCH_32BIT +static_assert(4, sizeof(MemberRef)); +#else static_assert(8, sizeof(MemberRef)); +#endif public type MemberExpr struct @(opaque) { // base.loc points to the beginning of the member name in refs[1] diff --git a/ast/module.c2 b/ast/module.c2 index 75d144637..de04d4550 100644 --- a/ast/module.c2 +++ b/ast/module.c2 @@ -40,7 +40,11 @@ public type Module struct @(opaque) { SymbolTable symbols; InstanceTable instances; } +#if ARCH_32BIT +static_assert(56, sizeof(Module)); +#else static_assert(80, sizeof(Module)); +#endif // Note: name must be allocated in target StringPool public fn Module* Module.create(ast_context.Context* c, u32 name_idx, bool is_external) { diff --git a/ast/struct_type_decl.c2 b/ast/struct_type_decl.c2 index 3ebfef815..025120eb1 100644 --- a/ast/struct_type_decl.c2 +++ b/ast/struct_type_decl.c2 @@ -50,7 +50,11 @@ public type FieldInitField struct { // 1 byte padding Decl* decl; // can point to anonymous sub-struct members as well } +#if ARCH_32BIT +static_assert(20, sizeof(FieldInitField)); +#else static_assert(24, sizeof(FieldInitField)); +#endif public fn bool FieldInitField.isZeroSizeBitfield(const FieldInitField* f) { return f.is_bitfield && f.bitfield_width == 0; diff --git a/ast/type_ref.c2 b/ast/type_ref.c2 index 1c7d10f8f..94a9a36bc 100644 --- a/ast/type_ref.c2 +++ b/ast/type_ref.c2 @@ -42,7 +42,12 @@ public type Ref struct { u32 name_idx; Decl* decl; // set during analysis, or during parsing for Function } + +#if ARCH_32BIT +static_assert(12, sizeof(Ref)); +#else static_assert(16, sizeof(Ref)); +#endif public fn u32 Ref.getNameIdx(const Ref* r) { return r.name_idx; diff --git a/ast/utils.c2 b/ast/utils.c2 index 56d8f0818..8174ca6ad 100644 --- a/ast/utils.c2 +++ b/ast/utils.c2 @@ -25,9 +25,72 @@ import stdio; import stdlib; import string; -#if Arch32 -#else +#if ARCH_32BIT +static_assert(20, sizeof(Decl)); +static_assert(32, sizeof(AliasTypeDecl)); +static_assert(40, sizeof(EnumTypeDecl)); +static_assert(24, sizeof(FunctionTypeDecl)); +static_assert(32, sizeof(VarDecl)); +static_assert(40, sizeof(EnumConstantDecl)); +static_assert(32, sizeof(ImportDecl)); +static_assert(36, sizeof(StructTypeDecl)); +static_assert(64, sizeof(FunctionDecl)); +static_assert(8, sizeof(Stmt)); +static_assert(12, sizeof(GotoStmt)); +static_assert(16, sizeof(LabelStmt)); +static_assert(16, sizeof(AssertStmt)); +static_assert(8, sizeof(DeclStmt)); +static_assert(12, sizeof(SwitchStmt)); +static_assert(20, sizeof(AsmStmt)); +static_assert(16, sizeof(IfStmt)); +static_assert(16, sizeof(WhileStmt)); +static_assert(24, sizeof(ForStmt)); +static_assert(8, sizeof(BreakStmt)); +static_assert(8, sizeof(CompoundStmt)); +static_assert(8, sizeof(ContinueStmt)); +static_assert(8, sizeof(FallthroughStmt)); +static_assert(8, sizeof(ReturnStmt)); + +static_assert(12, sizeof(Expr)); +static_assert(12, sizeof(BooleanLiteral)); +static_assert(12, sizeof(CharLiteral)); +static_assert(20, sizeof(MemberExpr)); +static_assert(12, sizeof(NilExpr)); +static_assert(16, sizeof(IdentifierExpr)); +static_assert(16, sizeof(ImplicitCastExpr)); +static_assert(20, sizeof(InitListExpr)); +static_assert(24, sizeof(IntegerLiteral)); +static_assert(16, sizeof(ParenExpr)); +static_assert(20, sizeof(StringLiteral)); +static_assert(24, sizeof(TypeExpr)); +static_assert(16, sizeof(UnaryOperator)); +static_assert(24, sizeof(ArrayDesignatedInitExpr)); +static_assert(20, sizeof(ArraySubscriptExpr)); +static_assert(20, sizeof(BinaryOperator)); +static_assert(20, sizeof(BitOffsetExpr)); +static_assert(24, sizeof(CallExpr)); +static_assert(32, sizeof(ExplicitCastExpr)); +static_assert(24, sizeof(BuiltinExpr)); +static_assert(24, sizeof(FieldDesignatedInitExpr)); +static_assert(28, sizeof(ConditionalOperator)); +static_assert(24, sizeof(NamedArgument)); +static_assert(20, sizeof(AlternateExpr)); + +static_assert(4, sizeof(QualType)); +static_assert(12, sizeof(Type)); +static_assert(12, sizeof(BuiltinType)); +static_assert(16, sizeof(EnumType)); +static_assert(16, sizeof(FunctionType)); +static_assert(16, sizeof(PointerType)); +static_assert(16, sizeof(StructType)); +static_assert(20, sizeof(ArrayType)); + +static_assert(12, sizeof(ArrayValue)); +static_assert(8, sizeof(SwitchCase)); +static_assert(16, sizeof(StaticAssert)); +static_assert(8, sizeof(TypeRef)); +#else static_assert(24, sizeof(Decl)); static_assert(32, sizeof(AliasTypeDecl)); static_assert(64, sizeof(EnumTypeDecl)); @@ -92,7 +155,6 @@ static_assert(16, sizeof(ArrayValue)); static_assert(8, sizeof(SwitchCase)); static_assert(24, sizeof(StaticAssert)); static_assert(8, sizeof(TypeRef)); - #endif public const QualType QualType_Invalid = { } diff --git a/ast/var_decl.c2 b/ast/var_decl.c2 index cbf6ec2c2..c07d14307 100644 --- a/ast/var_decl.c2 +++ b/ast/var_decl.c2 @@ -65,14 +65,22 @@ type BitFieldInfo struct { BitFieldLayout layout; // u16 pad } +#if ARCH_32BIT +static_assert(12, sizeof(BitFieldInfo)); +#else static_assert(16, sizeof(BitFieldInfo)); +#endif type VarDeclInit struct { Expr* expr; SrcLoc loc; // u32 pad } +#if ARCH_32BIT +static_assert(8, sizeof(VarDeclInit)); +#else static_assert(16, sizeof(VarDeclInit)); +#endif public type VarDecl struct @(opaque) { Decl base; diff --git a/ast_utils/attr.c2 b/ast_utils/attr.c2 index 8b8ca3115..ff2da56a4 100644 --- a/ast_utils/attr.c2 +++ b/ast_utils/attr.c2 @@ -69,7 +69,11 @@ public type Attr struct { AttrValueKind value_kind; AttrValue value; } +#if ARCH_32BIT +static_assert(24, sizeof(Attr)); +#else static_assert(32, sizeof(Attr)); +#endif // Note: only meant for printing (since not allocated in StringPool) public fn const char* Attr.kind2name(const Attr* a) { diff --git a/ast_utils/string_buffer.c2 b/ast_utils/string_buffer.c2 index 387aaf60d..84f78a5c7 100644 --- a/ast_utils/string_buffer.c2 +++ b/ast_utils/string_buffer.c2 @@ -33,7 +33,11 @@ public type Buf struct { u32 indent_step; } +#if ARCH_32BIT +static_assert(20, sizeof(Buf)); +#else static_assert(24, sizeof(Buf)); +#endif public fn Buf* Buf.init(Buf* buf, char* data, u32 capacity, bool grow, bool use_colors, u32 indent_step) { assert(capacity); diff --git a/ast_utils/string_pool.c2 b/ast_utils/string_pool.c2 index 57784df4c..53f3f5d5c 100644 --- a/ast_utils/string_pool.c2 +++ b/ast_utils/string_pool.c2 @@ -62,7 +62,11 @@ public type Pool struct @(opaque) { u32 entry_capacity; HashEntry* entries; // contain hash table followed by collision lists } +#if ARCH_32BIT +static_assert(56, sizeof(Pool)); +#else static_assert(64, sizeof(Pool)); +#endif public fn Pool* create(u32 data_capacity, u32 hash_size) { Pool* p = stdlib.calloc(1, sizeof(Pool)); diff --git a/bootstrap/globals.c b/bootstrap/globals.c index 05ae32c57..9f23a8863 100644 --- a/bootstrap/globals.c +++ b/bootstrap/globals.c @@ -20,6 +20,9 @@ typedef unsigned int u32; int verbose; +int m32; +int ptr_width = sizeof(void*) * 8; +char cmdline[128]; int pf(const char *fmt, ...) { int res; @@ -73,9 +76,16 @@ size_t pstrcpy(char *dest, size_t size, const char *src) { void preprocess_header(const char *header_name) { char cmd[200]; size_t pos; - printf("// preprocessor output of <%s>\n{\n", header_name); - fflush(stdout); - pos = snprintf(cmd, sizeof(cmd), "echo '#include <%s>' | cc -E -", header_name); + if (m32) { + printf("// preprocessor output of <%s> (%d-bits, -m32, #undef __LP64__)\n{\n", header_name, ptr_width); + fflush(stdout); + pos = snprintf(cmd, sizeof(cmd), "echo '#undef __LP64__\n#include <%s>' | cc -m32 -E -", + header_name); + } else { + printf("// preprocessor output of <%s> (%d-bits)\n{\n", header_name, ptr_width); + fflush(stdout); + pos = snprintf(cmd, sizeof(cmd), "echo '#include <%s>' | cc -E -", header_name); + } if (pos > sizeof(cmd)) { pos = sizeof(cmd); } @@ -99,11 +109,20 @@ int main(int argc, char *argv[]) { jmp_buf buf; setjmp(buf); + m32 = (ptr_width == 32); + + strcpy(cmdline, argv[0]); for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-v")) { + strcat(cmdline, " -v"); verbose = 1; continue; } + if (!strcmp(argv[i], "-m32")) { + strcat(cmdline, " -m32"); + m32 = 1; + continue; + } fprintf(stderr, "globals: invalid argument '%s'\n", argv[i]); return 1; } @@ -113,7 +132,7 @@ int main(int argc, char *argv[]) { nothing(stderr_); printf("// ----------------------------------------------------------------\n"); - printf("// Output of global header processor\n{\n"); + printf("// Output of %s (%d-bits)\n{\n", cmdline, ptr_width); //printf("// preprocessor output of cc -E - < globals.c\n{\n"); //fflush(stdout); //system("cc -E - < globals.c"); @@ -122,8 +141,18 @@ int main(int argc, char *argv[]) { #define xstr(x) #x #define str(x) xstr(x) - preprocess_header("sys/types.h"); - + printf("// libc/sys_types.c2i\n{\n"); { + preprocess_header("sys/types.h"); + } + printf("}\n"); + printf("// libc/sys_time.c2i\n{\n"); { + preprocess_header("sys/time.h"); + } + printf("}\n"); + printf("// libc/sys_stat.c2i\n{\n"); { + preprocess_header("sys/stat.h"); + } + printf("}\n"); printf("// libc/c2_assert.c2i\n{\n"); { preprocess_header("assert.h"); } @@ -1138,14 +1167,6 @@ int main(int argc, char *argv[]) { preprocess_header("sys/socket.h"); } printf("}\n"); - printf("// libc/sys_stat.c2i\n{\n"); { - preprocess_header("sys/stat.h"); - } - printf("}\n"); - printf("// libc/sys_time.c2i\n{\n"); { - preprocess_header("sys/time.h"); - } - printf("}\n"); printf("// libc/sys_utsname.c2i\n{\n"); { preprocess_header("sys/utsname.h"); } diff --git a/common/process_utils.c2 b/common/process_utils.c2 index d62b8f001..6ccdb027d 100644 --- a/common/process_utils.c2 +++ b/common/process_utils.c2 @@ -25,6 +25,7 @@ import stdio local; import stdlib local; import string local; import sys_stat local; +import sys_types local; // pid_t import unistd local; const u32 MAX_ARG_LEN = 512; diff --git a/common/target_info.c2 b/common/target_info.c2 index 9240ba307..afea125bc 100644 --- a/common/target_info.c2 +++ b/common/target_info.c2 @@ -18,15 +18,16 @@ module target_info; import stdio local; import string local; -public type Arch enum u8 (const char* const name) { - Unknown : { "unknown" }, - I686 : { "i686" }, - Arm : { "arm" }, - X86_64 : { "x86_64" }, - Amd64 : { "amd64" }, - Arm64 : { "arm64" }, - Riscv_32 : { "riscv32" }, - Riscv_64 : { "riscv64" }, +public type Arch enum u8 (const char* const name, Arch m32_version) { + Unknown : { "unknown", Unknown }, + I386 : { "i386", I386 }, + I686 : { "i686", I686 }, + Arm : { "arm", Arm }, + X86_64 : { "x86_64", I686 }, + Amd64 : { "amd64", I686 }, + Arm64 : { "arm64", Arm }, + Riscv_32 : { "riscv32", Riscv_32 }, + Riscv_64 : { "riscv64", Riscv_32 }, } public type System enum u8 (const char* const name) { @@ -60,9 +61,9 @@ public fn System str2sys(const char* name) { return Unknown; } -public fn Arch str2arch(const char* name) { - for (Arch i = Arch.min; i <= Arch.max; i++) { - if (strcasecmp(i.name, name) == 0) return i; +public fn Arch str2arch(const char* name, bool m32 = false) { + for (Arch a = Arch.min; a <= Arch.max; a++) { + if (strcasecmp(a.name, name) == 0) return m32 ? a.m32_version : a; } return Unknown; } @@ -99,6 +100,7 @@ public fn void Info.init(Info* info) { info.ptrWidth = 64; info.longWidth = 64; break; + case I386: case I686: case Arm: info.ptrWidth = 32; diff --git a/examples/common/logger.c2 b/examples/common/logger.c2 index 2a5d994ae..3cee45bea 100644 --- a/examples/common/logger.c2 +++ b/examples/common/logger.c2 @@ -21,7 +21,7 @@ import string local; import stdio local; import stdlib local; import sys_time local; -import libc_time; +import libc_time local; import utils local; @@ -152,7 +152,7 @@ fn void Log.internal(Log* log, Level level, const char* color_, const char* form Timeval tv; gettimeofday(&tv, nil); Time now = tv.tv_sec; - libc_time.Tm* now2 = libc_time.localtime(&now); + Tm* now2 = localtime(&now); buf.printf("%02d/%02d/%02d %02d:%02d:%02d.%d", now2.tm_year % 100, now2.tm_mon + 1, now2.tm_mday, now2.tm_hour, now2.tm_min, now2.tm_sec, tv.tv_usec / 1000); diff --git a/generator/ir/field_struct_layouter.c2 b/generator/ir/field_struct_layouter.c2 index 1cb727b55..b8eeea021 100644 --- a/generator/ir/field_struct_layouter.c2 +++ b/generator/ir/field_struct_layouter.c2 @@ -27,7 +27,11 @@ type FieldInit struct { const ast.FieldInitField* info; ast.Expr* expr; } +#if ARCH_32BIT +static_assert(8, sizeof(FieldInit)); +#else static_assert(16, sizeof(FieldInit)); +#endif type FieldStructLayouter struct { Generator* gen; diff --git a/ir/context_target.c2 b/ir/context_target.c2 index adc0e7361..ecc908e4e 100644 --- a/ir/context_target.c2 +++ b/ir/context_target.c2 @@ -24,6 +24,7 @@ import target_info; fn const ir_tools.Target* getArchTarget(const target_info.Info* info) { switch (info.arch) { case Unknown: + case I386: case I686: break; case Arm: diff --git a/ir/function_info.c2 b/ir/function_info.c2 index 94c71b2cd..80d66d9f0 100644 --- a/ir/function_info.c2 +++ b/ir/function_info.c2 @@ -29,7 +29,11 @@ public type FunctionInfo struct { u8[1 + constants.MaxCallArgs/2] args; // stores 2 ir.Types per u8, first low, then high bits u32 id; } +#if ARCH_32BIT +static_assert(68, sizeof(FunctionInfo)); +#else static_assert(88, sizeof(FunctionInfo)); +#endif public fn FunctionInfo* FunctionInfo.create(u32 id, u32 num_blks, u32 num_instr, u32 num_refs) { FunctionInfo* fi = stdlib.malloc(sizeof(FunctionInfo)); diff --git a/ir/inserter.c2 b/ir/inserter.c2 index 817e6369b..b93cb29b5 100644 --- a/ir/inserter.c2 +++ b/ir/inserter.c2 @@ -51,7 +51,11 @@ public type Inserter struct { u32 split_count; u32 split_cap; } +#if ARCH_32BIT +static_assert(56, sizeof(Inserter)); +#else static_assert(72, sizeof(Inserter)); +#endif public fn void Inserter.create(Inserter* ins) { string.memset(ins, 0, sizeof(Inserter)); diff --git a/ir/interference_graph.c2 b/ir/interference_graph.c2 index e239115e1..6088677f3 100644 --- a/ir/interference_graph.c2 +++ b/ir/interference_graph.c2 @@ -63,7 +63,11 @@ public type InterferenceGraph struct @(opaque) { u32 queue_count; u32 queue_head; } +#if ARCH_32BIT +static_assert(208, sizeof(InterferenceGraph)); +#else static_assert(224, sizeof(InterferenceGraph)); +#endif // Note: map size must be a multiple of largest arena size (so 256) public fn InterferenceGraph* create(u32 max_elems, u16 num_variables, u16 num_regs) { diff --git a/ir/live_map.c2 b/ir/live_map.c2 index 2982becda..846ba6245 100644 --- a/ir/live_map.c2 +++ b/ir/live_map.c2 @@ -53,7 +53,11 @@ public type Map struct @(opaque) { u32 max_elems; // only used for dump Arena[NumArenas] arenas; } +#if ARCH_32BIT +static_assert(160, sizeof(Map)); +#else static_assert(168, sizeof(Map)); +#endif // Note: map size must be a multiple of largest arena size (so 256) public fn Map* create(u32 max_elems, u16 num_variables) { diff --git a/ir/slot_writes_map.c2 b/ir/slot_writes_map.c2 index a0296e9a7..ac86168f9 100644 --- a/ir/slot_writes_map.c2 +++ b/ir/slot_writes_map.c2 @@ -61,7 +61,11 @@ public type Map struct @(opaque) { u32 max_elems; // only used for dump Arena[NumArenas] arenas; } +#if ARCH_32BIT +static_assert(160, sizeof(Map)); +#else static_assert(168, sizeof(Map)); +#endif // Note: map size must be a multiple of largest arena size (so 256) public fn Map* create(u32 max_elems, u16 num_blocks) { diff --git a/ir/tools.c2 b/ir/tools.c2 index 592ff514e..dca14bb9e 100644 --- a/ir/tools.c2 +++ b/ir/tools.c2 @@ -52,7 +52,11 @@ public type Tools struct { const void* arg2; // Symbol* FunctionInfo* fi; // no ownership } +#if ARCH_32BIT +static_assert(728, sizeof(Tools)); +#else static_assert(816, sizeof(Tools)); +#endif public fn void Tools.init(Tools* t, const Target* target, const void* arg1, PrintFn print) { t.conversion.init(64); @@ -229,7 +233,7 @@ public fn void Tools.reorder_blocks(Tools* t, FunctionInfo* fi, const index_list Instr* switch_instr = fi.instructions.get(instr_idx); assert(switch_instr.isSwitch()); Ref* join_ref = &switch_instr.args[1]; - join_ref.value = (i32) t.conversion.get((u32)join_ref.value); + join_ref.value = (i32)t.conversion.get((u32)join_ref.value); } else { b.dests[0] = t.conversion.get(b.dests[0]); b.dests[1] = t.conversion.get(b.dests[1]); diff --git a/libs/io_uring/io_uring.c2i b/libs/io_uring/io_uring.c2i index e6513de0b..93d03989b 100644 --- a/libs/io_uring/io_uring.c2i +++ b/libs/io_uring/io_uring.c2i @@ -29,7 +29,11 @@ type Sq struct @(cname="io_uring_sq") { u32[4] pad; } +#if ARCH_32BIT +static_assert(64, sizeof(Sq)); +#else static_assert(104, sizeof(Sq)); +#endif type Cq struct @(cname="io_uring_cq") { @@ -46,7 +50,11 @@ type Cq struct @(cname="io_uring_cq") { u32[4] pad; } +#if ARCH_32BIT +static_assert(52, sizeof(Cq)); +#else static_assert(88, sizeof(Cq)); +#endif type Ring struct @(cname="io_uring") { @@ -58,7 +66,11 @@ type Ring struct @(cname="io_uring") { u32 features; u32[3] pad; } +#if ARCH_32BIT +static_assert(140, sizeof(Ring)); +#else static_assert(216, sizeof(Ring)); +#endif /* @@ -230,7 +242,7 @@ void prep_rw(int op, Sqe* sqe, int fd, const void* addr, u32 len, u64 offset) // sqe.ioprio = 0; sqe.fd = fd; sqe.off = offset; - sqe.addr = (u64)addr; + sqe.addr = (usize)addr; sqe.len = len; sqe.rw_flags = 0; sqe.user_data = 0; @@ -389,7 +401,7 @@ void Sqe.prep_timeout_remove(Sqe* sqe, u64 user_data, u32 flags) //@(cname="io_u void Sqe.prep_timeout_update(Sqe* sqe, linux_types.Timespec* ts, u64 user_data, u32 flags) //@(cname="io_uring_prep_timeout_update") { - prep_rw(Op.TIMEOUT_REMOVE, sqe, -1, (void*)user_data, 0, (size_t)ts); + prep_rw(Op.TIMEOUT_REMOVE, sqe, -1, (void*)(usize)user_data, 0, (size_t)ts); sqe.timeout_flags = flags | TIMEOUT_UPDATE; } @@ -398,7 +410,7 @@ void Sqe.prep_accept(Sqe* sqe, int fd, u32* addrlen, int flags) //@(cname="io_uring_prep_accept") { - prep_rw(Op.ACCEPT, sqe, fd, addr, 0, (u64)addrlen); + prep_rw(Op.ACCEPT, sqe, fd, addr, 0, (usize)addrlen); sqe.accept_flags = (u32)flags; } diff --git a/libs/libc/csignal.c2i b/libs/libc/csignal.c2i index 4b4a97b24..4d10788d2 100644 --- a/libs/libc/csignal.c2i +++ b/libs/libc/csignal.c2i @@ -72,7 +72,11 @@ struct Sigaction { int sa_flags; SigActionRestorer sa_restorer; } +#if ARCH_32BIT +static_assert(144, sizeof(Sigaction)); +#else static_assert(152, sizeof(Sigaction)); +#endif // from x86_64-linux-gnu/bits/types/sigset_t.h diff --git a/libs/libc/ctermios.c2i b/libs/libc/ctermios.c2i index 3e2e48057..b671863e0 100644 --- a/libs/libc/ctermios.c2i +++ b/libs/libc/ctermios.c2i @@ -1,10 +1,11 @@ module ctermios extern "C"; +import sys_types local; + #if SYSTEM_LINUX typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned int tcflag_t; -typedef int pid_t; const u32 NCCS = 32; @@ -163,7 +164,6 @@ const unsigned EXTPROC = 0200000; typedef unsigned long tcflag_t; typedef unsigned char cc_t; typedef unsigned long speed_t; -typedef int pid_t; const u32 NCCS = 20; diff --git a/libs/libc/libc_time.c2i b/libs/libc/libc_time.c2i index ccb861c89..48a0a0455 100644 --- a/libs/libc/libc_time.c2i +++ b/libs/libc/libc_time.c2i @@ -1,5 +1,7 @@ module libc_time extern "C"; +import sys_types local; // clock_t, time_t + struct Tm { int tm_sec; /* Seconds (0-60) */ int tm_min; /* Minutes (0-59) */ @@ -35,7 +37,6 @@ Time mktime(Tm* tm); size_t strftime(char* s, size_t max, const char* format, const Tm* tm); -typedef long clock_t; clock_t clock(void); #if SYSTEM_FREEBSD @@ -45,3 +46,44 @@ const i64 CLOCKS_PER_SEC = 100; #else const i64 CLOCKS_PER_SEC = 1000000; #endif + +struct Timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +} + +//int clock_getcpuclockid(pid_t pid, clockid_t *clock_id); +/* + CLOCK_REALTIME + CLOCK_REALTIME_PRECISE + CLOCK_REALTIME_FAST + CLOCK_REALTIME_COARSE + Increments as a wall clock should. + CLOCK_MONOTONIC + CLOCK_MONOTONIC_PRECISE + CLOCK_MONOTONIC_FAST + CLOCK_MONOTONIC_COARSE + Increments in SI seconds. + CLOCK_UPTIME + CLOCK_UPTIME_PRECISE + CLOCK_UPTIME_FAST + CLOCK_BOOTTIME + Starts at zero when the kernel boots and increments monotonically + in SI seconds while the machine is running. + CLOCK_VIRTUAL + Increments only when the CPU is running in user mode on behalf of + the calling process. + CLOCK_PROF + Increments when the CPU is running in user or kernel mode. + CLOCK_SECOND + Returns the current second without performing a full time counter + query, using an in-kernel cached value of the current second. + CLOCK_PROCESS_CPUTIME_ID + Returns the execution time of the calling process. + CLOCK_THREAD_CPUTIME_ID + Returns the execution time of the calling thread. + */ + +int clock_gettime(clockid_t clock_id, Timespec *tp); +int clock_settime(clockid_t clock_id, const Timespec *tp); +int clock_getres(clockid_t clock_id, Timespec *tp); diff --git a/libs/libc/manifest.yaml b/libs/libc/manifest.yaml index 2941a3c98..14d0387bb 100644 --- a/libs/libc/manifest.yaml +++ b/libs/libc/manifest.yaml @@ -38,6 +38,7 @@ modules: - sys_socket - sys_stat - sys_time + - sys_types - sys_utsname - uio - unistd diff --git a/libs/libc/stdio.c2i b/libs/libc/stdio.c2i index 0e00739e3..d82be1dca 100644 --- a/libs/libc/stdio.c2i +++ b/libs/libc/stdio.c2i @@ -1,6 +1,7 @@ module stdio extern "C"; import stdarg local; +import sys_types local; // off_t // possibilities for the third argument to 'setvbuf' const u8 _IOFBF = 0; // fully buffered @@ -26,13 +27,6 @@ struct IO_marker @(cname="_IO_marker") { } */ -typedef i64 Offset @(cname="off_t"); -typedef i64 off_t; - -//NOTE: _G_fpos_t is some struct(_G_fpos_t.h) -//typedef _G_fpos_t fpos_t; -typedef off_t fpos_t; - #if SYSTEM_LINUX struct FILE @(opaque) {} diff --git a/libs/libc/sys_mman.c2i b/libs/libc/sys_mman.c2i index cf79815d5..40506a153 100644 --- a/libs/libc/sys_mman.c2i +++ b/libs/libc/sys_mman.c2i @@ -1,8 +1,8 @@ module sys_mman extern "C"; -typedef i64 Offset @(cname="off_t"); +import sys_types local; // off_t -void* mmap(void* addr, size_t length, int prot, int flags, int fd, Offset offset); +void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void* addr, size_t length); const u32 PROT_NONE = 0x0; diff --git a/libs/libc/sys_sendfile.c2i b/libs/libc/sys_sendfile.c2i index 14bbf2d9c..031be7ba3 100644 --- a/libs/libc/sys_sendfile.c2i +++ b/libs/libc/sys_sendfile.c2i @@ -1,6 +1,6 @@ module sys_sendfile extern "C"; -typedef i64 Offset @(cname="off_t"); +import sys_types local; // off_t -ssize_t sendfile(int __out_fd, int __in_fd, Offset* __offset, size_t __count); +ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count); diff --git a/libs/libc/sys_stat.c2i b/libs/libc/sys_stat.c2i index f1746ba9c..1a9c897fd 100644 --- a/libs/libc/sys_stat.c2i +++ b/libs/libc/sys_stat.c2i @@ -1,5 +1,7 @@ module sys_stat extern "C"; +import sys_types local; + #if SYSTEM_LINUX // Version for Ubuntu 18.04 struct Stat @(cname="stat", no_typedef) { @@ -25,13 +27,18 @@ struct Stat @(cname="stat", no_typedef) { long st_ctime_nsec; long[3] reserved; } +#if ARCH_32BIT +static_assert(76, sizeof(Stat)); +#else static_assert(144, sizeof(Stat)); +#endif int fstat(int fd, Stat* buf); int lstat(const char* pathname, Stat* buf); int stat(const char* pathname, Stat* buf); #endif #if SYSTEM_DARWIN + struct Timespec @(cname="timespec", no_typedef) { long tv_sec; long tv_nsec; @@ -56,7 +63,11 @@ struct Stat @(cname="stat", no_typedef) { int st_lspare; long[2] st_qspare; } +#if ARCH_32BIT +static_assert(88, sizeof(Stat)); +#else static_assert(144, sizeof(Stat)); +#endif #if ARCH_X86_64 int fstat(int fd, Stat* buf) @(cname="fstat64"); int lstat(const char* pathname, Stat* buf) @(cname="lstat64"); @@ -70,37 +81,62 @@ int stat(const char* pathname, Stat* buf) @(cname="stat"); #if SYSTEM_FREEBSD struct Timespec @(cname="timespec", no_typedef) { - long tv_sec; + time_t tv_sec; long tv_nsec; } struct Stat @(cname="stat", no_typedef) { - u64 st_dev; - u64 st_ino; - u64 st_nlink; - unsigned short st_mode; + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + mode_t st_mode; unsigned short st_padding0; - unsigned int st_uid; - unsigned int st_gid; + uid_t st_uid; + gid_t st_gid; i32 st_padding1; - u64 st_rdev; + dev_t st_rdev; + // XXX: should use a union to map older field names + //#define st_atime st_atim.tv_sec + //#define st_mtime st_mtim.tv_sec + //#define st_ctime st_ctim.tv_sec + //#define st_birthtime st_birthtim.tv_sec + //#define st_atimensec st_atim.tv_nsec + //#define st_mtimensec st_mtim.tv_nsec + //#define st_ctimensec st_ctim.tv_nsec + //#define st_birthtimensec st_birthtim.tv_nsec +#if ARCH_32BIT + i32 st_atim_ext; Timespec st_atimespec; // st_atim + i32 st_mtim_ext; Timespec st_mtimespec; // st_mtim + i32 st_ctim_ext; Timespec st_ctimespec; // st_ctim + i32 st_btim_ext; Timespec st_birthtimespec; // st_birthtim - unsigned long st_size; - unsigned long st_blocks; - unsigned int st_blksize; // actually int - unsigned int st_flags; +#else + Timespec st_atimespec; // st_atim + Timespec st_mtimespec; // st_mtim + Timespec st_ctimespec; // st_ctim + Timespec st_birthtimespec; // st_birthtim +#endif + off_t st_size; + blkcnt_t st_blocks; + blksize_t st_blksize; // actually int + fflags_t st_flags; u64 st_gen; u64[10] st_lspare; } +#if ARCH_32BIT +static_assert(208, sizeof(Stat)); +#else static_assert(224, sizeof(Stat)); +#endif int fstat(int fd, Stat* buf); int lstat(const char* pathname, Stat* buf); int stat(const char* pathname, Stat* buf); #endif #if SYSTEM_OPENBSD + struct Timespec @(cname="timespec", no_typedef) { long tv_sec; long tv_nsec; @@ -142,8 +178,6 @@ const u32 S_ISUID = 0004000; const u32 S_ISGID = 0002000; const u32 S_ISVTX = 0001000; -typedef unsigned int mode_t; - int chmod(const char* file, mode_t mode); int lchmod(const char* file, mode_t mode); int fchmod(int fd, mode_t mode); diff --git a/libs/libc/sys_time.c2i b/libs/libc/sys_time.c2i index 237619bfd..34ad8a3bc 100644 --- a/libs/libc/sys_time.c2i +++ b/libs/libc/sys_time.c2i @@ -1,19 +1,12 @@ module sys_time extern "C"; -#if SYSTEM_DARWIN -typedef long Time @(cname="time_t"); -typedef int SuSeconds @(cname="suseconds_t"); -#else -// Same for Linux, FreeBSD and OpenBSD -typedef long Time @(cname="time_t"); -typedef long SuSeconds @(cname="suseconds_t"); -#endif +import sys_types local; // time_t, suseconds_t struct Timeval @(cname="timeval") { - Time tv_sec; - SuSeconds tv_usec; + time_t tv_sec; + suseconds_t tv_usec; } -static_assert(16, sizeof(Timeval)); +static_assert(2 * sizeof(time_t), sizeof(Timeval)); struct Timezone @(cname="timezone") { int tz_minuteswest; diff --git a/libs/libc/sys_types.c2i b/libs/libc/sys_types.c2i new file mode 100644 index 000000000..7dce3fab1 --- /dev/null +++ b/libs/libc/sys_types.c2i @@ -0,0 +1,60 @@ +module sys_types extern "C"; + +typedef int pid_t; +typedef int Pid @(cname="pid_t"); +typedef i64 off64_t; +typedef i64 off_t; +typedef i64 Offset @(cname="off_t"); +typedef off_t fpos_t; +//NOTE: _G_fpos_t is some struct(_G_fpos_t.h) +//typedef _G_fpos_t fpos_t; +typedef int clockid_t; +typedef int wchar_t; + +#if SYSTEM_LINUX +typedef long clock_t; +typedef long time_t; +typedef long suseconds_t; +typedef unsigned useconds_t; +typedef unsigned int mode_t; +typedef unsigned gid_t; +typedef unsigned uid_t; +#endif +#if SYSTEM_DARWIN +typedef long clock_t; +typedef long time_t; +typedef int suseconds_t; +typedef unsigned useconds_t; +typedef unsigned int mode_t; +typedef unsigned gid_t; +typedef unsigned uid_t; +#endif +#if SYSTEM_FREEBSD +#if ARCH_32BIT +typedef unsigned long clock_t; +typedef i32 time_t; +#else +typedef i32 clock_t; +typedef i64 time_t; +#endif +typedef long suseconds_t; +typedef unsigned int useconds_t; +typedef u32 uid_t; +typedef i64 blkcnt_t; +typedef i32 blksize_t; +typedef u64 dev_t; +typedef u32 fflags_t; +typedef u32 gid_t; +typedef u64 ino_t; +typedef u16 mode_t; +typedef u64 nlink_t; +#endif +#if SYSTEM_OPENBSD +typedef long clock_t; +typedef long time_t; +typedef long suseconds_t; +typedef unsigned useconds_t; +typedef unsigned int mode_t; +typedef unsigned gid_t; +typedef unsigned uid_t; +#endif diff --git a/libs/libc/unistd.c2i b/libs/libc/unistd.c2i index 75ae05e52..39f3528bf 100644 --- a/libs/libc/unistd.c2i +++ b/libs/libc/unistd.c2i @@ -1,19 +1,13 @@ module unistd extern "C"; import libc_fcntl local; +import sys_types local; // /* Standard file descriptors. */ const int STDIN_FILENO = 0; const int STDOUT_FILENO = 1; const int STDERR_FILENO = 2; -// ifdef USE_XOPEN_EXTENDED .. -typedef unsigned gid_t; -typedef long long off_t; -typedef int pid_t; -typedef unsigned uid_t; -typedef unsigned useconds_t; - /* POSIX.1-1990 */ void _exit(int) @(noreturn); @@ -206,7 +200,6 @@ int pipe2(int* pipefd, int flags) { #endif -typedef int Pid @(cname="pid_t"); Pid wait(int* wstatus); Pid waitpid(Pid pid, int* wstatus, int options); int kill(Pid pid, int sig); diff --git a/libs/mbedtls/mbedtls.c2i b/libs/mbedtls/mbedtls.c2i index beb1a3a88..9403272d4 100644 --- a/libs/mbedtls/mbedtls.c2i +++ b/libs/mbedtls/mbedtls.c2i @@ -137,8 +137,11 @@ type Pk_context struct @(cname="mbedtls_pk_context") { const Pk_info_t* pk_info; /**< Public key information */ void * pk_ctx; /**< Underlying public key context */ } - +#if ARCH_32BIT +static_assert(8, sizeof(Pk_context)); +#else static_assert(16, sizeof(Pk_context)); +#endif void pk_init(Pk_context* ctx) @(cname="mbedtls_pk_init"); void pk_free(Pk_context *ctx) @(cname="mbedtls_pk_free"); @@ -171,16 +174,18 @@ const int ERR_X509_FATAL_ERROR = -0x3000; // ------ x509_crt.h ------ type X509_buf Asn1_buf @(cname="mbedtls_x509_buf"); - -static_assert(24, sizeof(X509_buf)); - type X509_name Asn1_named_data @(cname="mbedtls_x509_name"); - -static_assert(64, sizeof(X509_name)); - type X509_sequence Asn1_sequence @(cname="mbedtls_x509_sequence"); +#if ARCH_32BIT +static_assert(12, sizeof(X509_buf)); +static_assert(32, sizeof(X509_name)); +static_assert(16, sizeof(X509_sequence)); +#else +static_assert(24, sizeof(X509_buf)); +static_assert(64, sizeof(X509_name)); static_assert(32, sizeof(X509_sequence)); +#endif type X509_time struct @(cname="mbedtls_x509_time") { int year; @@ -280,7 +285,11 @@ type X509_crt struct @(cname="mbedtls_x509_crt") { X509_crt *next; /**< Next certificate in the CA-chain. */ } +#if ARCH_32BIT +static_assert(340, sizeof(X509_crt)); +#else static_assert(616, sizeof(X509_crt)); +#endif void x509_crt_init(X509_crt* crt) @(cname="mbedtls_x509_crt_init"); int x509_crt_parse_path(X509_crt *chain, const char* path) @(cname="mbedtls_x509_crt_parse_path"); @@ -702,7 +711,11 @@ type Ssl_config struct @(cname="mbedtls_ssl_config") { #endif } +#if ARCH_32BIT +static_assert(208, sizeof(Ssl_config)); +#else static_assert(384, sizeof(Ssl_config)); +#endif type Ssl_handshake_params struct @(opaque, cname="mbedtls_ssl_handshake_params"); @@ -936,8 +949,11 @@ type Ssl_context struct @(cname="mbedtls_ssl_context") { //#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ } +#if ARCH_32BIT +static_assert(288, sizeof(Ssl_context)); +#else static_assert(472, sizeof(Ssl_context)); - +#endif // ------ aes.h ------ @@ -995,7 +1011,11 @@ type Ctr_drbg_context struct @(cname="mbedtls_ctr_drbg_context") { //#endif } +#if ARCH_32BIT +static_assert(320, sizeof(Ctr_drbg_context)); +#else static_assert(344, sizeof(Ctr_drbg_context)); +#endif type Entropy_seed_f fn int(void *, unsigned char *, size_t); @@ -1057,7 +1077,11 @@ type Entropy_context struct @(cname="mbedtls_entropy_context") { //#endif } +#if ARCH_32BIT +static_assert(632, sizeof(Entropy_context)); +#else static_assert(1032, sizeof(Entropy_context)); +#endif void entropy_init(Entropy_context *ctx) @(cname="mbedtls_entropy_init"); int entropy_func(void* data, unsigned char* output, size_t len) @(cname="mbedtls_entropy_func"); diff --git a/parser/c2_tokenizer.c2 b/parser/c2_tokenizer.c2 index c3deb57da..5c788570c 100644 --- a/parser/c2_tokenizer.c2 +++ b/parser/c2_tokenizer.c2 @@ -278,7 +278,11 @@ public type Tokenizer struct { char[256] error_msg; } +#if ARCH_32BIT +static_assert(360, sizeof(Tokenizer)); +#else static_assert(408, sizeof(Tokenizer)); +#endif public fn void Tokenizer.init(Tokenizer* t, string_pool.Pool* pool, diff --git a/test/arch/x86_64/isize_max.c2 b/test/arch/x86_64/isize_max.c2 index dc8a35296..585ccd18d 100644 --- a/test/arch/x86_64/isize_max.c2 +++ b/test/arch/x86_64/isize_max.c2 @@ -1,5 +1,8 @@ // @warnings{no-unused} module test; -isize q = isize.max + 1; // @error{constant value 9223372036854775808 out-of-bounds for type 'isize', range [-9223372036854775808, 9223372036854775807]} - +#if ARCH_32BIT +isize q = isize.max + 1; // @error32{constant value 2147483648 out-of-bounds for type 'isize', range [-2147483648, 2147483647]} +#else +isize q = isize.max + 1; // @error64{constant value 9223372036854775808 out-of-bounds for type 'isize', range [-9223372036854775808, 9223372036854775807]} +#endif diff --git a/test/arch/x86_64/isize_min.c2 b/test/arch/x86_64/isize_min.c2 index 664d4dd2c..06bdcebae 100644 --- a/test/arch/x86_64/isize_min.c2 +++ b/test/arch/x86_64/isize_min.c2 @@ -1,5 +1,8 @@ // @warnings{no-unused} module test; -isize p = isize.min - 1; // @error{constant value -9223372036854775809 out-of-bounds for type 'isize', range [-9223372036854775808, 9223372036854775807]} - +#if ARCH_32BIT +isize p = isize.min - 1; // @error32{constant value -2147483649 out-of-bounds for type 'isize', range [-2147483648, 2147483647]} +#else +isize p = isize.min - 1; // @error64{constant value -9223372036854775809 out-of-bounds for type 'isize', range [-9223372036854775808, 9223372036854775807]} +#endif diff --git a/test/arch/x86_64/offsetof_struct.c2 b/test/arch/x86_64/offsetof_struct.c2 index b07432e50..51cfd638a 100644 --- a/test/arch/x86_64/offsetof_struct.c2 +++ b/test/arch/x86_64/offsetof_struct.c2 @@ -29,8 +29,13 @@ static_assert(0, offsetof(S2, f1)); static_assert(2, offsetof(S2, f2)); static_assert(4, offsetof(S2, f3)); static_assert(8, offsetof(S2, f4)); +#if ARCH_32BIT +static_assert(12, offsetof(S2, f5)); +static_assert(16, offsetof(S2, f6)); +#else static_assert(16, offsetof(S2, f5)); static_assert(20, offsetof(S2, f6)); +#endif type S2p struct @(packed) { u8 f1; @@ -45,8 +50,13 @@ static_assert(0, offsetof(S2p, f1)); static_assert(1, offsetof(S2p, f2)); static_assert(3, offsetof(S2p, f3)); static_assert(7, offsetof(S2p, f4)); -static_assert(15, offsetof(S2p, f5)); +#if ARCH_32BIT +static_assert(11, offsetof(S2p, f5)); +static_assert(14, offsetof(S2p, f6)); +#else static_assert(18, offsetof(S2p, f6)); +static_assert(15, offsetof(S2p, f5)); +#endif type S3 struct { u32[10] array1; @@ -106,7 +116,13 @@ type S7 struct { u16 m3; } } +#if ARCH_32BIT +static_assert(12, sizeof(S7)); +static_assert(4, offsetof(S7, m2)); +static_assert(8, offsetof(S7, m3)); +#else static_assert(24, sizeof(S7)); static_assert(8, offsetof(S7, m2)); static_assert(16, offsetof(S7, m3)); +#endif diff --git a/test/arch/x86_64/sizeof_basic_struct.c2 b/test/arch/x86_64/sizeof_basic_struct.c2 index dd0481233..9f0efbe34 100644 --- a/test/arch/x86_64/sizeof_basic_struct.c2 +++ b/test/arch/x86_64/sizeof_basic_struct.c2 @@ -114,5 +114,9 @@ type S12 struct { u32 c; void* b; } +#if ARCH_32BIT +static_assert(12, sizeof(S12)); +#else static_assert(24, sizeof(S12)); +#endif diff --git a/test/arch/x86_64/sizeof_builtin.c2 b/test/arch/x86_64/sizeof_builtin.c2 index c4b5cecd2..ccac86983 100644 --- a/test/arch/x86_64/sizeof_builtin.c2 +++ b/test/arch/x86_64/sizeof_builtin.c2 @@ -2,7 +2,11 @@ module test; +#if ARCH_32BIT +static_assert(4, sizeof(isize)); +static_assert(4, sizeof(usize)); +#else static_assert(8, sizeof(isize)); static_assert(8, sizeof(usize)); -static_assert(8, sizeof(void*)); +#endif diff --git a/test/arch/x86_64/usize_min.c2 b/test/arch/x86_64/usize_min.c2 index adf6b55ee..36e7ca222 100644 --- a/test/arch/x86_64/usize_min.c2 +++ b/test/arch/x86_64/usize_min.c2 @@ -1,5 +1,8 @@ // @warnings{no-unused} module test; -usize r = usize.min - 1; // @error{constant value -1 out-of-bounds for type 'usize', range [0, 18446744073709551615]} - +#if ARCH_32BIT +usize r = usize.min - 1; // @error32{constant value -1 out-of-bounds for type 'usize', range [0, 4294967295]} +#else +usize r = usize.min - 1; // @error64{constant value -1 out-of-bounds for type 'usize', range [0, 18446744073709551615]} +#endif diff --git a/test/c_generator/attributes/printf_format.c2t b/test/c_generator/attributes/printf_format.c2t index 04ceaa7b0..1131770a2 100644 --- a/test/c_generator/attributes/printf_format.c2t +++ b/test/c_generator/attributes/printf_format.c2t @@ -17,7 +17,7 @@ public fn i32 main() return 0; } -// @expect{atleast, cgen/build.c} +// @expect64{atleast, cgen/build.c} __attribute__((__format__(printf, 1, 2))) static void file1_log(const char* format, ...); @@ -38,3 +38,24 @@ int main(void) return 0; } +// @expect32{atleast, cgen/build.c} + +__attribute__((__format__(printf, 1, 2))) +static void file1_log(const char* format, ...); +int main(void); + +__attribute__((__format__(printf, 1, 2))) +static void file1_log(const char* format, ...) +{ +} + +int main(void) +{ + int i = -20; + u32 u = 10; + i64 li = -33333; + u64 lu = 444444; + file1_log("A %d B %u %+4d %06u C %lld D %llu E", i, u, i, u, li, lu); + return 0; +} + diff --git a/test/c_generator/builtin/offsetof_struct.c2t b/test/c_generator/builtin/offsetof_struct.c2t index 51a2f788e..a80f8135e 100644 --- a/test/c_generator/builtin/offsetof_struct.c2t +++ b/test/c_generator/builtin/offsetof_struct.c2t @@ -168,7 +168,7 @@ fn void test1() { } -// @expect{atleast, cgen/build.c} +// @expect64{atleast, cgen/build.c} static u32 test_s1_offs[5] = { 0, 4, 8, 12, 16 }; static u32 test_s2_offs[6] = { 0, 2, 4, 8, 16, 20 }; @@ -189,3 +189,24 @@ static void test_test1(void) u32 s6_offs_local[3] = { 6, 2, 4 }; } +// @expect32{atleast, cgen/build.c} + +static u32 test_s1_offs[5] = { 0, 4, 8, 12, 16 }; +static u32 test_s2_offs[6] = { 0, 2, 4, 8, 12, 16 }; +static u32 test_s2p_offs[6] = { 0, 1, 3, 7, 11, 14 }; +static u32 test_s3_offs[4] = { 0, 40, 44, 60 }; +static u32 test_s4_offs[5] = { 4, 4, 6, 8, 12 }; +static u32 test_s5_offs[3] = { 12, 4, 8 }; +static u32 test_s6_offs[3] = { 6, 2, 4 }; + +static void test_test1(void) +{ + u32 s1_offs_local[5] = { 0, 4, 8, 12, 16 }; + u32 s2_offs_local[6] = { 0, 2, 4, 8, 12, 16 }; + u32 s2p_offs_local[6] = { 0, 1, 3, 7, 11, 14 }; + u32 s3_offs_local[4] = { 0, 40, 44, 60 }; + u32 s4_offs_local[5] = { 4, 4, 6, 8, 12 }; + u32 s5_offs_local[3] = { 12, 4, 8 }; + u32 s6_offs_local[3] = { 6, 2, 4 }; +} + diff --git a/test/c_generator/expr/sizeof_expr.c2t b/test/c_generator/expr/sizeof_expr.c2t index 42ca797d8..ae8bceec5 100644 --- a/test/c_generator/expr/sizeof_expr.c2t +++ b/test/c_generator/expr/sizeof_expr.c2t @@ -40,7 +40,7 @@ public fn i32 main(i32 argc, const char** argv) { } -// @expect{atleast, cgen/build.c} +// @expect64{atleast, cgen/build.c} int main(int argc, const char** argv) { @@ -63,3 +63,26 @@ int main(int argc, const char** argv) return 0; } +// @expect32{atleast, cgen/build.c} + +int main(int argc, const char** argv) +{ + int a = 4; + int b = 4; + //int c = 4; + int d = 4; + int e = 4; + //int f = 12; + int g = 24; + int h = 4; + int i = 8; + int j = 24; + int k = 4; + int l = 8; + int o1 = 10; + int o2 = 20; + int o3 = 40; + + return 0; +} + diff --git a/test/expr/arithmetic/pointer_subtract.c2 b/test/expr/arithmetic/pointer_subtract.c2 index 7e4a175f4..dbd1296a6 100644 --- a/test/expr/arithmetic/pointer_subtract.c2 +++ b/test/expr/arithmetic/pointer_subtract.c2 @@ -1,3 +1,4 @@ +// @warnings{no-unused} module test; type Struct struct { @@ -6,6 +7,6 @@ type Struct struct { } fn u32 test1(Struct* s) { - return s.p2 - s.p1; // @error{implicit conversion loses integer precision: 'isize' to 'u32'} + return s.p2 - s.p1; // @error64{implicit conversion loses integer precision: 'isize' to 'u32'} } diff --git a/test/expr/explicit_cast/cast_func_to_various.c2 b/test/expr/explicit_cast/cast_func_to_various.c2 index f44b54876..fee6e5b7a 100644 --- a/test/expr/explicit_cast/cast_func_to_various.c2 +++ b/test/expr/explicit_cast/cast_func_to_various.c2 @@ -20,15 +20,17 @@ fn void test1(Func arg) { } fn void test2(Func arg) { - u8 b1 = (u8)(arg); // @error{pointers may only be cast to integer type 'u64'} + // @error32{pointers may only be cast to integer type 'u32'} +1 + u8 b1 = (u8)(arg); // @error64{pointers may only be cast to integer type 'u64'} } fn void test3(Func arg) { - u32 c1 = (u32)(arg); // @error{pointers may only be cast to integer type 'u64'} + u32 c1 = (u32)(arg); // @error64{pointers may only be cast to integer type 'u64'} } fn void test4(Func arg) { - f32 d1 = (f32)(arg); // @error{pointers may only be cast to integer type 'u64'} + // @error32{pointers may only be cast to integer type 'u32'} +1 + f32 d1 = (f32)(arg); // @error64{pointers may only be cast to integer type 'u64'} } fn void test5(Func arg) { @@ -36,12 +38,12 @@ fn void test5(Func arg) { } fn void test6(Func arg) { - u32 f1 = (u32)(arg); // @error{pointers may only be cast to integer type 'u64'} + u32 f1 = (u32)(arg); // @error64{pointers may only be cast to integer type 'u64'} } fn void test7(Func arg) { - u64 g1 = (u64)(arg); + u64 g1 = (u64)(arg); // @error32{pointers may only be cast to integer type 'u32'} FuncOther k1 = (FuncOther)(arg); FuncSame l1 = (FuncSame)(arg); - Enum j1 = (Enum)(arg); // @error{invalid cast from 'Func' to 'test.Enum'} + Enum j1 = (Enum)(arg); // @error{invalid cast from 'Func' to 'test.Enum'} } diff --git a/test/expr/explicit_cast/cast_nonword_to_ptr.c2 b/test/expr/explicit_cast/cast_nonword_to_ptr.c2 index e86406a5e..86b6679ee 100644 --- a/test/expr/explicit_cast/cast_nonword_to_ptr.c2 +++ b/test/expr/explicit_cast/cast_nonword_to_ptr.c2 @@ -13,23 +13,23 @@ type Enum enum u32 { fn void test1() { u16 a = 0; - s1 = (Struct*)a; // @error{only integers of type 'u64' may be cast to a pointer} + // @error32{only integers of type 'u32' may be cast to a pointer} +1 + s1 = (Struct*)a; // @error64{only integers of type 'u64' may be cast to a pointer} } fn void test2() { - // TODO this is allowed on 32-bit architectures u32 b = 0; - s1 = (Struct*)b; // @error{only integers of type 'u64' may be cast to a pointer} + s1 = (Struct*)b; // @error64{only integers of type 'u64' may be cast to a pointer} } fn void test3() { u64 c = 0; - s1 = (Struct*)c; + s1 = (Struct*)c; // @error32{only integers of type 'u32' may be cast to a pointer} } fn void test4() { Enum d = Enum.A; - s1 = (Struct*)d; // @error{invalid cast from 'test.Enum' to 'test.Struct*'} + s1 = (Struct*)d; // @error{invalid cast from 'test.Enum' to 'test.Struct*'} } fn void test5() { diff --git a/test/expr/explicit_cast/cast_ptr_to_nonword.c2 b/test/expr/explicit_cast/cast_ptr_to_nonword.c2 index 0641dc494..143987a68 100644 --- a/test/expr/explicit_cast/cast_ptr_to_nonword.c2 +++ b/test/expr/explicit_cast/cast_ptr_to_nonword.c2 @@ -10,19 +10,21 @@ type Enum enum u32 { } fn void test1(Struct* s) { - u64 a1 = (u64)(s); - u64 a2 = (u64)s; - u32 b1 = (u32)(s); // @error{pointers may only be cast to integer type 'u64'} - u32 b2 = (u32)s; // @error{pointers may only be cast to integer type 'u64'} + u64 a1 = (u64)(s); // @error32{pointers may only be cast to integer type 'u32'} + u64 a2 = (u64)s; // @error32{pointers may only be cast to integer type 'u32'} + u32 b1 = (u32)(s); // @error64{pointers may only be cast to integer type 'u64'} + u32 b2 = (u32)s; // @error64{pointers may only be cast to integer type 'u64'} } fn void test2(Struct* s) { - bool c1 = (bool)(s); // @error{pointers may only be cast to integer type 'u64'} - bool c2 = (bool)s; // @error{pointers may only be cast to integer type 'u64'} + // @error32{pointers may only be cast to integer type 'u32'} +1 + bool c1 = (bool)(s); // @error64{pointers may only be cast to integer type 'u64'} + // @error32{pointers may only be cast to integer type 'u32'} +1 + bool c2 = (bool)s; // @error64{pointers may only be cast to integer type 'u64'} } fn void test3(Struct* s) { - Enum d1 = (Enum)(s); // @error{invalid cast from 'test.Struct*' to 'test.Enum'} - Enum d2 = (Enum)s; // @error{invalid cast from 'test.Struct*' to 'test.Enum'} + Enum d1 = (Enum)(s); // @error{invalid cast from 'test.Struct*' to 'test.Enum'} + Enum d2 = (Enum)s; // @error{invalid cast from 'test.Struct*' to 'test.Enum'} } diff --git a/test/expr/explicit_cast/explicit_casts_builtin.c2 b/test/expr/explicit_cast/explicit_casts_builtin.c2 index 13fcf29bb..d11326a28 100644 --- a/test/expr/explicit_cast/explicit_casts_builtin.c2 +++ b/test/expr/explicit_cast/explicit_casts_builtin.c2 @@ -22,11 +22,12 @@ fn void test2(i32 a) { } fn void test3a(i32 a) { - Func b1 = (Func)(a); // @error{only integers of type 'u64' may be cast to a pointer} + // @error32{only integers of type 'u32' may be cast to a pointer} +1 + Func b1 = (Func)(a); // @error64{only integers of type 'u64' may be cast to a pointer} } fn void test4(u64 a) { - Func b1 = (Func)(a); + Func b1 = (Func)(a); // @error32{only integers of type 'u32' may be cast to a pointer} } fn void test5(i32 a) { diff --git a/test/expr/explicit_cast/explicit_casts_pointer.c2 b/test/expr/explicit_cast/explicit_casts_pointer.c2 index e4e0b6c44..19daced82 100644 --- a/test/expr/explicit_cast/explicit_casts_pointer.c2 +++ b/test/expr/explicit_cast/explicit_casts_pointer.c2 @@ -14,7 +14,7 @@ type Ptr void*; type Func fn void(i32); fn void test1(void* a) { - u32 b1 = (u32)(a); // @error{pointers may only be cast to integer type 'u64'} + u32 b1 = (u32)(a); // @error64{pointers may only be cast to integer type 'u64'} } fn void test2(void* a) { diff --git a/test/globals/static_asserts/static_assert_ok.c2 b/test/globals/static_asserts/static_assert_ok.c2 index 29c55b21f..4e739f19c 100644 --- a/test/globals/static_asserts/static_assert_ok.c2 +++ b/test/globals/static_asserts/static_assert_ok.c2 @@ -37,13 +37,20 @@ static_assert(123, A); type T1 struct { char* cp; } +#if ARCH_32BIT +static_assert(4, sizeof(T1)); +#else static_assert(8, sizeof(T1)); - +#endif type T2 struct { char* cp; char c; } +#if ARCH_32BIT +static_assert(8, sizeof(T2)); +#else static_assert(16, sizeof(T2)); +#endif type T3 struct { char[16] ca; diff --git a/test/parser/preprocessor_directives.c2 b/test/parser/preprocessor_directives.c2 index fea273e0e..6ec0db5ee 100644 --- a/test/parser/preprocessor_directives.c2 +++ b/test/parser/preprocessor_directives.c2 @@ -28,9 +28,9 @@ static_assert(Z, 1); #warning /* comment */ this is a disabled warning #endif -/**/ // @warning{this is a warning} +1 + // @warning{this is a warning} +1 #warning this is a warning -/**/ // @warning{this is a warning} +1 + // @warning{this is a warning} +1 #warning /* comment */ this is a warning public fn i32 main() { diff --git a/test/parser/sizeof_expr_ok.c2 b/test/parser/sizeof_expr_ok.c2 index fdee36892..1936f1d21 100644 --- a/test/parser/sizeof_expr_ok.c2 +++ b/test/parser/sizeof_expr_ok.c2 @@ -50,14 +50,22 @@ static_assert(sizeof(sp), sizeof(MyStruct*)); static_assert(sizeof(sp), sizeof(sp)); //static_assert(sizeof(const MyStruct[10]), sizeof(MyStruct) * 10); //static_assert(sizeof(MyStruct[10]), sizeof(MyStruct) * 10); +#if ARCH_32BIT +static_assert(sizeof(s), 24); +#else static_assert(sizeof(s), 32); +#endif //static_assert(sizeof(*&s), 32); static_assert(sizeof(s), sizeof(s)); static_assert(sizeof(s), sizeof(MyStruct)); //static_assert(sizeof(s), sizeof(MyStruct[1])); static_assert(sizeof(MyStruct), sizeof(s)); static_assert(sizeof(MyStruct), sizeof(MyStruct)); +#if ARCH_32BIT +static_assert(24, sizeof(MyStruct)); +#else static_assert(32, sizeof(MyStruct)); +#endif static_assert(sizeof(s.p), sizeof(usize)); static_assert(sizeof(s.def), 16); //static_assert(sizeof(*s.def), 1); diff --git a/test/types/conversion/integer_types.c2 b/test/types/conversion/integer_types.c2 index 9fb284f1d..3a7474172 100644 --- a/test/types/conversion/integer_types.c2 +++ b/test/types/conversion/integer_types.c2 @@ -81,8 +81,9 @@ fn void test_i64(i64 a) { u16 s2 = a; // @error{implicit conversion loses integer precision: 'i64' to 'u16'} u32 i2 = a; // @error{implicit conversion loses integer precision: 'i64' to 'u32'} u64 l2 = a; // @error{implicit conversion changes signedness: 'i64' to 'u64'} - isize is = a; - usize us = a; // @error{implicit conversion changes signedness: 'i64' to 'usize'} + isize is = a; // @error32{implicit conversion loses integer precision: 'i64' to 'isize'} + // @error32{implicit conversion loses integer precision: 'i64' to 'usize'} +1 + usize us = a; // @error64{implicit conversion changes signedness: 'i64' to 'usize'} } fn void test_u8(u8 a) { @@ -123,7 +124,7 @@ fn void test_u32(u32 a) { u16 s2 = a; // @error{implicit conversion loses integer precision: 'u32' to 'u16'} u32 i2 = a; u64 l2 = a; - isize us = a; + isize us = a; // @error32{implicit conversion changes signedness: 'u32' to 'isize'} usize is = a; } @@ -137,19 +138,21 @@ fn void test_u64(u64 a) { u16 s2 = a; // @error{implicit conversion loses integer precision: 'u64' to 'u16'} u32 i2 = a; // @error{implicit conversion loses integer precision: 'u64' to 'u32'} u64 l2 = a; - isize us = a; // @error{implicit conversion changes signedness: 'u64' to 'isize'} - usize is = a; + // @error32{implicit conversion loses integer precision: 'u64' to 'isize'} +1 + isize us = a; // @error64{implicit conversion changes signedness: 'u64' to 'isize'} + usize is = a; // @error32{implicit conversion loses integer precision: 'u64' to 'usize'} } fn void test_isize(isize a) { char c = a; // @error{implicit conversion loses integer precision: 'isize' to 'char'} i8 m = a; // @error{implicit conversion loses integer precision: 'isize' to 'i8'} i16 s = a; // @error{implicit conversion loses integer precision: 'isize' to 'i16'} - i32 i = a; // @error{implicit conversion loses integer precision: 'isize' to 'i32'} + i32 i = a; // @error64{implicit conversion loses integer precision: 'isize' to 'i32'} i64 l = a; u8 m2 = a; // @error{implicit conversion loses integer precision: 'isize' to 'u8'} u16 s2 = a; // @error{implicit conversion loses integer precision: 'isize' to 'u16'} - u32 i2 = a; // @error{implicit conversion loses integer precision: 'isize' to 'u32'} + // @error32{implicit conversion changes signedness: 'isize' to 'u32'} +1 + u32 i2 = a; // @error64{implicit conversion loses integer precision: 'isize' to 'u32'} u64 l2 = a; // @error{implicit conversion changes signedness: 'isize' to 'u64'} isize is = a; usize us = a; // @error{implicit conversion changes signedness: 'isize' to 'usize'} @@ -159,11 +162,12 @@ fn void test_usize(usize a) { char c = a; // @error{implicit conversion loses integer precision: 'usize' to 'char'} i8 m = a; // @error{implicit conversion loses integer precision: 'usize' to 'i8'} i16 s = a; // @error{implicit conversion loses integer precision: 'usize' to 'i16'} - i32 i = a; // @error{implicit conversion loses integer precision: 'usize' to 'i32'} - i64 l = a; // @error{implicit conversion changes signedness: 'usize' to 'i64'} + // @error32{implicit conversion changes signedness: 'usize' to 'i32'} +1 + i32 i = a; // @error64{implicit conversion loses integer precision: 'usize' to 'i32'} + i64 l = a; // @error64{implicit conversion changes signedness: 'usize' to 'i64'} u8 m2 = a; // @error{implicit conversion loses integer precision: 'usize' to 'u8'} u16 s2 = a; // @error{implicit conversion loses integer precision: 'usize' to 'u16'} - u32 i2 = a; // @error{implicit conversion loses integer precision: 'usize' to 'u32'} + u32 i2 = a; // @error64{implicit conversion loses integer precision: 'usize' to 'u32'} u64 l2 = a; isize us = a; // @error{implicit conversion changes signedness: 'usize' to 'isize'} usize is = a; diff --git a/test/types/conversion/ptr_subtract.c2 b/test/types/conversion/ptr_subtract.c2 index 0e0f0952c..2d9cd14a7 100644 --- a/test/types/conversion/ptr_subtract.c2 +++ b/test/types/conversion/ptr_subtract.c2 @@ -3,6 +3,6 @@ module test; fn u32 test1(const char* ptr) { const char* cp = ptr; - return cp - ptr; // @error{implicit conversion loses integer precision: 'isize' to 'u32'} + return cp - ptr; // @error64{implicit conversion loses integer precision: 'isize' to 'u32'} } diff --git a/test/types/enum/assoc/ptr_value.c2 b/test/types/enum/assoc/ptr_value.c2 index 7f674bcf0..a89d74d05 100644 --- a/test/types/enum/assoc/ptr_value.c2 +++ b/test/types/enum/assoc/ptr_value.c2 @@ -5,7 +5,7 @@ i32 number = 10; type Enum enum u8 (i32* a) { A : { 10 }, // @error{incompatible integer to pointer conversion: 'i32' to 'i32*'} - B : { (i32*)(u64)10 }, + B : { (i32*)(usize)10 }, C : { &number }, } diff --git a/test/types/literals_single/init_isize.c2 b/test/types/literals_single/init_isize.c2 index b2f6dce2a..517b4ab49 100644 --- a/test/types/literals_single/init_isize.c2 +++ b/test/types/literals_single/init_isize.c2 @@ -3,7 +3,12 @@ module test; fn void test1() { isize a = 0; +#if ARCH_32BIT + isize b = -2147483647; + isize c = 2147483647; +#else isize b = -9223372036854775807; isize c = 9223372036854775807; +#endif } diff --git a/test/types/literals_single/init_usize.c2 b/test/types/literals_single/init_usize.c2 index 2754c3b0e..6a5559dd6 100644 --- a/test/types/literals_single/init_usize.c2 +++ b/test/types/literals_single/init_usize.c2 @@ -3,7 +3,12 @@ module test; fn void test1() { usize a = 0; +#if ARCH_32BIT + usize b = 4294967295; + usize c = -1; // @error32{constant value -1 out-of-bounds for type 'usize', range [0, 4294967295]} +#else usize b = 18446744073709551615; - usize c = -1; // @error{constant value -1 out-of-bounds for type 'usize', range [0, 18446744073709551615]} + usize c = -1; // @error64{constant value -1 out-of-bounds for type 'usize', range [0, 18446744073709551615]} +#endif } diff --git a/test/types/struct/struct_member_offsets.c2 b/test/types/struct/struct_member_offsets.c2 index 9f8f74eba..fd8dd69a0 100644 --- a/test/types/struct/struct_member_offsets.c2 +++ b/test/types/struct/struct_member_offsets.c2 @@ -26,8 +26,13 @@ static_assert(0, offsetof(S2, f1)); static_assert(2, offsetof(S2, f2)); static_assert(4, offsetof(S2, f3)); static_assert(8, offsetof(S2, f4)); -static_assert(16, offsetof(S2, f5)); +#if ARCH_32BIT +static_assert(12, offsetof(S2, f5)); +static_assert(16, offsetof(S2, f6)); +#else static_assert(20, offsetof(S2, f6)); +static_assert(16, offsetof(S2, f5)); +#endif type S2p struct @(packed) { u8 f1; @@ -41,8 +46,13 @@ static_assert(0, offsetof(S2p, f1)); static_assert(1, offsetof(S2p, f2)); static_assert(3, offsetof(S2p, f3)); static_assert(7, offsetof(S2p, f4)); +#if ARCH_32BIT +static_assert(11, offsetof(S2p, f5)); +static_assert(14, offsetof(S2p, f6)); +#else static_assert(15, offsetof(S2p, f5)); static_assert(18, offsetof(S2p, f6)); +#endif type S3 struct { u32[10] array1; diff --git a/tools/tester/test_db.c2 b/tools/tester/test_db.c2 index 8580eaf56..c1038e3c6 100644 --- a/tools/tester/test_db.c2 +++ b/tools/tester/test_db.c2 @@ -21,6 +21,7 @@ import stdio local; import stdarg local; import stdlib local; import string local; +import sys_types local; // pid_t import unistd local; import constants; @@ -251,11 +252,12 @@ fn const char* Db.findEndOfLine(Db* db) { fn const char* Db.readWord(Db* db) { const char* cp = db.cur; - while (*cp != 0 && cp - db.cur < 31) { - if ((*cp < 'a' || *cp > 'z') && *cp != '-' && *cp != '_') break; + while (*cp != 0 && (isalnum(*cp) || *cp == '-' || *cp == '_')) { cp++; } u32 len = (u32)(cp - db.cur); + if (len >= elemsof(db.word_buffer)) + len = elemsof(db.word_buffer) - 1; memcpy(db.word_buffer, db.cur, len); db.word_buffer[len] = 0; return db.word_buffer; @@ -358,7 +360,7 @@ fn bool Db.parseFile(Db* db) { return true; } -fn bool Db.parseExpect(Db* db) { +fn bool Db.parseExpect(Db* db, bool add) { // Syntax expect{mode, name} if (*db.cur != '{') { db.errorMsg.add("expected { after expect"); @@ -394,11 +396,13 @@ fn bool Db.parseExpect(Db* db) { } db.skipLine(); // skip rest of the line - db.currentExpect = expect_file.create(filename, em); - // TODO check for name duplicates - db.addExpected(db.currentExpect); + if (add) { + db.currentExpect = expect_file.create(filename, em); + // TODO check for name duplicates + db.addExpected(db.currentExpect); + } while (*db.cur != 0 && !strstart(db.cur, "// @", nil)) { - if (*db.cur != '\n') { + if (*db.cur != '\n' && add) { db.currentExpect.addLine(db.line_nr, db.cur, db.findEndOfLine()); } db.skipLine(); @@ -411,6 +415,7 @@ fn bool Db.parseKeyword(Db* db) { // NOTE: cur points to start of keyword after // @ const char* keyword = db.readWord(); + i32 flags = 3; switch (keyword) { case "skip": if (!db.runSkipped) db.skip = true; @@ -437,13 +442,19 @@ fn bool Db.parseKeyword(Db* db) { } db.cur += 4; return db.parseFile(); + case "expect32": + flags = 0; + fallthrough; + case "expect64": + flags ^= 1; + fallthrough; case "expect": if (db.kind != C2T && db.kind != C2A) { - db.errorMsg.add("keyword 'expect' only allowed in .c2t/.c2a files"); + db.errorMsg.print("keyword '%s' only allowed in .c2t/.c2a files", keyword); return false; } - db.cur += 6; - return db.parseExpect(); + db.cur += strlen(keyword); + return db.parseExpect((sizeof(void*) / 4) & flags); default: db.errorMsg.print("unknown keyword '%s'", keyword); return false; @@ -492,16 +503,29 @@ fn void Db.parseTags(Db* db, const char* start, const char* end) { if (!cp) return; cp += 4; // skip "// @"; + i32 flags = 0; Type kind = ERROR; - if (strstart(cp, "error{", &cp)) { + if (strstart(cp, "error", &cp)) { kind = ERROR; } else - if (strstart(cp, "warning{", &cp)) { + if (strstart(cp, "warning", &cp)) { kind = WARNING; } else - if (strstart(cp, "note{", &cp)) { + if (strstart(cp, "note", &cp)) { kind = NOTE; } else { + goto fail; + } + if (strstart(cp, "32{", &cp)) { + flags = 1; + } else + if (strstart(cp, "64{", &cp)) { + flags = 2; + } else + if (strstart(cp, "{", &cp)) { + flags = 3; + } else { + fail: db.error("unknown tag, expect note/warning/error"); return; } @@ -510,6 +534,12 @@ fn void Db.parseTags(Db* db, const char* start, const char* end) { return; u32 line_nr = db.line_nr - db.line_offset; + if (!((sizeof(void*) / 4) & flags)) { +#if TesterDebug + color_print(color.Blue, " ignoring tag '%s' at %d", msg, line_nr); +#endif + return; + } // adjust line number for some special cases for (const char* suff = cp + strlen(msg) + 1; suff < end; suff++) { if (!isspace(*suff)) { @@ -541,7 +571,8 @@ fn void Db.parseTags(Db* db, const char* start, const char* end) { fn void Db.parseLineOutside(Db* db, const char* start, const char* end) { const char* cp = start; - skipInitialWhitespace(&cp, end); + //global directives must start at column 1 + //skipInitialWhitespace(&cp, end); if (cp == end) return; // TODO if .c2t/.cta, only accept tags or comments @@ -577,18 +608,34 @@ fn void Db.parseLineOutside(Db* db, const char* start, const char* end) { db.file_start = end + 1; db.line_offset = db.line_nr; db.mode = Infile; - } else if (strstart(cp, "expect{", &cp)) { + } else if (strstart(cp, "expect", &cp)) { if (db.kind != C2T) { db.error("invalid @expect tag in .c2/.cta test"); return; } + i32 flags = 0; + if (strstart(cp, "32{", &cp)) { + flags = 1; + } else + if (strstart(cp, "64{", &cp)) { + flags = 2; + } else + if (strstart(cp, "{", &cp)) { + flags = 3; + } else { + db.error("unknown tag"); + return; + } char[128] name; if (!db.readUntil(name, elemsof(name), cp, '}', "filename")) return; - db.currentExpect = expect_file.create(name, ATLEAST); - // TODO check for name duplicates - db.addExpected(db.currentExpect); + db.currentExpect = nil; db.mode = InExpectFile; + if ((sizeof(void*) / 4) & flags) { + db.currentExpect = expect_file.create(name, ATLEAST); + // TODO check for name duplicates + db.addExpected(db.currentExpect); + } } else if (strstart(cp, "backend c", &cp)) { if (db.kind != C2T) { db.error("invalid @backend c tag in .c2/c2a test"); @@ -631,9 +678,10 @@ fn void Db.parseLineExpect(Db* db, const char* start, const char* end) { db.parseLine(start, end); return; } - assert(db.currentExpect); - db.currentExpect.addLine(db.line_nr, start, end); - // TODO add non-empty lines (stripped of heading+trailing whitespace) to list + if (db.currentExpect) { + db.currentExpect.addLine(db.line_nr, start, end); + // TODO add non-empty lines (stripped of heading+trailing whitespace) to list + } } fn void Db.parseLine(Db* db, const char* start, const char* end) { @@ -687,7 +735,7 @@ public fn bool Db.parse(Db* db) { return false; case C2T: if (!db.parseOuter()) { - print_error("%s: error in recipe: %s on line %d", db.filename, db.errorMsg.str(), db.line_nr); + print_error_at("%s:%d: error in recipe: %s", db.filename, db.line_nr, db.errorMsg.str()); return false; } db.recipe.add("end\n"); @@ -700,7 +748,7 @@ public fn bool Db.parse(Db* db) { db.recipe.add(" $backend c skip\n"); db.recipe.add(" $write-AST\n"); if (!db.parseOuter()) { - print_error("%s: error in recipe: %s on line %d", db.filename, db.errorMsg.str(), db.line_nr); + print_error_at("%s:%d: error in recipe: %s", db.filename, db.line_nr, db.errorMsg.str()); return false; } db.recipe.add("end\n"); @@ -727,7 +775,7 @@ public fn void Db.testFile(Db* db) { } // spawn a child to run c2c - Pid pid = fork(); + pid_t pid = fork(); if (pid == -1) { fprintf(stderr, "fork() failed: %s\n", strerror(errno)); exit(1); diff --git a/tools/tester/test_utils.c2 b/tools/tester/test_utils.c2 index 800d8bad3..8ecf8ce77 100644 --- a/tools/tester/test_utils.c2 +++ b/tools/tester/test_utils.c2 @@ -72,6 +72,17 @@ public fn void print_error(const char* format @(printf_format), ...) { else fprintf(stderr, "%s: %s\n", proc_name, buffer); } +public fn void print_error_at(const char* format @(printf_format), ...) { + char[1024] buffer; + va_list args; + va_start(args, format); + vsnprintf(buffer, elemsof(buffer), format, args); + va_end(args); + + if (color_output) fprintf(stderr, "%s%s%s\n", color.Byellow.str(), buffer, color.Normal.str()); + else fprintf(stderr, "%s\n", buffer); +} + public fn void color_print2(string_buffer.Buf* output, Color col, const char* format @(printf_format),