From dd4edfb7471ce389db6a908f65ea90d234debb84 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 27 Feb 2023 14:51:35 +0100 Subject: [PATCH] Updated malloc/calloc/realloc/free deprecation of old helper functions. Add checks to prevent incorrect alignment on types when using malloc. Better errors from $assert. Added @deprecated. Fixed issue using named arguments after varargs. --- lib/std/collections/linkedlist.c3 | 4 +- lib/std/collections/list.c3 | 6 +- lib/std/collections/map.c3 | 12 +- lib/std/core/allocators/arena_allocator.c3 | 12 +- lib/std/core/allocators/dynamic_arena.c3 | 12 +- lib/std/core/allocators/heap_allocator.c3 | 6 +- lib/std/core/allocators/mem_allocator_fn.c3 | 4 +- lib/std/core/allocators/temp_allocator.c3 | 16 +- lib/std/core/mem.c3 | 226 +++++-- lib/std/core/mem_allocator.c3 | 6 +- lib/std/core/mem_array.c3 | 30 +- lib/std/core/private/main_stub.c3 | 4 +- lib/std/core/str.c3 | 16 +- lib/std/core/string.c3 | 10 +- lib/std/io/io_stream.c3 | 4 +- lib/std/io/stream/bytewriter.c3 | 4 +- lib/std/threads/os/thread_posix.c3 | 2 +- resources/examples/contextfree/boolerr.c3 | 2 +- resources/testfragments/allocators_testing.c3 | 8 +- src/compiler/compiler_internal.h | 2 + src/compiler/enums.h | 1 + src/compiler/sema_decls.c | 15 +- src/compiler/sema_expr.c | 3 +- src/compiler/sema_stmts.c | 16 +- src/compiler/symtab.c | 1 + src/version.h | 2 +- test/test_suite/assert/static_assert.c3 | 2 +- test/test_suite/errors/error_regression_2.c3t | 622 +++++++++++++----- 28 files changed, 705 insertions(+), 343 deletions(-) diff --git a/lib/std/collections/linkedlist.c3 b/lib/std/collections/linkedlist.c3 index a0ecee378..23d77bd90 100644 --- a/lib/std/collections/linkedlist.c3 +++ b/lib/std/collections/linkedlist.c3 @@ -45,7 +45,7 @@ macro void LinkedList.@free_node(LinkedList &list, Node* node) @private macro Node* LinkedList.@alloc_node(LinkedList &list) @private { if (!list.allocator) list.allocator = mem::current_allocator(); - return list.allocator.alloc(Node.sizeof)!!; + return malloc(Node, .using = list.allocator); } fn void LinkedList.link_first(LinkedList* list, Type value) @private @@ -175,7 +175,7 @@ fn void LinkedList.insert(LinkedList* list, usz index, Type element) fn void LinkedList.link_before(LinkedList *list, Node *succ, Type value) @private { Node* pred = succ.prev; - Node* new_node = mem::alloc(Node); + Node* new_node = malloc(Node); *new_node = { .prev = pred, .next = succ, .value = value }; succ.prev = new_node; if (!pred) diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index 96f606e6f..c316999b9 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -22,7 +22,7 @@ fn void List.init(List* list, usz initial_capacity = 16, Allocator* allocator = if (initial_capacity > 0) { initial_capacity = math::next_power_of_2(initial_capacity); - list.entries = allocator.alloc_aligned(Type.sizeof * initial_capacity, Type[1].alignof)!!; + list.entries = malloc_aligned(Type, initial_capacity, .alignment = Type[1].alignof, .using = allocator)!!; } else { @@ -133,7 +133,7 @@ fn Type List.get(List* list, usz index) fn void List.free(List* list) { if (!list.allocator) return; - list.allocator.free_aligned(list.entries)!!; + free_aligned(list.entries, .using = list.allocator); list.capacity = 0; list.size = 0; list.entries = null; @@ -153,7 +153,7 @@ fn void List.reserve(List* list, usz min_capacity) if (list.capacity >= min_capacity) return; if (!list.allocator) list.allocator = mem::temp_allocator(); min_capacity = math::next_power_of_2(min_capacity); - list.entries = list.allocator.realloc_aligned(list.entries, Type.sizeof * min_capacity, Type[1].alignof) ?? null; + list.entries = realloc_aligned(list.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = list.allocator) ?? null; list.capacity = min_capacity; } diff --git a/lib/std/collections/map.c3 b/lib/std/collections/map.c3 index dd35c8b91..5871a333c 100644 --- a/lib/std/collections/map.c3 +++ b/lib/std/collections/map.c3 @@ -28,7 +28,7 @@ fn void HashMap.init(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, flo map.allocator = allocator; map.load_factor = load_factor; map.threshold = (uint)(capacity * load_factor); - map.table = array::make(Entry*, capacity, allocator); + map.table = calloc(Entry*, capacity, .using = allocator); } /** @@ -168,7 +168,7 @@ fn Key[] HashMap.key_list(HashMap* map, Allocator* allocator = mem::current_allo { if (!map.count) return Key[] {}; - Key[] list = array::make(Key, map.count, allocator); + Key[] list = calloc(Key, map.count, .using = allocator); usz index = 0; foreach (Entry* entry : map.table) { @@ -189,7 +189,7 @@ fn Value[] HashMap.value_tlist(HashMap* map) fn Value[] HashMap.value_list(HashMap* map, Allocator* allocator = mem::current_allocator()) { if (!map.count) return Value[] {}; - Value[] list = array::make(Value, map.count, allocator); + Value[] list = calloc(Value, map.count, .using = allocator); usz index = 0; foreach (Entry* entry : map.table) { @@ -222,7 +222,7 @@ $endif; fn void HashMap.add_entry(HashMap* map, uint hash, Key key, Value value, uint bucket_index) @private { - Entry* entry = map.allocator.alloc(Entry.sizeof)!!; + Entry* entry = malloc(Entry, .using = map.allocator); *entry = { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] }; map.table[bucket_index] = entry; if (map.count++ >= map.threshold) @@ -240,7 +240,7 @@ fn void HashMap.resize(HashMap* map, uint new_capacity) @private map.threshold = uint.max; return; } - Entry*[] new_table = array::make(Entry*, new_capacity, map.allocator); + Entry*[] new_table = calloc(Entry*, new_capacity, .using = map.allocator); map.transfer(new_table); map.table = new_table; map.free_internal(old_table.ptr); @@ -339,7 +339,7 @@ fn bool HashMap.remove_entry_for_key(HashMap* map, Key key) @private fn void HashMap.create_entry(HashMap* map, uint hash, Key key, Value value, int bucket_index) @private { Entry *e = map.table[bucket_index]; - Entry* entry = map.allocator.alloc(Entry.sizeof)!!; + Entry* entry = malloc(Entry, .using = map.allocator); *entry = { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] }; map.table[bucket_index] = entry; map.count++; diff --git a/lib/std/core/allocators/arena_allocator.c3 b/lib/std/core/allocators/arena_allocator.c3 index 86fbc7557..f4a5fe080 100644 --- a/lib/std/core/allocators/arena_allocator.c3 +++ b/lib/std/core/allocators/arena_allocator.c3 @@ -52,7 +52,7 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz if (!size) return null; alignment = alignment_for_allocation(alignment); void* mem = arena._alloc(size, alignment, offset)?; - if (clear) mem::clear(mem, size, DEFAULT_MEM_ALIGNMENT); + if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); return mem; case ALIGNED_REALLOC: case REALLOC: @@ -84,8 +84,8 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz * @require alignment > 0 `alignment must be non zero` * @require math::is_power_of_2(alignment) * @require size > 0 - * @require alignment <= MAX_MEMORY_ALIGNMENT `alignment too big` - * @require offset <= MAX_MEMORY_ALIGNMENT `offset too big` + * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` + * @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big` * @require offset <= size && offset >= 0 * @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset * @require this != null @@ -110,8 +110,8 @@ fn void*! ArenaAllocator._alloc(ArenaAllocator* this, usz size, usz alignment, u * @require alignment > 0 `alignment must be non zero` * @require math::is_power_of_2(alignment) * @require size > 0 - * @require alignment <= MAX_MEMORY_ALIGNMENT `alignment too big` - * @require offset <= MAX_MEMORY_ALIGNMENT `offset too big` + * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` + * @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big` * @require offset <= size && offset >= 0 * @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset * @require this != null @@ -141,6 +141,6 @@ fn void*! ArenaAllocator._realloc(ArenaAllocator* this, void *old_pointer, usz s } // Otherwise just allocate new memory. void* mem = this._alloc(size, alignment, offset)?; - mem::copy(mem, old_pointer, old_size, DEFAULT_MEM_ALIGNMENT, DEFAULT_MEM_ALIGNMENT); + mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return mem; } \ No newline at end of file diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index faa1153ff..56e02b222 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -31,14 +31,14 @@ fn void DynamicArenaAllocator.destroy(DynamicArenaAllocator* this) while (page) { DynamicArenaPage* next_page = page.prev_arena; - this.backing_allocator.free(page)!!; + free(page, .using = this.backing_allocator); page = next_page; } page = this.unused_page; while (page) { DynamicArenaPage* next_page = page.prev_arena; - this.backing_allocator.free(page)!!; + free(page, .using = this.backing_allocator); page = next_page; } this.page = null; @@ -103,7 +103,7 @@ fn void*! DynamicArenaAllocator._realloc(DynamicArenaAllocator* this, void* old_ return old_pointer; } void* new_mem = this._alloc(size, alignment, offset)?; - mem::copy(new_mem, old_pointer, old_size, DEFAULT_MEM_ALIGNMENT); + mem::copy(new_mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT); return new_mem; } @@ -134,10 +134,10 @@ fn void*! DynamicArenaAllocator._alloc_new(DynamicArenaAllocator* this, usz size // Grab the page without alignment (we do it ourselves) void* mem = this.backing_allocator.alloc(page_size)?; - DynamicArenaPage*! page = this.backing_allocator.alloc(DynamicArenaPage.sizeof); + DynamicArenaPage*! page = malloc(DynamicArenaPage, .using = this.backing_allocator); if (catch err = page) { - this.backing_allocator.free(mem)?; + free(mem, .using = this.backing_allocator); return err!; } page.memory = mem; @@ -210,7 +210,7 @@ fn void*! dynamic_arena_allocator_function(Allocator* data, usz size, usz alignm assert(!old_pointer, "Unexpected no old pointer for calloc."); if (!size) return null; void* mem = allocator._alloc(size, alignment, offset)?; - mem::clear(mem, size, DEFAULT_MEM_ALIGNMENT); + mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); return mem; case ALLOC: case ALIGNED_ALLOC: diff --git a/lib/std/core/allocators/heap_allocator.c3 b/lib/std/core/allocators/heap_allocator.c3 index b3a90256a..099cdbb7f 100644 --- a/lib/std/core/allocators/heap_allocator.c3 +++ b/lib/std/core/allocators/heap_allocator.c3 @@ -77,13 +77,13 @@ fn void*! SimpleHeapAllocator._realloc(SimpleHeapAllocator* this, void* old_poin fn void*! SimpleHeapAllocator._calloc(SimpleHeapAllocator* this, usz bytes) @local { void* data = this._alloc(bytes)?; - mem::clear(data, bytes, DEFAULT_MEM_ALIGNMENT); + mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT); return data; } fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @local { - usz aligned_bytes = mem::aligned_offset(bytes, DEFAULT_MEM_ALIGNMENT); + usz aligned_bytes = mem::aligned_offset(bytes, mem::DEFAULT_MEM_ALIGNMENT); if (!this.free_list) { this.add_block(aligned_bytes)?; @@ -132,7 +132,7 @@ fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @loca fn void! SimpleHeapAllocator.add_block(SimpleHeapAllocator* this, usz aligned_bytes) @local { - assert(mem::aligned_offset(aligned_bytes, DEFAULT_MEM_ALIGNMENT) == aligned_bytes); + assert(mem::aligned_offset(aligned_bytes, mem::DEFAULT_MEM_ALIGNMENT) == aligned_bytes); char[] result = this.alloc_fn(aligned_bytes + Header.sizeof)?; Header* new_block = (Header*)result.ptr; new_block.size = result.len - Header.sizeof; diff --git a/lib/std/core/allocators/mem_allocator_fn.c3 b/lib/std/core/allocators/mem_allocator_fn.c3 index be36cfd40..bfc0f380c 100644 --- a/lib/std/core/allocators/mem_allocator_fn.c3 +++ b/lib/std/core/allocators/mem_allocator_fn.c3 @@ -73,7 +73,7 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes AlignedBlock* desc = (AlignedBlock*)old_pointer - 1; void* data_start = desc.start; void* new_data = @aligned_calloc(#calloc_fn, bytes, alignment, offset)?; - mem::copy(new_data, old_pointer, desc.len > bytes ? desc.len : bytes, DEFAULT_MEM_ALIGNMENT, DEFAULT_MEM_ALIGNMENT); + mem::copy(new_data, old_pointer, desc.len > bytes ? desc.len : bytes, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); $if ($checks(#free_fn(data_start)?)): #free_fn(data_start)?; $else: @@ -94,7 +94,7 @@ macro void! @aligned_free(#free_fn, void* old_pointer) fn void*! libc_allocator_fn(Allocator* unused, usz bytes, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @inline { - if (!alignment) alignment = DEFAULT_MEM_ALIGNMENT; + if (!alignment) alignment = mem::DEFAULT_MEM_ALIGNMENT; assert(math::is_power_of_2(alignment), "Alignment was not a power of 2"); void* data; diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index 702c95661..81579b036 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -39,7 +39,7 @@ macro bool TempAllocatorPage.is_aligned(TempAllocatorPage* page) => page.size & **/ fn TempAllocator*! new_temp(usz size, Allocator* backing_allocator) { - TempAllocator* allocator = backing_allocator.alloc(size + TempAllocator.sizeof)?; + TempAllocator* allocator = malloc_checked(TempAllocator, .using = backing_allocator, .end_padding = size)?; allocator.last_page = null; allocator.function = &temp_allocator_function; allocator.backing_allocator = backing_allocator; @@ -132,7 +132,7 @@ fn void*! TempAllocator._realloc_page(TempAllocator* this, TempAllocatorPage* pa usz page_size = page.pagesize(); // Clear on size > original size. void* data = this._alloc(size, alignment, offset, false)?; - mem::copy(data, &page.data[0], page_size, DEFAULT_MEM_ALIGNMENT, DEFAULT_MEM_ALIGNMENT); + mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); if (page.is_aligned()) { this.backing_allocator.free_aligned(real_pointer)?; @@ -159,7 +159,7 @@ fn void*! TempAllocator._realloc(TempAllocator* this, void* pointer, usz size, u // TODO optimize last allocation TempAllocatorChunk* data = this._alloc(size, alignment, offset, size > chunk.size)?; - mem::copy(data, pointer, chunk.size, DEFAULT_MEM_ALIGNMENT, DEFAULT_MEM_ALIGNMENT); + mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return data; } @@ -167,7 +167,7 @@ fn void*! TempAllocator._realloc(TempAllocator* this, void* pointer, usz size, u /** * @require math::is_power_of_2(alignment) * @require size > 0 - * @require alignment <= MAX_MEMORY_ALIGNMENT `alignment too big` + * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require this != null **/ fn void*! TempAllocator._alloc(TempAllocator* this, usz size, usz alignment, usz offset, bool clear) @local @@ -188,7 +188,7 @@ fn void*! TempAllocator._alloc(TempAllocator* this, usz size, usz alignment, usz TempAllocatorChunk* chunk_start = mem - TempAllocatorChunk.sizeof; chunk_start.size = size; this.used = new_usage; - if (clear) mem::clear(mem, size, DEFAULT_MEM_ALIGNMENT); + if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); return mem; } @@ -196,7 +196,7 @@ fn void*! TempAllocator._alloc(TempAllocator* this, usz size, usz alignment, usz TempAllocatorPage* page; // We have something we need to align. - if (alignment > DEFAULT_MEM_ALIGNMENT || offset) + if (alignment > mem::DEFAULT_MEM_ALIGNMENT || offset) { // This is actually simpler, since it will create the offset for us. usz total_alloc_size = TempAllocatorPage.sizeof + size; @@ -214,14 +214,14 @@ fn void*! TempAllocator._alloc(TempAllocator* this, usz size, usz alignment, usz else { // Here we might need to pad - usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, DEFAULT_MEM_ALIGNMENT); + usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT); usz total_alloc_size = padded_header_size + size; void* alloc = (clear ? this.backing_allocator.calloc(total_alloc_size) : this.backing_allocator.alloc(total_alloc_size))?; // Find the page. page = alloc + padded_header_size - TempAllocatorPage.sizeof; assert(mem::ptr_is_aligned(page, TempAllocator.alignof)); - assert(mem::ptr_is_aligned(&page.data[0], DEFAULT_MEM_ALIGNMENT)); + assert(mem::ptr_is_aligned(&page.data[0], mem::DEFAULT_MEM_ALIGNMENT)); page.start = alloc; page.size = size; } diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 57c638947..18b49a006 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -3,6 +3,10 @@ // a copy of which can be found in the LICENSE_STDLIB file. module std::core::mem; +const MAX_MEMORY_ALIGNMENT = 0x1000_0000; +const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2; + + macro @volatile_load(&x) @builtin { return $$volatile_load(&x); @@ -183,80 +187,136 @@ macro @tclone(&value) @builtin return x; } -fn void* malloc(usz size) @builtin @inline +macro type_alloc_must_be_aligned($Type) { - return thread_allocator.alloc(size)!!; + return $Type.alignof > DEFAULT_MEM_ALIGNMENT; +} +/** + * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" + * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" + **/ +macro malloc(..., Allocator* using = mem::thread_allocator, usz end_padding = 0) @builtin +{ + return malloc_checked($vasplat(), .using = using, .end_padding = end_padding)!!; } -fn void*! malloc_checked(usz size) @builtin @inline +/** + * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" + * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" + **/ +macro malloc_checked(..., Allocator* using = mem::thread_allocator, usz end_padding = 0) @builtin { - return thread_allocator.alloc(size); + $if ($checks($vatype(0).sizeof)): + var $Type = $vatype(0); + $assert(!type_alloc_must_be_aligned($vatype(0)), "Type must be allocated with malloc_aligned"); + $if ($vacount == 2): + usz size = $vaarg(1); + return (($Type*)using.alloc($Type.sizeof * size + end_padding))[:size]; + $else: + return ($Type*)using.alloc($Type.sizeof + end_padding); + $endif; + $else: + return using.alloc($vaarg(0) + end_padding); + $endif; +} + + +/** + * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" + * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" + * @require alignment && math::is_power_of_2(alignment) + **/ +macro malloc_aligned(..., usz alignment = 0, usz end_padding = 0, Allocator* using = mem::thread_allocator) @builtin +{ + $if ($checks($vatype(0).sizeof)): + var $Type = $vatype(0); + $if ($vacount == 2): + usz size = $vaarg(1); + return (($Type*)using.alloc_aligned($Type.sizeof * size + end_padding, alignment))[:size]; + $else: + return ($Type*)using.alloc_aligned($Type.sizeof + end_padding, alignment); + $endif; + $else: + return using.alloc_aligned($vaarg(0) + end_padding, alignment); + $endif; +} + +macro alloc($Type) @deprecated => malloc($Type); + +macro char[] alloc_bytes(usz bytes) @deprecated => malloc(char, bytes); + +/** + * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" + * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" + **/ +macro calloc(..., Allocator* using = mem::thread_allocator, usz end_padding = 0) @builtin +{ + return calloc_checked($vasplat(), .using = using, .end_padding = end_padding)!!; +} + +/** + * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" + * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" + **/ +macro calloc_checked(..., Allocator* using = mem::thread_allocator, usz end_padding = 0) @builtin +{ + $if ($checks($vatype(0).sizeof)): + var $Type = $vatype(0); + $assert(!type_alloc_must_be_aligned($vatype(0)), "Type must be allocated with calloc_aligned"); + $if ($vacount == 2): + usz size = $vaarg(1); + return (($Type*)using.calloc($Type.sizeof * size + end_padding))[:size]; + $else: + return ($Type*)using.calloc($Type.sizeof + end_padding); + $endif; + $else: + return using.calloc($vaarg(0) + end_padding); + $endif; +} + + +/** + * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" + * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" + * @require alignment && math::is_power_of_2(alignment) + **/ +macro calloc_aligned(..., usz alignment = 0, Allocator* using = mem::thread_allocator, usz end_padding = 0) @builtin +{ + $if ($checks($vatype(0).sizeof)): + var $Type = $vatype(0); + $if ($vacount == 2): + usz size = $vaarg(1); + return (($Type*)using.calloc_aligned($Type.sizeof * size + end_padding, alignment))[:size]; + $else: + return ($Type*)using.calloc_aligned($Type.sizeof + end_padding, alignment); + $endif; + $else: + return using.calloc_aligned($vaarg(0) + end_padding, alignment); + $endif; +} + +fn void* realloc(void *ptr, usz new_size, Allocator* using = mem::thread_allocator) @builtin @inline +{ + return using.realloc(ptr, new_size)!!; +} + +fn void*! realloc_checked(void *ptr, usz new_size, Allocator* using = mem::thread_allocator) @builtin @inline +{ + return using.realloc(ptr, new_size); } /** * @require alignment && math::is_power_of_2(alignment) */ -fn void*! malloc_aligned(usz size, usz alignment) @builtin @inline +fn void*! realloc_aligned(void *ptr, usz new_size, usz alignment, Allocator* using = mem::thread_allocator) @builtin @inline { - return thread_allocator.alloc_aligned(size, alignment); + return using.realloc_aligned(ptr, new_size, alignment); } -fn char[] alloc_bytes(usz bytes) @inline -{ - return ((char*)thread_allocator.alloc(bytes))[:bytes]!!; -} - -macro alloc($Type) -{ - return ($Type*)thread_allocator.alloc($Type.sizeof)!!; -} - - -fn void* calloc(usz size) @builtin @inline -{ - return thread_allocator.calloc(size)!!; -} - -fn void*! calloc_checked(usz size) @builtin @inline -{ - return thread_allocator.calloc(size); -} - -/** - * @require alignment && math::is_power_of_2(alignment) - */ -fn void*! calloc_aligned(usz size, usz alignment) @builtin @inline -{ - return thread_allocator.calloc_aligned(size, alignment); -} - -fn void* realloc(void *ptr, usz new_size) @builtin @inline -{ - return thread_allocator.realloc(ptr, new_size)!!; -} - -fn void*! realloc_checked(void *ptr, usz new_size) @builtin @inline -{ - return thread_allocator.realloc(ptr, new_size); -} - -/** - * @require alignment && math::is_power_of_2(alignment) - */ -fn void*! realloc_aligned(void *ptr, usz new_size, usz alignment) @builtin @inline -{ - return thread_allocator.realloc_aligned(ptr, new_size, alignment); -} - -fn void free(void* ptr) @builtin @inline -{ - return thread_allocator.free(ptr)!!; -} - -fn void free_aligned(void* ptr) @builtin @inline -{ - return thread_allocator.free_aligned(ptr)!!; -} +macro void free(void* ptr, Allocator* using = mem::thread_allocator) @builtin => using.free(ptr)!!; +macro void! free_checked(void* ptr, Allocator* using = mem::thread_allocator) @builtin => using.free(ptr); +macro void free_aligned(void* ptr, Allocator* using = mem::thread_allocator) @builtin => using.free_aligned(ptr)!!; +macro void! free_aligned_checked(void* ptr, Allocator* using = mem::thread_allocator) @builtin => using.free_aligned(ptr); /** * Run with a specific allocator inside of the macro body. @@ -269,20 +329,44 @@ macro void @scoped(Allocator* allocator; @body()) @body(); } +macro talloc($Type) @builtin @deprecated => tmalloc($Type); -macro talloc($Type) @builtin +/** + * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" + * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" + **/ +macro tmalloc(..., usz end_padding = 0, usz alignment = DEFAULT_MEM_ALIGNMENT) @builtin { - return temp_allocator().alloc_aligned($Type.sizeof, $Type.alignof)!!; + $if ($checks($vatype(0).sizeof)): + var $Type = $vatype(0); + $if ($vacount == 2): + usz size = $vaarg(1); + return (($Type*)temp_allocator().alloc_aligned($Type.sizeof * size + end_padding, alignment))[:size]!!; + $else: + return ($Type*)temp_allocator().alloc_aligned($Type.sizeof + end_padding, alignment)!!; + $endif; + $else: + return temp_allocator().alloc_aligned($vaarg(0) + end_padding, alignment)!!; + $endif; } -fn void* tmalloc(usz size, usz alignment = allocator::DEFAULT_MEM_ALIGNMENT) @builtin @inline +/** + * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" + * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" + **/ +macro tcalloc(..., usz end_padding = 0, usz alignment = allocator::DEFAULT_MEM_ALIGNMENT) @builtin { - return temp_allocator().alloc_aligned(size, alignment)!!; -} - -fn void* tcalloc(usz size, usz alignment = allocator::DEFAULT_MEM_ALIGNMENT) @builtin @inline -{ - return temp_allocator().calloc_aligned(size, alignment)!!; + $if ($checks($vatype(0).sizeof)): + var $Type = $vatype(0); + $if ($vacount == 2): + usz size = $vaarg(1); + return (($Type*)temp_allocator().calloc_aligned($Type.sizeof * size + end_padding, alignment))[:size]!!; + $else: + return ($Type*)temp_allocator().calloc_aligned($Type.sizeof + end_padding, alignment)!!; + $endif; + $else: + return temp_allocator().calloc_aligned($vaarg(0) + end_padding, alignment)!!; + $endif; } fn void* trealloc(void* ptr, usz size, usz alignment = allocator::DEFAULT_MEM_ALIGNMENT) @builtin @inline diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index c8a0d3a31..87c789a90 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -1,7 +1,5 @@ module std::core::mem::allocator; -const MAX_MEMORY_ALIGNMENT = 0x1000_0000; -const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2; const DEFAULT_SIZE_PREFIX = usz.sizeof; const DEFAULT_SIZE_PREFIX_ALIGNMENT = usz.alignof; @@ -100,9 +98,9 @@ fn void Allocator.reset(Allocator* allocator, usz mark = 0) fn usz alignment_for_allocation(usz alignment) @inline @private { - if (alignment < DEFAULT_MEM_ALIGNMENT) + if (alignment < mem::DEFAULT_MEM_ALIGNMENT) { - alignment = DEFAULT_MEM_ALIGNMENT; + alignment = mem::DEFAULT_MEM_ALIGNMENT; } return alignment; } diff --git a/lib/std/core/mem_array.c3 b/lib/std/core/mem_array.c3 index 12c38de3e..25cd4d5d2 100644 --- a/lib/std/core/mem_array.c3 +++ b/lib/std/core/mem_array.c3 @@ -6,35 +6,25 @@ module std::core::mem::array; /** * @require usz.max / elements > $Type.sizeof **/ -macro alloc($Type, usz elements) -{ - $Type* ptr = malloc($Type.sizeof * elements); - return ptr[:elements]; -} +macro alloc($Type, usz elements) @deprecated => malloc($Type, elements); /** * @require usz.max / elements > $Type.sizeof **/ -macro talloc($Type, usz elements) +macro talloc($Type, usz elements) @deprecated => tmalloc($Type, elements); + +/** + * @require (usz.max / elements > $Type.sizeof) + **/ +macro make($Type, usz elements, Allocator* allocator = mem::current_allocator()) @deprecated { - $Type* ptr = tmalloc($Type.sizeof * elements, $Type[1].alignof); - return ptr[:elements]; + return calloc($Type, elements, .using = allocator); } /** * @require (usz.max / elements > $Type.sizeof) **/ -macro make($Type, usz elements, Allocator* allocator = mem::current_allocator()) +macro tmake($Type, usz elements) @deprecated { - $Type* ptr = allocator.calloc($Type.sizeof * elements)!!; - return ptr[:elements]; -} - -/** - * @require (usz.max / elements > $Type.sizeof) - **/ -macro tmake($Type, usz elements) -{ - $Type* ptr = tcalloc($Type.sizeof * elements, $Type[1].alignof); - return ptr[:elements]; + return tcalloc($Type, elements); } diff --git a/lib/std/core/private/main_stub.c3 b/lib/std/core/private/main_stub.c3 index daf8fb29d..2359e6358 100644 --- a/lib/std/core/private/main_stub.c3 +++ b/lib/std/core/private/main_stub.c3 @@ -17,7 +17,7 @@ macro int @main_to_void_main(#m, int, char**) macro String[] args_to_strings(int argc, char** argv) @private { - String *list = malloc(String.sizeof * argc); + String *list = malloc(String, argc); for (int i = 0; i < argc; i++) { char* arg = argv[i]; @@ -63,7 +63,7 @@ macro String[] win_command_line_to_strings(ushort* cmd_line) @private macro String[] wargs_strings(int argc, Char16** argv) @private { - String *list = malloc(String.sizeof * argc); + String *list = malloc(String, argc); for (int i = 0; i < argc; i++) { Char16* arg = argv[i]; diff --git a/lib/std/core/str.c3 b/lib/std/core/str.c3 index 8582d9f6b..63a37ff6b 100644 --- a/lib/std/core/str.c3 +++ b/lib/std/core/str.c3 @@ -166,7 +166,7 @@ fn String[] split(String s, String needle, Allocator* allocator = mem::current_a { usz capacity = 16; usz i = 0; - String* holder = allocator.alloc(String.sizeof * capacity)!!; + String* holder = malloc(String, capacity, .using = allocator); while (s.len) { usz! index = index_of(s, needle); @@ -184,7 +184,7 @@ fn String[] split(String s, String needle, Allocator* allocator = mem::current_a if (i == capacity) { capacity *= 2; - holder = allocator.realloc(holder, String.sizeof * capacity)!!; + holder = realloc(holder, String.sizeof * capacity, .using = allocator); } holder[i++] = res; } @@ -251,7 +251,7 @@ fn String String.tcopyz(String s) => copyz(s, mem::temp_allocator()) @inline; fn ZString copy_zstring(String s, Allocator* allocator = mem::current_allocator()) { usz len = s.len; - char* str = allocator.alloc(len + 1)!!; + char* str = malloc(len + 1, .using = allocator); mem::copy(str, s.ptr, len); str[len] = 0; return (ZString)str; @@ -261,7 +261,7 @@ fn ZString copy_zstring(String s, Allocator* allocator = mem::current_allocator( fn String copyz(String s, Allocator* allocator = mem::current_allocator()) { usz len = s.len; - char* str = allocator.alloc(len + 1)!!; + char* str = malloc(len + 1, .using = allocator); mem::copy(str, s.ptr, len); str[len] = 0; return str[:len]; @@ -301,7 +301,7 @@ fn usz utf8_codepoints(String utf8) fn Char32[]! utf8to32(String utf8, Allocator* allocator = mem::current_allocator()) { usz codepoints = conv::utf8_codepoints(utf8); - Char32* data = allocator.alloc(Char32.sizeof * (codepoints + 1))?; + Char32* data = malloc_checked(Char32, codepoints + 1, .using = allocator)?; conv::utf8to32_unsafe(utf8, data)?; data[codepoints] = 0; return data[:codepoints]; @@ -310,7 +310,7 @@ fn Char32[]! utf8to32(String utf8, Allocator* allocator = mem::current_allocator fn String utf32to8(Char32[] utf32, Allocator* allocator = mem::current_allocator()) { usz len = conv::utf8len_for_utf32(utf32); - char* data = allocator.alloc(len + 1)!!; + char* data = malloc_checked(len + 1, .using = allocator)!!; conv::utf32to8_unsafe(utf32, data); data[len] = 0; return data[:len]; @@ -319,7 +319,7 @@ fn String utf32to8(Char32[] utf32, Allocator* allocator = mem::current_allocator fn Char16[]! utf8to16(String utf8, Allocator* allocator = mem::current_allocator()) { usz len16 = conv::utf16len_for_utf8(utf8); - Char16* data = allocator.alloc((len16 + 1) * Char16.sizeof)?; + Char16* data = malloc_checked(Char16, len16 + 1, .using = allocator)?; conv::utf8to16_unsafe(utf8, data)?; data[len16] = 0; return data[:len16]; @@ -329,7 +329,7 @@ fn Char16[]! utf8to16(String utf8, Allocator* allocator = mem::current_allocator fn String! utf16to8(Char16[] utf16, Allocator* allocator = mem::current_allocator()) { usz len = conv::utf8len_for_utf16(utf16); - char* data = allocator.alloc(len + 1)?; + char* data = malloc_checked(len + 1, .using = allocator)?; conv::utf16to8_unsafe(utf16, data)?; data[len] = 0; return data[:len]; diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index 0412ae6d7..a393161fe 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -13,7 +13,7 @@ const usz MIN_CAPACITY = 16; fn VarString new_with_capacity(usz capacity, Allocator* allocator = mem::current_allocator()) { if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY; - StringData* data = allocator.alloc(StringData.sizeof + capacity)!!; + StringData* data = malloc(StringData, 1, .using = allocator, .end_padding = capacity); data.allocator = allocator; data.len = 0; data.capacity = capacity; @@ -163,9 +163,9 @@ fn ZString VarString.copy_zstr(VarString* str, Allocator* allocator = mem::curre usz str_len = str.len(); if (!str_len) { - return (ZString)allocator.calloc(1)!!; + return (ZString)calloc(1, .using = allocator); } - char* zstr = allocator.alloc(str_len + 1)!!; + char* zstr = malloc(str_len + 1, .using = allocator); StringData* data = str.data(); mem::copy(zstr, &data.chars, str_len); zstr[str_len] = 0; @@ -200,7 +200,7 @@ fn void VarString.destroy(VarString* str) if (!*str) return; StringData* data = str.data(); if (!data) return; - data.allocator.free(data)!!; + free(data, .using = data.allocator); *str = (VarString)null; } @@ -307,7 +307,7 @@ fn void VarString.reserve(VarString* str, usz addition) @private if (data.capacity >= len) return; usz new_capacity = data.capacity *= 2; if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY; - *str = (VarString)data.allocator.realloc(data, StringData.sizeof + new_capacity)!!; + *str = (VarString)realloc(data, StringData.sizeof + new_capacity, .using = data.allocator); } fn VarString VarString.new_concat(VarString a, VarString b, Allocator* allocator = mem::current_allocator()) diff --git a/lib/std/io/io_stream.c3 b/lib/std/io/io_stream.c3 index 3fe383b26..98ee3d05c 100644 --- a/lib/std/io/io_stream.c3 +++ b/lib/std/io/io_stream.c3 @@ -173,12 +173,12 @@ $switch (env::MEMORY_ENV): $case NORMAL: @pool() { - return copy_through_buffer(s, dst, array::talloc(char, 4096)); + return copy_through_buffer(s, dst, tmalloc(char, 4096)); }; $case SMALL: @pool() { - return copy_through_buffer(s, dst, array::talloc(char, 1024)); + return copy_through_buffer(s, dst, tmalloc(char, 1024)); }; $case TINY: $case NONE: diff --git a/lib/std/io/stream/bytewriter.c3 b/lib/std/io/stream/bytewriter.c3 index ecb2ee59c..fe1c9d1c4 100644 --- a/lib/std/io/stream/bytewriter.c3 +++ b/lib/std/io/stream/bytewriter.c3 @@ -36,7 +36,7 @@ fn Stream ByteWriter.as_stream(ByteWriter* writer) fn void ByteWriter.destroy(ByteWriter* writer) { if (!writer.allocator) return; - if (void* ptr = writer.bytes.ptr) writer.allocator.free(ptr)!!; + if (void* ptr = writer.bytes.ptr) free(ptr, .using = writer.allocator); *writer = { }; } @@ -50,7 +50,7 @@ fn void! ByteWriter.ensure_capacity(ByteWriter* writer, usz len) @inline if (writer.bytes.len > len) return; if (len < 16) len = 16; usz new_capacity = math::next_power_of_2(len); - char* new_ptr = writer.allocator.realloc(writer.bytes.ptr, new_capacity)?; + char* new_ptr = realloc_checked(writer.bytes.ptr, new_capacity, .using = writer.allocator)?; writer.bytes = new_ptr[:new_capacity]; } diff --git a/lib/std/threads/os/thread_posix.c3 b/lib/std/threads/os/thread_posix.c3 index 1fa5fa25c..04af4c301 100644 --- a/lib/std/threads/os/thread_posix.c3 +++ b/lib/std/threads/os/thread_posix.c3 @@ -164,7 +164,7 @@ fn void* callback(void* arg) @private fn void! NativeThread.create(NativeThread* thread, ThreadFn thread_fn, void* arg) { - PosixThreadData *thread_data = mem::alloc(PosixThreadData); + PosixThreadData *thread_data = malloc(PosixThreadData); *thread_data = { .thread_fn = thread_fn, .arg = arg }; if (pthread_create(thread, null, &callback, thread_data) != 0) { diff --git a/resources/examples/contextfree/boolerr.c3 b/resources/examples/contextfree/boolerr.c3 index 8454a2efe..be4f56619 100644 --- a/resources/examples/contextfree/boolerr.c3 +++ b/resources/examples/contextfree/boolerr.c3 @@ -44,7 +44,7 @@ fn bool contains(String haystack, String needle) macro @dupe(value) { - $typeof(&value) temp = malloc_checked($sizeof(value))?; + $typeof(&value) temp = malloc_checked($typeof(value))?; *temp = value; return temp; } diff --git a/resources/testfragments/allocators_testing.c3 b/resources/testfragments/allocators_testing.c3 index bbfbc66b1..4259a9ca4 100644 --- a/resources/testfragments/allocators_testing.c3 +++ b/resources/testfragments/allocators_testing.c3 @@ -65,13 +65,13 @@ fn void main() }; mem::@tscoped() { - io::printf("Malloc: %p\n", malloc(23)); - io::printf("Malloc: %p\n", malloc(23)); + io::printf("Malloc: %p\n", (void*)malloc(23)); + io::printf("Malloc: %p\n", (void*)malloc(23)); }; - io::printf("Malloc: %p\n", malloc(23)); + io::printf("Malloc: %p\n", (void*)malloc(23)); @pool() { - io::printf("Talloc: %p\n", tmalloc(22)); + io::printf("Talloc: %p\n", (void*)tmalloc(22)); }; testAllocator(mem::temp_allocator(), 126); testAllocator(mem::temp_allocator(), 12600); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 99feae496..c1e31eaa9 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -679,6 +679,7 @@ typedef struct Decl_ bool is_export : 1; bool is_live : 1; bool no_strip : 1; + bool is_deprecated : 1; OperatorOverload operator : 4; union { @@ -1656,6 +1657,7 @@ typedef struct SemaContext_ CompilationUnit *compilation_unit; CallEnv call_env; Decl *current_macro; + SourceSpan inlining_span; ScopeId scope_id; unsigned macro_call_depth; Ast *break_target; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 995003843..842d30523 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -763,6 +763,7 @@ typedef enum ATTRIBUTE_BIGENDIAN, ATTRIBUTE_BUILTIN, ATTRIBUTE_CDECL, + ATTRIBUTE_DEPRECATED, ATTRIBUTE_EXPORT, ATTRIBUTE_EXTERN, ATTRIBUTE_EXTNAME, diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 3c460a2ce..88ac7d3db 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -118,7 +118,7 @@ static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *curr if (!name) return true; for (int i = 0; i < current_index; i++) { - if (name == decls[i]->name) + if (decls[i] && name == decls[i]->name) { SEMA_ERROR(current, "Duplicate parameter name '%s'.", name); SEMA_NOTE(decls[i], "Previous use of the name was here."); @@ -1484,6 +1484,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, [ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT, [ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC, [ATTRIBUTE_CDECL] = ATTR_FUNC, + [ATTRIBUTE_DEPRECATED] = USER_DEFINED_TYPES | ATTR_FUNC | ATTR_MACRO | ATTR_CONST | ATTR_GLOBAL | ATTR_MEMBER, [ATTRIBUTE_EXPORT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES, [ATTRIBUTE_NOSTRIP] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES, [ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER), @@ -1535,6 +1536,18 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, case ATTRIBUTE_LOCAL: // These are pseudo-attributes. UNREACHABLE; + case ATTRIBUTE_DEPRECATED: + if (expr) + { + if (!sema_analyse_expr(context, expr)) return false; + if (!expr_is_const_string(expr)) + { + SEMA_ERROR(expr, "Expected a constant string value as argument."); + return false; + } + } + decl->is_deprecated = true; + break; case ATTRIBUTE_WINMAIN: if (decl->name != kw_main) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index c7d95ed62..a18d0ebe4 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -995,7 +995,7 @@ static inline int sema_call_find_index_of_named_parameter(Decl **func_params, Ex const char *name = element->field; VECEACH(func_params, i) { - if (func_params[i]->name == name) return (int)i; + if (func_params[i] && func_params[i]->name == name) return (int)i; } SEMA_ERROR(expr, "There's no parameter with the name '%s'.", name); return -1; @@ -1791,6 +1791,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s macro_context.block_return_defer = macro_context.active_scope.defer_last; + macro_context.inlining_span = context->current_macro ? context->inlining_span : call_expr->span; macro_context.current_macro = decl; AstId body_id = call_expr->call_expr.body; macro_context.yield_body = body_id ? astptr(body_id) : NULL; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 22ccde9c2..76982f3a1 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1897,6 +1897,7 @@ static inline bool sema_analyse_then_overwrite(SemaContext *context, Ast *statem if (!sema_analyse_statement(context, ast)) return false; last = ast; } + last = ast_last(last); last->next = next; return true; } @@ -2496,9 +2497,22 @@ bool sema_analyse_ct_assert_stmt(SemaContext *context, Ast *statement) if (res == -1) return false; if (!res) { + if (context->current_macro) + { + if (message_expr) + { + sema_error_at(context->inlining_span, "%.*s", EXPAND_EXPR_STRING(message_expr)); + } + else + { + sema_error_at(context->inlining_span, "Compile time assert", EXPAND_EXPR_STRING(message_expr)); + } + sema_error_prev_at(expr->span, "$assert was defined here."); + return false; + } if (message_expr) { - SEMA_ERROR(expr, "Compile time assert - %.*s", EXPAND_EXPR_STRING(message_expr)); + SEMA_ERROR(expr, "%.*s", EXPAND_EXPR_STRING(message_expr)); } else { diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index aae505d05..d92f4f3e3 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -298,6 +298,7 @@ void symtab_init(uint32_t capacity) attribute_list[ATTRIBUTE_BIGENDIAN] = KW_DEF("@bigendian"); attribute_list[ATTRIBUTE_BUILTIN] = KW_DEF("@builtin"); attribute_list[ATTRIBUTE_CDECL] = KW_DEF("@cdecl"); + attribute_list[ATTRIBUTE_DEPRECATED] = KW_DEF("@deprecated"); attribute_list[ATTRIBUTE_EXPORT] = KW_DEF("@export"); attribute_list[ATTRIBUTE_EXTERN] = KW_DEF("@extern"); attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("@extname"); diff --git a/src/version.h b/src/version.h index 21ca51db4..384c24bf0 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.84" \ No newline at end of file +#define COMPILER_VERSION "0.4.86" \ No newline at end of file diff --git a/test/test_suite/assert/static_assert.c3 b/test/test_suite/assert/static_assert.c3 index a49691433..a60e79eaa 100644 --- a/test/test_suite/assert/static_assert.c3 +++ b/test/test_suite/assert/static_assert.c3 @@ -4,5 +4,5 @@ const int FOO = 2; fn void test() { $assert(FOO == 2, "Bad"); - $assert(FOO == 0, "Good"); // #error: Compile time assert - Good + $assert(FOO == 0, "Good"); // #error: Good } \ No newline at end of file diff --git a/test/test_suite/errors/error_regression_2.c3t b/test/test_suite/errors/error_regression_2.c3t index 0ad5bc8af..caa7dfa60 100644 --- a/test/test_suite/errors/error_regression_2.c3t +++ b/test/test_suite/errors/error_regression_2.c3t @@ -168,7 +168,7 @@ cond.rhs: ; preds = %entry br label %cond.phi cond.phi: ; preds = %cond.rhs, %cond.lhs - %val = phi %"char[]" [ %6, %cond.lhs ], [ { ptr @.str.28, i64 7 }, %cond.rhs ] + %val = phi %"char[]" [ %6, %cond.lhs ], [ { ptr @.str.43, i64 7 }, %cond.rhs ] store %"char[]" %val, ptr %title, align 8 %7 = getelementptr inbounds %"char[]", ptr %title, i32 0, i32 1 %8 = load i64, ptr %7, align 8 @@ -178,8 +178,8 @@ cond.phi: ; preds = %cond.rhs, %cond.lhs %11 = getelementptr inbounds %Summary, ptr %0, i32 0, i32 1 %12 = load i8, ptr %11, align 8 %13 = trunc i8 %12 to i1 - %ternary = select i1 %13, ptr @.str.30, ptr @.str.31 - %14 = call i32 (ptr, ptr, ...) @fprintf(ptr %1, ptr @.str.29, i32 %uisitrunc, ptr %10, ptr %ternary) + %ternary = select i1 %13, ptr @.str.45, ptr @.str.46 + %14 = call i32 (ptr, ptr, ...) @fprintf(ptr %1, ptr @.str.44, i32 %uisitrunc, ptr %10, ptr %ternary) ret void } @@ -271,26 +271,74 @@ entry: %value = alloca %Head, align 8 %literal10 = alloca %Head, align 8 %temp = alloca ptr, align 8 - %reterr17 = alloca i64, align 8 - %literal18 = alloca %Doc, align 8 - %error_var19 = alloca i64, align 8 - %value20 = alloca %Head, align 8 - %literal21 = alloca %Head, align 8 - %error_var22 = alloca i64, align 8 - %value23 = alloca %"char[]", align 8 - %temp24 = alloca ptr, align 8 + %using = alloca ptr, align 8 + %end_padding = alloca i64, align 8 + %error_var12 = alloca i64, align 8 + %using13 = alloca ptr, align 8 + %end_padding14 = alloca i64, align 8 + %.anon = alloca i64, align 8 + %blockret15 = alloca ptr, align 8 + %retparam = alloca ptr, align 8 + %reterr23 = alloca i64, align 8 + %literal24 = alloca %Doc, align 8 + %error_var25 = alloca i64, align 8 + %value26 = alloca %Head, align 8 + %literal27 = alloca %Head, align 8 + %error_var28 = alloca i64, align 8 + %value29 = alloca %"char[]", align 8 %temp30 = alloca ptr, align 8 + %using31 = alloca ptr, align 8 + %end_padding32 = alloca i64, align 8 + %error_var34 = alloca i64, align 8 + %using35 = alloca ptr, align 8 + %end_padding36 = alloca i64, align 8 + %.anon37 = alloca i64, align 8 + %blockret38 = alloca ptr, align 8 + %retparam39 = alloca ptr, align 8 + %temp52 = alloca ptr, align 8 + %using53 = alloca ptr, align 8 + %end_padding54 = alloca i64, align 8 + %error_var56 = alloca i64, align 8 + %using57 = alloca ptr, align 8 + %end_padding58 = alloca i64, align 8 + %.anon59 = alloca i64, align 8 + %blockret60 = alloca ptr, align 8 + %retparam61 = alloca ptr, align 8 %len = alloca i32, align 4 %str = alloca ptr, align 8 - %reterr43 = alloca i64, align 8 - %literal44 = alloca %Doc, align 8 - %error_var45 = alloca i64, align 8 - %value46 = alloca %Head, align 8 - %literal47 = alloca %Head, align 8 - %error_var48 = alloca i64, align 8 - %value49 = alloca %"char[]", align 8 - %temp51 = alloca ptr, align 8 - %temp57 = alloca ptr, align 8 + %using75 = alloca ptr, align 8 + %end_padding76 = alloca i64, align 8 + %error_var77 = alloca i64, align 8 + %using78 = alloca ptr, align 8 + %end_padding79 = alloca i64, align 8 + %.anon80 = alloca i32, align 4 + %blockret82 = alloca ptr, align 8 + %retparam83 = alloca ptr, align 8 + %reterr97 = alloca i64, align 8 + %literal98 = alloca %Doc, align 8 + %error_var99 = alloca i64, align 8 + %value100 = alloca %Head, align 8 + %literal101 = alloca %Head, align 8 + %error_var102 = alloca i64, align 8 + %value103 = alloca %"char[]", align 8 + %temp105 = alloca ptr, align 8 + %using106 = alloca ptr, align 8 + %end_padding107 = alloca i64, align 8 + %error_var109 = alloca i64, align 8 + %using110 = alloca ptr, align 8 + %end_padding111 = alloca i64, align 8 + %.anon112 = alloca i64, align 8 + %blockret113 = alloca ptr, align 8 + %retparam114 = alloca ptr, align 8 + %temp127 = alloca ptr, align 8 + %using128 = alloca ptr, align 8 + %end_padding129 = alloca i64, align 8 + %error_var131 = alloca i64, align 8 + %using132 = alloca ptr, align 8 + %end_padding133 = alloca i64, align 8 + %.anon134 = alloca i64, align 8 + %blockret135 = alloca ptr, align 8 + %retparam136 = alloca ptr, align 8 store ptr %1, ptr %url, align 8 %ptroffset = getelementptr inbounds i64, ptr %url, i64 1 store i64 %2, ptr %ptroffset, align 8 @@ -327,190 +375,400 @@ if.exit4: ; preds = %if.exit %hi6 = load i64, ptr %13, align 8 %14 = call i8 @test.contains(ptr %lo5, i64 %hi6, ptr @.str.4, i64 13) %15 = trunc i8 %14 to i1 - br i1 %15, label %if.then7, label %if.exit13 + br i1 %15, label %if.then7, label %if.exit19 if.then7: ; preds = %if.exit4 %16 = getelementptr inbounds %Doc, ptr %literal9, i32 0, i32 0 %17 = getelementptr inbounds %Head, ptr %literal10, i32 0, i32 0 store ptr null, ptr %17, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value, ptr align 8 %literal10, i32 8, i1 false) - %18 = call ptr @std.core.mem.malloc(i64 8) #3 - store ptr %18, ptr %temp, align 8 - %19 = load ptr, ptr %temp, align 8 - %not = icmp eq ptr %19, null - br i1 %not, label %if.then11, label %if.exit12 + %18 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %18, ptr %using, align 8 + store i64 0, ptr %end_padding, align 8 + %19 = load ptr, ptr %using, align 8 + store ptr %19, ptr %using13, align 8 + %20 = load i64, ptr %end_padding, align 8 + store i64 %20, ptr %end_padding14, align 8 + store i64 8, ptr %.anon, align 8 + %21 = load ptr, ptr %using13, align 8 + %22 = load i64, ptr %.anon, align 8 + %23 = load i64, ptr %end_padding14, align 8 + %add = add i64 %22, %23 + %24 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam, ptr %21, i64 %add) #3 + %not_err = icmp eq i64 %24, 0 + %25 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %25, label %after_check, label %assign_optional -if.then11: ; preds = %if.then7 +assign_optional: ; preds = %if.then7 + store i64 %24, ptr %error_var12, align 8 + br label %panic_block + +after_check: ; preds = %if.then7 + %26 = load ptr, ptr %retparam, align 8 + store ptr %26, ptr %blockret15, align 8 + br label %expr_block.exit + +expr_block.exit: ; preds = %after_check + %27 = load ptr, ptr %blockret15, align 8 + br label %noerr_block + +panic_block: ; preds = %assign_optional + %28 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %28(ptr @.panic_msg, i64 27, ptr @.file, i64 6, ptr @.func + unreachable + +noerr_block: ; preds = %expr_block.exit + store ptr %27, ptr %temp, align 8 + %29 = load ptr, ptr %temp, align 8 + %not = icmp eq ptr %29, null + br i1 %not, label %if.then16, label %if.exit17 + +if.then16: ; preds = %noerr_block store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var, align 8 br label %guard_block -if.exit12: ; preds = %if.then7 - %20 = load ptr, ptr %temp, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %20, ptr align 8 %value, i32 8, i1 false) - br label %noerr_block +if.exit17: ; preds = %noerr_block + %30 = load ptr, ptr %temp, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %30, ptr align 8 %value, i32 8, i1 false) + br label %noerr_block18 -guard_block: ; preds = %if.then11 - %21 = load i64, ptr %error_var, align 8 - ret i64 %21 +guard_block: ; preds = %if.then16 + %31 = load i64, ptr %error_var, align 8 + ret i64 %31 -noerr_block: ; preds = %if.exit12 - %22 = load ptr, ptr %temp, align 8 - store ptr %22, ptr %16, align 8 +noerr_block18: ; preds = %if.exit17 + %32 = load ptr, ptr %temp, align 8 + store ptr %32, ptr %16, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal9, i32 8, i1 false) ret i64 0 -if.exit13: ; preds = %if.exit4 - %23 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %lo14 = load ptr, ptr %23, align 8 - %24 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %hi15 = load i64, ptr %24, align 8 - %25 = call i8 @test.contains(ptr %lo14, i64 %hi15, ptr @.str.5, i64 11) - %26 = trunc i8 %25 to i1 - br i1 %26, label %if.then16, label %if.exit36 +if.exit19: ; preds = %if.exit4 + %33 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %lo20 = load ptr, ptr %33, align 8 + %34 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %hi21 = load i64, ptr %34, align 8 + %35 = call i8 @test.contains(ptr %lo20, i64 %hi21, ptr @.str.5, i64 11) + %36 = trunc i8 %35 to i1 + br i1 %36, label %if.then22, label %if.exit74 -if.then16: ; preds = %if.exit13 - %27 = getelementptr inbounds %Doc, ptr %literal18, i32 0, i32 0 - store ptr null, ptr %literal21, align 8 - %28 = getelementptr inbounds %Head, ptr %literal21, i32 0, i32 0 - store %"char[]" zeroinitializer, ptr %value23, align 8 - %29 = call ptr @std.core.mem.malloc(i64 16) #3 - store ptr %29, ptr %temp24, align 8 - %30 = load ptr, ptr %temp24, align 8 - %not25 = icmp eq ptr %30, null - br i1 %not25, label %if.then26, label %if.exit27 +if.then22: ; preds = %if.exit19 + %37 = getelementptr inbounds %Doc, ptr %literal24, i32 0, i32 0 + store ptr null, ptr %literal27, align 8 + %38 = getelementptr inbounds %Head, ptr %literal27, i32 0, i32 0 + store %"char[]" zeroinitializer, ptr %value29, align 8 + %39 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %39, ptr %using31, align 8 + store i64 0, ptr %end_padding32, align 8 + %40 = load ptr, ptr %using31, align 8 + store ptr %40, ptr %using35, align 8 + %41 = load i64, ptr %end_padding32, align 8 + store i64 %41, ptr %end_padding36, align 8 + store i64 16, ptr %.anon37, align 8 + %42 = load ptr, ptr %using35, align 8 + %43 = load i64, ptr %.anon37, align 8 + %44 = load i64, ptr %end_padding36, align 8 + %add40 = add i64 %43, %44 + %45 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam39, ptr %42, i64 %add40) #3 + %not_err41 = icmp eq i64 %45, 0 + %46 = call i1 @llvm.expect.i1(i1 %not_err41, i1 true) + br i1 %46, label %after_check43, label %assign_optional42 -if.then26: ; preds = %if.then16 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var22, align 8 - br label %guard_block28 +assign_optional42: ; preds = %if.then22 + store i64 %45, ptr %error_var34, align 8 + br label %panic_block45 -if.exit27: ; preds = %if.then16 - %31 = load ptr, ptr %temp24, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %31, ptr align 8 %value23, i32 16, i1 false) - br label %noerr_block29 +after_check43: ; preds = %if.then22 + %47 = load ptr, ptr %retparam39, align 8 + store ptr %47, ptr %blockret38, align 8 + br label %expr_block.exit44 -guard_block28: ; preds = %if.then26 - %32 = load i64, ptr %error_var22, align 8 - ret i64 %32 +expr_block.exit44: ; preds = %after_check43 + %48 = load ptr, ptr %blockret38, align 8 + br label %noerr_block46 -noerr_block29: ; preds = %if.exit27 - %33 = load ptr, ptr %temp24, align 8 - store ptr %33, ptr %28, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value20, ptr align 8 %literal21, i32 8, i1 false) - %34 = call ptr @std.core.mem.malloc(i64 8) #3 - store ptr %34, ptr %temp30, align 8 - %35 = load ptr, ptr %temp30, align 8 - %not31 = icmp eq ptr %35, null - br i1 %not31, label %if.then32, label %if.exit33 +panic_block45: ; preds = %assign_optional42 + %49 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %49(ptr @.panic_msg.7, i64 27, ptr @.file.8, i64 6, ptr @.func.9, i64 7 + unreachable -if.then32: ; preds = %noerr_block29 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var19, align 8 - br label %guard_block34 +noerr_block46: ; preds = %expr_block.exit44 + store ptr %48, ptr %temp30, align 8 + %50 = load ptr, ptr %temp30, align 8 + %not47 = icmp eq ptr %50, null + br i1 %not47, label %if.then48, label %if.exit49 -if.exit33: ; preds = %noerr_block29 - %36 = load ptr, ptr %temp30, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %36, ptr align 8 %value20, i32 8, i1 false) - br label %noerr_block35 +if.then48: ; preds = %noerr_block46 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var28, align 8 + br label %guard_block50 -guard_block34: ; preds = %if.then32 - %37 = load i64, ptr %error_var19, align 8 - ret i64 %37 +if.exit49: ; preds = %noerr_block46 + %51 = load ptr, ptr %temp30, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %51, ptr align 8 %value29, i32 16, i1 false) + br label %noerr_block51 -noerr_block35: ; preds = %if.exit33 - %38 = load ptr, ptr %temp30, align 8 - store ptr %38, ptr %27, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal18, i32 8, i1 false) +guard_block50: ; preds = %if.then48 + %52 = load i64, ptr %error_var28, align 8 + ret i64 %52 + +noerr_block51: ; preds = %if.exit49 + %53 = load ptr, ptr %temp30, align 8 + store ptr %53, ptr %38, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value26, ptr align 8 %literal27, i32 8, i1 false) + %54 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %54, ptr %using53, align 8 + store i64 0, ptr %end_padding54, align 8 + %55 = load ptr, ptr %using53, align 8 + store ptr %55, ptr %using57, align 8 + %56 = load i64, ptr %end_padding54, align 8 + store i64 %56, ptr %end_padding58, align 8 + store i64 8, ptr %.anon59, align 8 + %57 = load ptr, ptr %using57, align 8 + %58 = load i64, ptr %.anon59, align 8 + %59 = load i64, ptr %end_padding58, align 8 + %add62 = add i64 %58, %59 + %60 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam61, ptr %57, i64 %add62) #3 + %not_err63 = icmp eq i64 %60, 0 + %61 = call i1 @llvm.expect.i1(i1 %not_err63, i1 true) + br i1 %61, label %after_check65, label %assign_optional64 + +assign_optional64: ; preds = %noerr_block51 + store i64 %60, ptr %error_var56, align 8 + br label %panic_block67 + +after_check65: ; preds = %noerr_block51 + %62 = load ptr, ptr %retparam61, align 8 + store ptr %62, ptr %blockret60, align 8 + br label %expr_block.exit66 + +expr_block.exit66: ; preds = %after_check65 + %63 = load ptr, ptr %blockret60, align 8 + br label %noerr_block68 + +panic_block67: ; preds = %assign_optional64 + %64 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %64(ptr @.panic_msg.10, i64 27, ptr @.file.11, i64 6, ptr @.func.12, i64 7 + unreachable + +noerr_block68: ; preds = %expr_block.exit66 + store ptr %63, ptr %temp52, align 8 + %65 = load ptr, ptr %temp52, align 8 + %not69 = icmp eq ptr %65, null + br i1 %not69, label %if.then70, label %if.exit71 + +if.then70: ; preds = %noerr_block68 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var25, align 8 + br label %guard_block72 + +if.exit71: ; preds = %noerr_block68 + %66 = load ptr, ptr %temp52, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %66, ptr align 8 %value26, i32 8, i1 false) + br label %noerr_block73 + +guard_block72: ; preds = %if.then70 + %67 = load i64, ptr %error_var25, align 8 + ret i64 %67 + +noerr_block73: ; preds = %if.exit71 + %68 = load ptr, ptr %temp52, align 8 + store ptr %68, ptr %37, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal24, i32 8, i1 false) ret i64 0 -if.exit36: ; preds = %if.exit13 - %39 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %40 = load i64, ptr %39, align 8 - %uisitrunc = trunc i64 %40 to i32 - %41 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %42 = load ptr, ptr %41, align 8 - %43 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr null, i64 0, ptr @.str.7, i32 %uisitrunc, ptr %42) - store i32 %43, ptr %len, align 4 - %44 = load i32, ptr %len, align 4 - %siuiext = sext i32 %44 to i64 - %add = add i64 %siuiext, 1 - %45 = call ptr @std.core.mem.malloc(i64 %add) #3 - store ptr %45, ptr %str, align 8 - %46 = load ptr, ptr %str, align 8 - %not37 = icmp eq ptr %46, null - br i1 %not37, label %if.then38, label %if.exit39 +if.exit74: ; preds = %if.exit19 + %69 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %70 = load i64, ptr %69, align 8 + %uisitrunc = trunc i64 %70 to i32 + %71 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %72 = load ptr, ptr %71, align 8 + %73 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr null, i64 0, ptr @.str.13, i32 %uisitrunc, ptr %72) + store i32 %73, ptr %len, align 4 + %74 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %74, ptr %using75, align 8 + store i64 0, ptr %end_padding76, align 8 + %75 = load ptr, ptr %using75, align 8 + store ptr %75, ptr %using78, align 8 + %76 = load i64, ptr %end_padding76, align 8 + store i64 %76, ptr %end_padding79, align 8 + %77 = load i32, ptr %len, align 4 + %add81 = add i32 %77, 1 + store i32 %add81, ptr %.anon80, align 4 + %78 = load ptr, ptr %using78, align 8 + %79 = load i32, ptr %.anon80, align 4 + %siuiext = sext i32 %79 to i64 + %80 = load i64, ptr %end_padding79, align 8 + %add84 = add i64 %siuiext, %80 + %81 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam83, ptr %78, i64 %add84) #3 + %not_err85 = icmp eq i64 %81, 0 + %82 = call i1 @llvm.expect.i1(i1 %not_err85, i1 true) + br i1 %82, label %after_check87, label %assign_optional86 -if.then38: ; preds = %if.exit36 +assign_optional86: ; preds = %if.exit74 + store i64 %81, ptr %error_var77, align 8 + br label %panic_block89 + +after_check87: ; preds = %if.exit74 + %83 = load ptr, ptr %retparam83, align 8 + store ptr %83, ptr %blockret82, align 8 + br label %expr_block.exit88 + +expr_block.exit88: ; preds = %after_check87 + %84 = load ptr, ptr %blockret82, align 8 + br label %noerr_block90 + +panic_block89: ; preds = %assign_optional86 + %85 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %85(ptr @.panic_msg.14, i64 27, ptr @.file.15, i64 6, ptr @.func.16 + unreachable + +noerr_block90: ; preds = %expr_block.exit88 + store ptr %84, ptr %str, align 8 + %86 = load ptr, ptr %str, align 8 + %not91 = icmp eq ptr %86, null + br i1 %not91, label %if.then92, label %if.exit93 + +if.then92: ; preds = %noerr_block90 ret i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64) -if.exit39: ; preds = %if.exit36 - %47 = load ptr, ptr %str, align 8 - %48 = load i32, ptr %len, align 4 - %siuiext40 = sext i32 %48 to i64 - %add41 = add i64 %siuiext40, 1 - %49 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %50 = load i64, ptr %49, align 8 - %uisitrunc42 = trunc i64 %50 to i32 - %51 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %52 = load ptr, ptr %51, align 8 - %53 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %47, i64 %add41, ptr @.str.8, i32 %uisitrunc42, ptr %52) - %54 = getelementptr inbounds %Doc, ptr %literal44, i32 0, i32 0 - store ptr null, ptr %literal47, align 8 - %55 = getelementptr inbounds %Head, ptr %literal47, i32 0, i32 0 - %56 = load ptr, ptr %str, align 8 - %57 = load i32, ptr %len, align 4 - %sub = sub i32 %57, 1 +if.exit93: ; preds = %noerr_block90 + %87 = load ptr, ptr %str, align 8 + %88 = load i32, ptr %len, align 4 + %siuiext94 = sext i32 %88 to i64 + %add95 = add i64 %siuiext94, 1 + %89 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %90 = load i64, ptr %89, align 8 + %uisitrunc96 = trunc i64 %90 to i32 + %91 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %92 = load ptr, ptr %91, align 8 + %93 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %87, i64 %add95, ptr @.str.17, i32 %uisitrunc96, ptr %92) + %94 = getelementptr inbounds %Doc, ptr %literal98, i32 0, i32 0 + store ptr null, ptr %literal101, align 8 + %95 = getelementptr inbounds %Head, ptr %literal101, i32 0, i32 0 + %96 = load ptr, ptr %str, align 8 + %97 = load i32, ptr %len, align 4 + %sub = sub i32 %97, 1 %sisiext = sext i32 %sub to i64 - %58 = add i64 %sisiext, 1 - %size = sub i64 %58, 0 - %ptroffset50 = getelementptr inbounds i8, ptr %56, i64 0 - %59 = insertvalue %"char[]" undef, ptr %ptroffset50, 0 - %60 = insertvalue %"char[]" %59, i64 %size, 1 - store %"char[]" %60, ptr %value49, align 8 - %61 = call ptr @std.core.mem.malloc(i64 16) #3 - store ptr %61, ptr %temp51, align 8 - %62 = load ptr, ptr %temp51, align 8 - %not52 = icmp eq ptr %62, null - br i1 %not52, label %if.then53, label %if.exit54 + %98 = add i64 %sisiext, 1 + %size = sub i64 %98, 0 + %ptroffset104 = getelementptr inbounds i8, ptr %96, i64 0 + %99 = insertvalue %"char[]" undef, ptr %ptroffset104, 0 + %100 = insertvalue %"char[]" %99, i64 %size, 1 + store %"char[]" %100, ptr %value103, align 8 + %101 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %101, ptr %using106, align 8 + store i64 0, ptr %end_padding107, align 8 + %102 = load ptr, ptr %using106, align 8 + store ptr %102, ptr %using110, align 8 + %103 = load i64, ptr %end_padding107, align 8 + store i64 %103, ptr %end_padding111, align 8 + store i64 16, ptr %.anon112, align 8 + %104 = load ptr, ptr %using110, align 8 + %105 = load i64, ptr %.anon112, align 8 + %106 = load i64, ptr %end_padding111, align 8 + %add115 = add i64 %105, %106 + %107 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam114, ptr %104, i64 %add115) #3 + %not_err116 = icmp eq i64 %107, 0 + %108 = call i1 @llvm.expect.i1(i1 %not_err116, i1 true) + br i1 %108, label %after_check118, label %assign_optional117 -if.then53: ; preds = %if.exit39 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var48, align 8 - br label %guard_block55 +assign_optional117: ; preds = %if.exit93 + store i64 %107, ptr %error_var109, align 8 + br label %panic_block120 -if.exit54: ; preds = %if.exit39 - %63 = load ptr, ptr %temp51, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %63, ptr align 8 %value49, i32 16, i1 false) - br label %noerr_block56 +after_check118: ; preds = %if.exit93 + %109 = load ptr, ptr %retparam114, align 8 + store ptr %109, ptr %blockret113, align 8 + br label %expr_block.exit119 -guard_block55: ; preds = %if.then53 - %64 = load i64, ptr %error_var48, align 8 - ret i64 %64 +expr_block.exit119: ; preds = %after_check118 + %110 = load ptr, ptr %blockret113, align 8 + br label %noerr_block121 -noerr_block56: ; preds = %if.exit54 - %65 = load ptr, ptr %temp51, align 8 - store ptr %65, ptr %55, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value46, ptr align 8 %literal47, i32 8, i1 false) - %66 = call ptr @std.core.mem.malloc(i64 8) #3 - store ptr %66, ptr %temp57, align 8 - %67 = load ptr, ptr %temp57, align 8 - %not58 = icmp eq ptr %67, null - br i1 %not58, label %if.then59, label %if.exit60 +panic_block120: ; preds = %assign_optional117 + %111 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %111(ptr @.panic_msg.18, i64 27, ptr @.file.19, i64 6, ptr @.func.20 + unreachable -if.then59: ; preds = %noerr_block56 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var45, align 8 - br label %guard_block61 +noerr_block121: ; preds = %expr_block.exit119 + store ptr %110, ptr %temp105, align 8 + %112 = load ptr, ptr %temp105, align 8 + %not122 = icmp eq ptr %112, null + br i1 %not122, label %if.then123, label %if.exit124 -if.exit60: ; preds = %noerr_block56 - %68 = load ptr, ptr %temp57, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %68, ptr align 8 %value46, i32 8, i1 false) - br label %noerr_block62 +if.then123: ; preds = %noerr_block121 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var102, align 8 + br label %guard_block125 -guard_block61: ; preds = %if.then59 - %69 = load i64, ptr %error_var45, align 8 - ret i64 %69 +if.exit124: ; preds = %noerr_block121 + %113 = load ptr, ptr %temp105, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %113, ptr align 8 %value103, i32 16, i1 false) + br label %noerr_block126 -noerr_block62: ; preds = %if.exit60 - %70 = load ptr, ptr %temp57, align 8 - store ptr %70, ptr %54, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal44, i32 8, i1 false) +guard_block125: ; preds = %if.then123 + %114 = load i64, ptr %error_var102, align 8 + ret i64 %114 + +noerr_block126: ; preds = %if.exit124 + %115 = load ptr, ptr %temp105, align 8 + store ptr %115, ptr %95, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value100, ptr align 8 %literal101, i32 8, i1 false) + %116 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %116, ptr %using128, align 8 + store i64 0, ptr %end_padding129, align 8 + %117 = load ptr, ptr %using128, align 8 + store ptr %117, ptr %using132, align 8 + %118 = load i64, ptr %end_padding129, align 8 + store i64 %118, ptr %end_padding133, align 8 + store i64 8, ptr %.anon134, align 8 + %119 = load ptr, ptr %using132, align 8 + %120 = load i64, ptr %.anon134, align 8 + %121 = load i64, ptr %end_padding133, align 8 + %add137 = add i64 %120, %121 + %122 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam136, ptr %119, i64 %add137) #3 + %not_err138 = icmp eq i64 %122, 0 + %123 = call i1 @llvm.expect.i1(i1 %not_err138, i1 true) + br i1 %123, label %after_check140, label %assign_optional139 + +assign_optional139: ; preds = %noerr_block126 + store i64 %122, ptr %error_var131, align 8 + br label %panic_block142 + +after_check140: ; preds = %noerr_block126 + %124 = load ptr, ptr %retparam136, align 8 + store ptr %124, ptr %blockret135, align 8 + br label %expr_block.exit141 + +expr_block.exit141: ; preds = %after_check140 + %125 = load ptr, ptr %blockret135, align 8 + br label %noerr_block143 + +panic_block142: ; preds = %assign_optional139 + %126 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %126(ptr @.panic_msg.21, i64 27, ptr @.file.22, i64 6, ptr @.func.23 + unreachable + +noerr_block143: ; preds = %expr_block.exit141 + store ptr %125, ptr %temp127, align 8 + %127 = load ptr, ptr %temp127, align 8 + %not144 = icmp eq ptr %127, null + br i1 %not144, label %if.then145, label %if.exit146 + +if.then145: ; preds = %noerr_block143 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var99, align 8 + br label %guard_block147 + +if.exit146: ; preds = %noerr_block143 + %128 = load ptr, ptr %temp127, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %128, ptr align 8 %value100, i32 8, i1 false) + br label %noerr_block148 + +guard_block147: ; preds = %if.then145 + %129 = load i64, ptr %error_var99, align 8 + ret i64 %129 + +noerr_block148: ; preds = %if.exit146 + %130 = load ptr, ptr %temp127, align 8 + store ptr %130, ptr %94, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal98, i32 8, i1 false) ret i64 0 } @@ -677,7 +935,7 @@ err_retblock: ; preds = %assign_optional3, % define ptr @test.bool_to_string(i8 zeroext %0) #0 { entry: %1 = trunc i8 %0 to i1 - %ternary = select i1 %1, %"char[]" { ptr @.str.9, i64 4 }, %"char[]" { ptr @.str.10, i64 5 } + %ternary = select i1 %1, %"char[]" { ptr @.str.24, i64 4 }, %"char[]" { ptr @.str.25, i64 5 } %2 = extractvalue %"char[]" %ternary, 0 ret ptr %2 } @@ -695,27 +953,27 @@ switch.entry: ; preds = %entry br i1 %eq, label %switch.case, label %next_if switch.case: ; preds = %switch.entry - ret ptr @.str.11 + ret ptr @.str.26 next_if: ; preds = %switch.entry %eq1 = icmp eq i64 ptrtoint (ptr @"test.ReadError$BAD_READ" to i64), %1 br i1 %eq1, label %switch.case2, label %next_if3 switch.case2: ; preds = %next_if - ret ptr @.str.12 + ret ptr @.str.27 next_if3: ; preds = %next_if %eq4 = icmp eq i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), %1 br i1 %eq4, label %switch.case5, label %next_if6 switch.case5: ; preds = %next_if3 - ret ptr @.str.13 + ret ptr @.str.28 next_if6: ; preds = %next_if3 br label %switch.default switch.default: ; preds = %next_if6 - ret ptr @.str.14 + ret ptr @.str.29 } ; Function Attrs: nounwind @@ -733,15 +991,15 @@ entry: %has_title.f = alloca i64, align 8 %retparam = alloca i8, align 1 %0 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 0 - store %"char[]" { ptr @.str.15, i64 4 }, ptr %0, align 8 + store %"char[]" { ptr @.str.30, i64 4 }, ptr %0, align 8 %1 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 1 - store %"char[]" { ptr @.str.16, i64 11 }, ptr %1, align 8 + store %"char[]" { ptr @.str.31, i64 11 }, ptr %1, align 8 %2 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 2 - store %"char[]" { ptr @.str.17, i64 13 }, ptr %2, align 8 + store %"char[]" { ptr @.str.32, i64 13 }, ptr %2, align 8 %3 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 3 - store %"char[]" { ptr @.str.18, i64 12 }, ptr %3, align 8 + store %"char[]" { ptr @.str.33, i64 12 }, ptr %3, align 8 %4 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 4 - store %"char[]" { ptr @.str.19, i64 4 }, ptr %4, align 8 + store %"char[]" { ptr @.str.34, i64 4 }, ptr %4, align 8 %5 = insertvalue %"char[][]" undef, ptr %literal, 0 %6 = insertvalue %"char[][]" %5, i64 5, 1 store %"char[][]" %6, ptr %URLS, align 8 @@ -768,7 +1026,7 @@ loop.body: ; preds = %loop.cond %uisitrunc = trunc i64 %15 to i32 %16 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %17 = load ptr, ptr %16, align 8 - %18 = call i32 (ptr, ...) @printf(ptr @.str.20, i32 %uisitrunc, ptr %17) + %18 = call i32 (ptr, ...) @printf(ptr @.str.35, i32 %uisitrunc, ptr %17) %19 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %lo = load ptr, ptr %19, align 8 %20 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 @@ -776,10 +1034,10 @@ loop.body: ; preds = %loop.cond %21 = call { ptr, i8 } @test.readAndBuildSummary(ptr %lo, i64 %hi) store { ptr, i8 } %21, ptr %result, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %summary, ptr align 8 %result, i32 16, i1 false) - %22 = call i32 (ptr, ...) @printf(ptr @.str.21) + %22 = call i32 (ptr, ...) @printf(ptr @.str.36) %23 = load ptr, ptr @__stdoutp, align 8 call void @test.Summary.print(ptr %summary, ptr %23) - %24 = call i32 (ptr, ...) @printf(ptr @.str.22) + %24 = call i32 (ptr, ...) @printf(ptr @.str.37) %25 = getelementptr inbounds %Summary, ptr %summary, i32 0, i32 0 %26 = load ptr, ptr %25, align 8 %ptrbool = icmp ne ptr %26, null @@ -802,7 +1060,7 @@ cond.phi: ; preds = %cond.rhs, %cond.lhs %uisitrunc2 = trunc i64 %31 to i32 %32 = getelementptr inbounds %"char[]", ptr %title_sure, i32 0, i32 0 %33 = load ptr, ptr %32, align 8 - %34 = call i32 (ptr, ...) @printf(ptr @.str.24, i32 %uisitrunc2, ptr %33) + %34 = call i32 (ptr, ...) @printf(ptr @.str.39, i32 %uisitrunc2, ptr %33) %35 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %lo3 = load ptr, ptr %35, align 8 %36 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 @@ -855,8 +1113,8 @@ else_block11: ; preds = %phi_block phi_block12: ; preds = %else_block11, %after_check10 %val13 = phi i1 [ %47, %after_check10 ], [ false, %else_block11 ] - %ternary = select i1 %val13, ptr @.str.26, ptr @.str.27 - %48 = call i32 (ptr, ...) @printf(ptr @.str.25, ptr %val7, ptr %ternary) + %ternary = select i1 %val13, ptr @.str.41, ptr @.str.42 + %48 = call i32 (ptr, ...) @printf(ptr @.str.40, ptr %val7, ptr %ternary) %49 = load i64, ptr %.anon1, align 8 %add = add i64 %49, 1 store i64 %add, ptr %.anon1, align 8