From 1548cd06ef6dbcf9171bb1f4b647f14549296b37 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 11 Feb 2023 02:03:02 +0100 Subject: [PATCH] Enable local multi-declarations. Fix of builtin argument checking. Migrate to @noinit. --- CMakeLists.txt | 16 +-- lib/std/core/builtin.c3 | 2 +- lib/std/core/floatparse.c3 | 4 +- lib/std/core/mem.c3 | 4 +- lib/std/core/str.c3 | 2 +- lib/std/io/io_formatter_private.c3 | 4 +- lib/std/math/math_nolibc/__tan.c3 | 2 +- lib/std/math/math_nolibc/atan.c3 | 12 +- lib/std/math/math_nolibc/cos.c3 | 4 +- lib/std/math/math_nolibc/rempi.c3 | 16 +-- lib/std/math/math_nolibc/sin.c3 | 2 +- lib/std/math/math_nolibc/sincos.c3 | 2 +- resources/examples/fasta.c3 | 6 +- .../examples/notworking/acornvm/avm_memory.c3 | 2 +- src/compiler/compiler_internal.h | 2 + src/compiler/copying.c | 40 +++--- src/compiler/enums.h | 1 + src/compiler/llvm_codegen_stmt.c | 10 +- src/compiler/parse_stmt.c | 114 +++++++++++++++--- src/compiler/sema_builtins.c | 2 +- src/compiler/sema_stmts.c | 20 ++- src/utils/stringutils.c | 10 +- src/version.h | 2 +- test/test_suite/arrays/array_comparison.c3t | 24 ++-- test/test_suite/clang/2002-07.c3t | 14 +-- .../expressions/bool_conversions.c3t | 2 +- test/test_suite/functions/assorted_tests.c3t | 10 +- test/test_suite/initializer_lists/fasta.c3t | 6 +- test/test_suite/macros/userland_bitcast.c3t | 2 +- test/test_suite/variables/var_init_multi.c3t | 28 +++++ 30 files changed, 259 insertions(+), 106 deletions(-) create mode 100644 test/test_suite/variables/var_init_multi.c3t diff --git a/CMakeLists.txt b/CMakeLists.txt index d49f7e196..8d5d13c11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,15 +14,15 @@ if(MSVC) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Od /Zi") else() -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3") +#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") +#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3") +#set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1 -fsanitize=address") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O1 -fsanitize=address") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=address") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -fsanitize=address") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") endif() -#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1 -fsanitize=undefined") -#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O1 -fsanitize=undefined") -#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=undefined") -#set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -fsanitize=undefined") -#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined") set(C3_LLVM_VERSION "auto" CACHE STRING "Use LLVM version [default: auto]") option(C3_USE_MIMALLOC "Use built-in mimalloc" OFF) diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index acb14262e..b12a8fa3f 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -102,7 +102,7 @@ macro bitcast(expr, $Type) @builtin { var $size = (usz)($sizeof(expr)); $assert($size == $Type.sizeof, "Cannot bitcast between types of different size."); - $Type x = void; + $Type x @noinit; mem::copy(&x, &expr, $size, $Type.alignof, $alignof(expr)); return x; } diff --git a/lib/std/core/floatparse.c3 b/lib/std/core/floatparse.c3 index 00f22e027..62f6f6364 100644 --- a/lib/std/core/floatparse.c3 +++ b/lib/std/core/floatparse.c3 @@ -50,7 +50,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign) assert(len); - char c = void; + char c @noinit; // Skip past first characters while ((c = chars[index]) == '0') { @@ -335,7 +335,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign) uint x; long rp; long dc; - char c = void; + char c @noinit; bool got_rad; bool got_digit; bool got_tail; diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 90af23470..e3c9557fb 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -99,8 +99,8 @@ macro bool equals(a, b, isz len = -1, usz $align = 0) $if (!$align): $align = $typeof(a[0]).alignof; $endif; - void* x = void; - void* y = void; + void* x @noinit; + void* y @noinit; $if ($typeof(a).kindof == TypeKind.SUBARRAY): len = a.len; if (len != b.len) return false; diff --git a/lib/std/core/str.c3 b/lib/std/core/str.c3 index 6c6632826..df85f7228 100644 --- a/lib/std/core/str.c3 +++ b/lib/std/core/str.c3 @@ -170,7 +170,7 @@ fn String[] split(String s, String needle, Allocator* allocator = mem::current_a while (s.len) { usz! index = index_of(s, needle); - String res = void; + String res @noinit; if (try index) { res = s[:index]; diff --git a/lib/std/io/io_formatter_private.c3 b/lib/std/io/io_formatter_private.c3 index 52fee86c2..d1ee62716 100644 --- a/lib/std/io/io_formatter_private.c3 +++ b/lib/std/io/io_formatter_private.c3 @@ -247,7 +247,7 @@ private fn void! Formatter.etoa(Formatter* this, FloatType value) // internal ftoa for fixed decimal floating point private fn void! Formatter.ftoa(Formatter* this, FloatType value) { - char[PRINTF_FTOA_BUFFER_SIZE] buf = void; + char[PRINTF_FTOA_BUFFER_SIZE] buf @noinit; usz len = 0; const FloatType[] POW10 = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; FloatType diff = 0.0; @@ -381,7 +381,7 @@ private fn void! Formatter.ftoa(Formatter* this, FloatType value) private fn void! Formatter.ntoa(Formatter* this, uint128 value, bool negative, uint base) { - char[PRINTF_NTOA_BUFFER_SIZE] buf = void; + char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit; usz len = 0; // no hash for 0 values diff --git a/lib/std/math/math_nolibc/__tan.c3 b/lib/std/math/math_nolibc/__tan.c3 index c6b764000..d5801de57 100644 --- a/lib/std/math/math_nolibc/__tan.c3 +++ b/lib/std/math/math_nolibc/__tan.c3 @@ -36,7 +36,7 @@ fn double __tan(double x, double y, int odd) @extern("__tan") @weak uint hx = (uint)(bitcast(x, ulong) >> 32); bool big = (hx &0x7fffffff) >= 0x3FE59428; // |x| >= 0.6744 - int sign = void; + int sign @noinit; if (big) { sign = hx >> 31; diff --git a/lib/std/math/math_nolibc/atan.c3 b/lib/std/math/math_nolibc/atan.c3 index a015d531e..0b8b80302 100644 --- a/lib/std/math/math_nolibc/atan.c3 +++ b/lib/std/math/math_nolibc/atan.c3 @@ -32,7 +32,7 @@ private const double[*] AT = { fn double _atan(double x) @weak @extern("atan") { - int id = void; + int id @noinit; uint ix = x.high_word(); uint sign = ix >> 31; ix &= 0x7fffffff; @@ -115,7 +115,7 @@ private const float[*] ATF = { fn float _atanf(float x) @weak @extern("atanf") { - int id = void; + int id @noinit; uint ix = x.word(); uint sign = ix >> 31; ix &= 0x7fffffff; @@ -190,11 +190,11 @@ fn double _atan2(double y, double x) @weak @extern("atan2") { if (math::is_nan(x) || math::is_nan(y)) return x + y; - uint lx = void; - uint ix = void; + uint lx @noinit; + uint ix @noinit; extract_words(x, &ix, &lx); - uint ly = void; - uint iy = void; + uint ly @noinit; + uint iy @noinit; extract_words(y, &iy, &ly); // x = 1.0 diff --git a/lib/std/math/math_nolibc/cos.c3 b/lib/std/math/math_nolibc/cos.c3 index 078474f86..df4bd8322 100644 --- a/lib/std/math/math_nolibc/cos.c3 +++ b/lib/std/math/math_nolibc/cos.c3 @@ -31,7 +31,7 @@ fn float _cosf(float x) @extern("cosf") @weak } // general argument reduction needed - double y = void; + double y @noinit; switch (__rem_pio2f(x, &y) & 3) { case 0: return __cosdf(y); @@ -77,7 +77,7 @@ fn double _cos(double x) @extern("cos") @weak return x - x; default: // argument reduction - double[2] y = void; + double[2] y @noinit; switch (__rem_pio2(x, &y) & 3) { case 0: return __cos(y[0], y[1]); diff --git a/lib/std/math/math_nolibc/rempi.c3 b/lib/std/math/math_nolibc/rempi.c3 index 50b7f8773..da67ccf3a 100644 --- a/lib/std/math/math_nolibc/rempi.c3 +++ b/lib/std/math/math_nolibc/rempi.c3 @@ -73,7 +73,7 @@ fn int __rem_pio2f(float x, double *y) int e0 = (ix >> 23) - (0x7f + 23); /* e0 = ilogb(|x|)-23, positive */ ux = ix - e0 << 23; double tx = bitcast(ux, float); - double ty = void; + double ty @noinit; int n = __rem_pio2_large(&tx,&ty, e0, 1, 0); if (sign) { @@ -124,11 +124,11 @@ const double[*] PIO2 = { fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) { - double[20] f = void; - double[20] fq = void; - double[20] q = void; - int[20] iq = void; - double fw = void; + double[20] f @noinit; + double[20] fq @noinit; + double[20] q @noinit; + int[20] iq @noinit; + double fw @noinit; /* initialize jk*/ int jk = INIT_JK[prec]; int jp = jk; @@ -155,9 +155,9 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) } int jz = jk; - double z = void; + double z @noinit; int ih = 0; - int n = void; + int n @noinit; while (1) { /* distill q[] into iq[] reversingly */ diff --git a/lib/std/math/math_nolibc/sin.c3 b/lib/std/math/math_nolibc/sin.c3 index 1d75fd301..9f5a6bdee 100644 --- a/lib/std/math/math_nolibc/sin.c3 +++ b/lib/std/math/math_nolibc/sin.c3 @@ -64,7 +64,7 @@ fn float _sinf(float x) @weak @extern("sinf") return x - x; } /* general argument reduction needed */ - double y = void; + double y @noinit; switch (__rem_pio2f(x, &y) & 3) { case 0: return __sindf(y); diff --git a/lib/std/math/math_nolibc/sincos.c3 b/lib/std/math/math_nolibc/sincos.c3 index f819fd0ff..192840715 100644 --- a/lib/std/math/math_nolibc/sincos.c3 +++ b/lib/std/math/math_nolibc/sincos.c3 @@ -83,7 +83,7 @@ fn void sincosf(float x, float *sin, float *cos) @extern("sincosf") @weak *sin = *cos = x - x; default: // general argument reduction needed - double y = void; + double y @noinit; uint n = __rem_pio2f(x, &y); float s = __sindf(y); float c = __cosdf(y); diff --git a/resources/examples/fasta.c3 b/resources/examples/fasta.c3 index 876c15221..810005dab 100644 --- a/resources/examples/fasta.c3 +++ b/resources/examples/fasta.c3 @@ -57,7 +57,7 @@ const LINELEN = 60; fn void repeat_fasta(String seq, int n) { usz len = seq.len; - int i = void; + int i @noinit; for (i = 0; i < n; i++) { io::putchar(seq[i % len]); @@ -70,12 +70,12 @@ fn void random_fasta(String symb, double[] probability, int n) { assert(symb.len == probability.len); int len = probability.len; - int i = void; + int i @noinit; for (i = 0; i < n; i++) { double v = fasta_rand(1.0); /* slowest idiomatic linear lookup. Fast if len is short though. */ - int j = void; + int j @noinit; for (j = 0; j < len - 1; j++) { v -= probability[j]; diff --git a/resources/examples/notworking/acornvm/avm_memory.c3 b/resources/examples/notworking/acornvm/avm_memory.c3 index 0bbb0bb5f..455aaf40e 100644 --- a/resources/examples/notworking/acornvm/avm_memory.c3 +++ b/resources/examples/notworking/acornvm/avm_memory.c3 @@ -137,7 +137,7 @@ fn MemInfo* newnolink(Value th, int enc, Auint sz) fn void growaux_(Value th, void *block, AuintIdx *size, AuintIdx size_elems, AuintIdx limit) { void* newblock; - AuintIdx newsize = void; + AuintIdx newsize @noinit; // cannot double it? if (*size >= limit / 2) { diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index c5f84cd63..38fc8b956 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1448,6 +1448,7 @@ typedef struct Ast_ AstAsmStmt asm_stmt; AstCompoundStmt compound_stmt; // 12 Decl *declare_stmt; // 8 + Decl **decls_stmt; Expr *expr_stmt; // 8 Decl *var_stmt; // 8 AstReturnStmt return_stmt; // 16 @@ -2042,6 +2043,7 @@ void copy_end(void); Expr *copy_expr_single(Expr *source_expr); Decl **copy_decl_list_single(Decl **decl_list); Decl **copy_decl_list_single_for_unit(Decl **decl_list); +Attr **copy_attributes_single(Attr** attr_list); Decl *copy_lambda_deep(Decl *decl); Ast *copy_ast_single(Ast *source_ast); Decl **copy_decl_list_macro(Decl **decl_list); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index cc47de44c..f5386679a 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -535,6 +535,9 @@ RETRY: { case AST_POISONED: break; + case AST_DECLS_STMT: + MACRO_COPY_DECL_LIST(ast->decls_stmt); + break; case AST_DOC_STMT: doc_ast_copy(c, &source->doc_stmt); break; @@ -700,6 +703,29 @@ Decl **copy_decl_list_single(Decl **decl_list) return result; } +static Attr **copy_attributes(CopyStruct *c, Attr** attr_list) +{ + if (!attr_list) return attr_list; + Attr** list = NULL; + VECEACH(attr_list, i) + { + Attr *attribute = attr_list[i]; + Attr *copy = MALLOCS(Attr); + *copy = *attribute; + MACRO_COPY_EXPR_LIST(copy->exprs); + vec_add(list, copy); + } + return list; +} + +Attr **copy_attributes_single(Attr** attr_list) +{ + copy_begin(); + Attr **attrs = copy_attributes(©_struct, attr_list); + copy_end(); + return attrs; +} + Decl **copy_decl_list_single_for_unit(Decl **decl_list) { bool old_is_template = copy_struct.is_template; @@ -788,20 +814,6 @@ void copy_decl_type(Decl *decl) decl->type = copy; } -static Attr **copy_attributes(CopyStruct *c, Attr** attr_list) -{ - if (!attr_list) return attr_list; - Attr** list = NULL; - VECEACH(attr_list, i) - { - Attr *attribute = attr_list[i]; - Attr *copy = MALLOCS(Attr); - *copy = *attribute; - MACRO_COPY_EXPR_LIST(copy->exprs); - vec_add(list, copy); - } - return list; -} static inline bool decl_is_resolved_static_var(Decl *decl) { diff --git a/src/compiler/enums.h b/src/compiler/enums.h index a41af2aa9..9fef9c09c 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -60,6 +60,7 @@ typedef enum AST_CT_IF_STMT, AST_CT_SWITCH_STMT, AST_DECLARE_STMT, + AST_DECLS_STMT, AST_DEFAULT_STMT, AST_DEFER_STMT, AST_EXPR_STMT, diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 3a692f08f..a350b4faf 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -1125,7 +1125,7 @@ static inline void llvm_emit_asm_block_stmt(GenContext *c, Ast *ast) if (val->ident.copy_output) { char buf[10]; - sprintf(buf, "%d", val->index); + snprintf(buf, 10, "%d", val->index); codegen_append_constraints(&clobber_list, buf); } else @@ -1442,6 +1442,14 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) llvm_emit_local_decl(c, ast->declare_stmt, &value); break; } + case AST_DECLS_STMT: + { + BEValue value; + FOREACH_BEGIN(Decl *decl, ast->decls_stmt) + llvm_emit_local_decl(c, decl, &value); + FOREACH_END(); + break; + } case AST_BREAK_STMT: llvm_emit_break(c, ast); break; diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index d04303b03..c325e0033 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -10,16 +10,104 @@ static inline Expr *parse_asm_expr(ParseContext *c); +static Ast *parse_declaration_statment_after_type(ParseContext *c, TypeInfo *type) +{ + Ast *ast = ast_calloc(); + ast->span = type->span; + ast->ast_kind = AST_DECLARE_STMT; + ASSIGN_DECL_OR_RET(ast->declare_stmt, parse_decl_after_type(c, type), poisoned_ast); + + if (tok_is(c, TOKEN_EOS)) return ast; + Decl *decl = ast->declare_stmt; + if (decl->attributes || decl->var.init_expr) + { + if (tok_is(c, TOKEN_COMMA) && peek(c) == TOKEN_IDENT) + { + if (decl->var.init_expr) + { + SEMA_ERROR(decl->var.init_expr, "Multiple variable declarations cannot use initialization."); + return poisoned_ast; + } + if (decl->attributes) + { + assert(VECLAST(decl->attributes)); + SEMA_ERROR(VECLAST(decl->attributes), "Multiple variable declarations must have attributes at the end."); + return poisoned_ast; + } + } + RANGE_EXTEND_PREV(ast); + return ast; + } + Decl **decls = NULL; + vec_add(decls, decl); + Attr **attributes = NULL; + while (try_consume(c, TOKEN_COMMA)) + { + ASSIGN_DECL_OR_RET(decl, parse_decl_after_type(c, copy_type_info_single(type)), poisoned_ast); + if (decl->var.init_expr) + { + SEMA_ERROR(decl->var.init_expr, "Multiple variable declarations cannot use initialization."); + return poisoned_ast; + } + if (decl->attributes) + { + if (tok_is(c, TOKEN_COMMA)) + { + assert(VECLAST(decl->attributes)); + SEMA_ERROR(VECLAST(decl->attributes), "Multiple variable declarations must have attributes at the end."); + return poisoned_ast; + } + attributes = decl->attributes; + } + vec_add(decls, decl); + } + if (attributes) + { + FOREACH_BEGIN(Decl *d, decls) + if (d == decl) continue; + d->attributes = copy_attributes_single(attributes); + FOREACH_END(); + } + ast->decls_stmt = decls; + ast->ast_kind = AST_DECLS_STMT; + RANGE_EXTEND_PREV(ast); + return ast; + +} + /** * declaration_stmt * : declaration ';' */ static inline Ast *parse_declaration_stmt(ParseContext *c) { - Ast *decl_stmt = new_ast(AST_DECLARE_STMT, c->span); - ASSIGN_DECL_OR_RET(decl_stmt->declare_stmt, parse_decl(c), poisoned_ast); + if (tok_is(c, TOKEN_CONST)) + { + // Consts don't have multiple declarations. + Ast *decl_stmt = new_ast(AST_DECLARE_STMT, c->span); + ASSIGN_DECL_OR_RET(decl_stmt->declare_stmt, parse_decl(c), poisoned_ast); + RANGE_EXTEND_PREV(decl_stmt); + CONSUME_EOS_OR_RET(poisoned_ast); + return decl_stmt; + } + + bool is_threadlocal = try_consume(c, TOKEN_TLOCAL); + bool is_static = !is_threadlocal && try_consume(c, TOKEN_STATIC); + is_static = is_threadlocal || is_static; + ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_ast); + ASSIGN_AST_OR_RET(Ast *result, parse_declaration_statment_after_type(c, type), poisoned_ast); CONSUME_EOS_OR_RET(poisoned_ast); - return decl_stmt; + if (result->ast_kind == AST_DECLARE_STMT) + { + result->declare_stmt->var.is_threadlocal = is_threadlocal; + result->declare_stmt->var.is_static = is_static; + return result; + } + FOREACH_BEGIN(Decl *var, result->decls_stmt) + var->var.is_threadlocal = is_threadlocal; + var->var.is_static = is_static; + FOREACH_END(); + return result; } static inline Decl *parse_optional_label(ParseContext *c, Ast *parent) @@ -765,8 +853,6 @@ static inline Ast *parse_expr_stmt(ParseContext *c) static inline Ast *parse_decl_or_expr_stmt(ParseContext *c) { ASSIGN_EXPR_OR_RET(Expr * expr, parse_expr(c), poisoned_ast); - Ast *ast = ast_calloc(); - ast->span = expr->span; // We might be parsing "int!" // If so we need to unwrap this. if (expr->expr_kind == EXPR_OPTIONAL && expr->inner_expr->expr_kind == EXPR_TYPEINFO) @@ -775,18 +861,16 @@ static inline Ast *parse_decl_or_expr_stmt(ParseContext *c) } if (expr->expr_kind == EXPR_TYPEINFO) { - ast->ast_kind = AST_DECLARE_STMT; - ASSIGN_DECL_OR_RET(ast->declare_stmt, parse_decl_after_type(c, expr->type_expr), poisoned_ast); + return parse_declaration_statment_after_type(c, expr->type_expr); } - else + Ast *ast = ast_calloc(); + ast->span = expr->span; + ast->ast_kind = AST_EXPR_STMT; + ast->expr_stmt = expr; + if (tok_is(c, TOKEN_IDENT) && expr->expr_kind == EXPR_IDENTIFIER) { - ast->ast_kind = AST_EXPR_STMT; - ast->expr_stmt = expr; - if (tok_is(c, TOKEN_IDENT) && expr->expr_kind == EXPR_IDENTIFIER) - { - SEMA_ERROR(expr, "Expected a type here."); - return poisoned_ast; - } + SEMA_ERROR(expr, "Expected a type here."); + return poisoned_ast; } CONSUME_EOS_OR_RET(poisoned_ast); return ast; diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index 8a9646530..6e177401e 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -522,7 +522,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) case BUILTIN_SQRT: case BUILTIN_TRUNC: if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_FLOATLIKE }, + (BuiltinArg[]) { BA_FLOATLIKE, BA_FLOATLIKE, BA_FLOATLIKE }, arg_count)) return false; rtype = args[0]->type; break; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index ccb45e459..ad5a2829e 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -913,6 +913,22 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType } +static inline bool sema_analyse_decls_stmt(SemaContext *context, Ast *statement) +{ + bool should_nop = false; + FOREACH_BEGIN(Decl *decl, statement->decls_stmt) + VarDeclKind kind = decl->var.kind; + if (kind == VARDECL_LOCAL_CT_TYPE || kind == VARDECL_LOCAL_CT) + { + if (!sema_analyse_var_decl_ct(context, decl)) return false; + } + assert(!should_nop); + if (!sema_analyse_var_decl(context, decl, true)) return false; + FOREACH_END(); + if (should_nop) statement->ast_kind = AST_NOP_STMT; + return true; +} + static inline bool sema_analyse_declare_stmt(SemaContext *context, Ast *statement) { VarDeclKind kind = statement->declare_stmt->var.kind; @@ -1250,7 +1266,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen // Set up the value, assigning the type as needed. - // Element *value = void + // Element *value @noinit if (!var->var.type_info) { var->var.type_info = type_info_new_base(value_type, var->span); @@ -2583,6 +2599,8 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state case AST_DOC_STMT: case AST_ASM_STMT: UNREACHABLE + case AST_DECLS_STMT: + return sema_analyse_decls_stmt(context, statement); case AST_ASM_BLOCK_STMT: return sema_analyse_asm_stmt(context, statement); case AST_ASSERT_STMT: diff --git a/src/utils/stringutils.c b/src/utils/stringutils.c index 6ca19903d..61be56ed7 100644 --- a/src/utils/stringutils.c +++ b/src/utils/stringutils.c @@ -6,7 +6,7 @@ #include #include #include "lib.h" -#include "stdio.h" +#include struct ScratchBuf scratch_buffer; @@ -224,7 +224,7 @@ void scratch_buffer_append(const char *string) void scratch_buffer_append_signed_int(int64_t i) { - uint32_t len_needed = (uint32_t)sprintf(&scratch_buffer.str[scratch_buffer.len], "%lld", (long long)i); + uint32_t len_needed = (uint32_t)snprintf(&scratch_buffer.str[scratch_buffer.len], MAX_STRING_BUFFER, "%lld", (long long)i); if (scratch_buffer.len + len_needed > MAX_STRING_BUFFER - 1) { error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1); @@ -234,7 +234,7 @@ void scratch_buffer_append_signed_int(int64_t i) void scratch_buffer_append_double(double d) { - uint32_t len_needed = (uint32_t)sprintf(&scratch_buffer.str[scratch_buffer.len], "%f", d); + uint32_t len_needed = (uint32_t)snprintf(&scratch_buffer.str[scratch_buffer.len], MAX_STRING_BUFFER, "%f", d); if (scratch_buffer.len + len_needed > MAX_STRING_BUFFER - 1) { error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1); @@ -255,7 +255,7 @@ void scratch_buffer_append_double(double d) void scratch_buffer_append_unsigned_int(uint64_t i) { - uint32_t len_needed = (uint32_t)sprintf(&scratch_buffer.str[scratch_buffer.len], "%llu", (unsigned long long)i); + uint32_t len_needed = (uint32_t)snprintf(&scratch_buffer.str[scratch_buffer.len], MAX_STRING_BUFFER, "%llu", (unsigned long long)i); if (scratch_buffer.len + len_needed > MAX_STRING_BUFFER - 1) { error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1); @@ -267,7 +267,7 @@ void scratch_buffer_printf(const char *format, ...) { va_list args; va_start(args, format); - uint32_t len_needed = (uint32_t)vsprintf(&scratch_buffer.str[scratch_buffer.len], format, args); + uint32_t len_needed = (uint32_t)vsnprintf(&scratch_buffer.str[scratch_buffer.len], MAX_STRING_BUFFER, format, args); if (scratch_buffer.len + len_needed > MAX_STRING_BUFFER - 1) { error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1); diff --git a/src/version.h b/src/version.h index 154d86221..f5e16775d 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.57" \ No newline at end of file +#define COMPILER_VERSION "0.4.58" \ No newline at end of file diff --git a/test/test_suite/arrays/array_comparison.c3t b/test/test_suite/arrays/array_comparison.c3t index a2780a060..109d5a155 100644 --- a/test/test_suite/arrays/array_comparison.c3t +++ b/test/test_suite/arrays/array_comparison.c3t @@ -7,22 +7,22 @@ extern fn void get3(bool[2]*); fn void test() { - double[2] a = void; - double[2] b = void; + double[2] a @noinit; + double[2] b @noinit; get(&a); get(&b); bool x = a == b; bool y = a != b; - int[2] a2 = void; - int[2] b2 = void; + int[2] a2 @noinit; + int[2] b2 @noinit; get2(&a2); get2(&b2); bool x2 = a2 == b2; bool y2 = a2 != b2; - bool[2] a3 = void; - bool[2] b3 = void; + bool[2] a3 @noinit; + bool[2] b3 @noinit; get3(&a3); get3(&b3); @@ -37,22 +37,22 @@ extern fn void aget3(bool[200]*); fn void test2() { - double[200] a = void; - double[200] b = void; + double[200] a @noinit; + double[200] b @noinit; aget(&a); aget(&b); bool x = a == b; bool y = a != b; - int[200] a2 = void; - int[200] b2 = void; + int[200] a2 @noinit; + int[200] b2 @noinit; aget2(&a2); aget2(&b2); bool x2 = a2 == b2; bool y2 = a2 != b2; - bool[200] a3 = void; - bool[200] b3 = void; + bool[200] a3 @noinit; + bool[200] b3 @noinit; aget3(&a3); aget3(&b3); bool x3 = a3 == b3; diff --git a/test/test_suite/clang/2002-07.c3t b/test/test_suite/clang/2002-07.c3t index 327eb8701..914d373bb 100644 --- a/test/test_suite/clang/2002-07.c3t +++ b/test/test_suite/clang/2002-07.c3t @@ -161,7 +161,7 @@ fn char smallArgs(char w, char x, char y, char z) { } private fn int f0(Quad q, int i) { /* Pass Q by value */ - Quad r = void; + Quad r @noinit; if (i) r.ss = q.ss; q.ssp = &r.ss; q.w = q.y = q.c = 1; @@ -169,7 +169,7 @@ private fn int f0(Quad q, int i) { /* Pass Q by value */ } fn int f1(Quad *q, int i) { /* Pass Q by address */ - Quad r = void; + Quad r @noinit; if (i) r = *q; q.w = q.y = q.c = 1; return q.ss.y+i+r.y-q.c; @@ -177,7 +177,7 @@ fn int f1(Quad *q, int i) { /* Pass Q by address */ fn int badFunc(float val) { - int result = void; + int result @noinit; if (val > 12.345) result = 4; return result; /* Test use of undefined value */ } @@ -188,7 +188,7 @@ fn int func(int param, long param2) { int result = param; {{{{ - char c = void; int x = void; + char c @noinit; int x @noinit; ef1(&result, &c, &x); }}} @@ -220,7 +220,7 @@ fn int funcZ(int i, int j) { } fn int sumArray(int* array, int num) { - int i = void; + int i @noinit; int result = 0; for (i = 0; i < num; ++i) result += array[i]; @@ -233,7 +233,7 @@ fn int arrayParam(int* values) { } fn int arrayToSum() { - int[100] a = void; + int[100] a @noinit; int i; for (i = 0; i < 100; ++i) a[i] = i*4; @@ -245,7 +245,7 @@ fn int arrayToSum() { fn int externFunc(long, uint*, short, char); fn int main(int argc, char **argv) { - uint i = void; + uint i @noinit; puts("Hello world!\n"); externFunc(-1, null, (short)argc, 2); diff --git a/test/test_suite/expressions/bool_conversions.c3t b/test/test_suite/expressions/bool_conversions.c3t index 657a2b3f7..928256869 100644 --- a/test/test_suite/expressions/bool_conversions.c3t +++ b/test/test_suite/expressions/bool_conversions.c3t @@ -6,7 +6,7 @@ fn int f0() { return (int)f0_0((void*)0x2); } define Test = fn void(); -fn bool f1() { return (bool){| Test x = void; return x = (Test)0; |}; } +fn bool f1() { return (bool){| Test x @noinit; return x = (Test)0; |}; } /* #expect: bool_conversions.ll diff --git a/test/test_suite/functions/assorted_tests.c3t b/test/test_suite/functions/assorted_tests.c3t index 13f358722..b939d8473 100644 --- a/test/test_suite/functions/assorted_tests.c3t +++ b/test/test_suite/functions/assorted_tests.c3t @@ -2,8 +2,8 @@ module test; fn int foo1() { - char *pp = void; - uint w_cnt = void; + char *pp @noinit; + uint w_cnt @noinit; w_cnt += *pp; @@ -19,9 +19,9 @@ fn void foo2(int x) fn int trys(ichar* s, int x) { - int asa = void; - double val = void; - int lls = void; + int asa @noinit; + double val @noinit; + int lls @noinit; if (x) { asa = lls + asa; diff --git a/test/test_suite/initializer_lists/fasta.c3t b/test/test_suite/initializer_lists/fasta.c3t index 03c380a71..ec2c582e5 100644 --- a/test/test_suite/initializer_lists/fasta.c3t +++ b/test/test_suite/initializer_lists/fasta.c3t @@ -59,7 +59,7 @@ const LINELEN = 60; fn void repeat_fasta(char[] seq, int n) { usz len = seq.len; - int i = void; + int i @noinit; for (i = 0; i < n; i++) { putchar(seq[i % len]); @@ -72,12 +72,12 @@ fn void random_fasta(char[] symb, double[] probability, int n) { assert(symb.len == probability.len); int len = probability.len; - int i = void; + int i @noinit; for (i = 0; i < n; i++) { double v = fasta_rand(1.0); /* slowest idiomatic linear lookup. Fast if len is short though. */ - int j = void; + int j @noinit; for (j = 0; j < len - 1; j++) { v -= probability[j]; diff --git a/test/test_suite/macros/userland_bitcast.c3t b/test/test_suite/macros/userland_bitcast.c3t index bc1d944fe..459d5967f 100644 --- a/test/test_suite/macros/userland_bitcast.c3t +++ b/test/test_suite/macros/userland_bitcast.c3t @@ -3,7 +3,7 @@ macro testbitcast(expr, $Type) { $assert($sizeof(expr) == $Type.sizeof, "Cannot bitcast between types of different size."); - $Type x = void; + $Type x @noinit; var $size = (usz)($sizeof(expr)); $if ($alignof(expr) >= 8 && $Type.alignof >= 8): diff --git a/test/test_suite/variables/var_init_multi.c3t b/test/test_suite/variables/var_init_multi.c3t new file mode 100644 index 000000000..e55193ecf --- /dev/null +++ b/test/test_suite/variables/var_init_multi.c3t @@ -0,0 +1,28 @@ +// #target: macos-x64 +module test; +fn int main() +{ + static int sx, sy; + tlocal int tx, ty; + int x, y; + int* z, w @noinit @align(16); + return x; +} + +/* #expect: test.ll + +@"main$sx" = internal unnamed_addr global i32 0, align 4 +@"main$sy" = internal unnamed_addr global i32 0, align 4 +@"main$tx" = internal thread_local(localdynamic) unnamed_addr global i32 0, align 4 +@"main$ty" = internal thread_local(localdynamic) unnamed_addr global i32 0, align 4 + +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca ptr, align 16 + %w = alloca ptr, align 16 + store i32 0, ptr %x, align 4 + store i32 0, ptr %y, align 4 + %0 = load i32, ptr %x, align 4 + ret i32 %0 +}