diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 915199875..2b1c299c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -88,16 +88,16 @@ jobs: ..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib55 --print-linking examples\raylib\raylib_snake.c3 ..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib55 --print-linking examples\raylib\raylib_tetris.c3 + - name: run compiler tests + run: | + cd test + ..\build\${{ matrix.build_type }}\c3c.exe compile-run -O1 src/test_suite_runner.c3 -- ..\build\${{ matrix.build_type }}\c3c.exe test_suite/ + - name: Compile run unit tests run: | cd test ..\build\${{ matrix.build_type }}\c3c.exe compile-test unit -O1 -D SLOW_TESTS - - name: run compiler tests - run: | - cd test - ..\build\${{ matrix.build_type }}\c3c.exe compile-run -O1 src/test_suite_runner.c3 -- ..\build\${{ matrix.build_type }}\c3c.exe test_suite/ --no-terminal - - name: Test python script run: | py msvc_build_libraries.py --accept-license diff --git a/lib/std/io/io.c3 b/lib/std/io/io.c3 index 72e0f8245..17251ae86 100644 --- a/lib/std/io/io.c3 +++ b/lib/std/io/io.c3 @@ -35,6 +35,7 @@ faultdef NO_PERMISSION, OUT_OF_SPACE, OVERFLOW, + PATH_COULD_NOT_BE_FOUND, READ_ONLY, SYMLINK_FAILED, TOO_MANY_DESCRIPTORS, diff --git a/lib/std/io/os/temp_directory.c3 b/lib/std/io/os/temp_directory.c3 index c8e20f782..7b03efad7 100644 --- a/lib/std/io/os/temp_directory.c3 +++ b/lib/std/io/os/temp_directory.c3 @@ -1,5 +1,112 @@ +module std::io::os; + +enum NativeSystemDir +{ + DESKTOP, + DOCUMENTS, + VIDEOS, + MUSIC, + DOWNLOADS, + PICTURES, + TEMPLATES, + PUBLIC_SHARE, + SAVED_GAMES, + SCREENSHOTS +} + module std::io::os @if(env::LIBC); -import std::io::path, std::os; +import std::io, std::os; + +fn String? win32_get_known_folder_temp(Win32_REFKNOWNFOLDERID rfid) @private @if(env::WIN32) +{ + Win32_PWSTR path; + Win32_HRESULT res = win32::shGetKnownFolderPath(rfid, 0x00008000 /* KF_FLAG_CREATE */, null, &path); + if (res) return io::PATH_COULD_NOT_BE_FOUND?; + return string::from_wstring(tmem, (WString)path); +} + +fn Path? native_home_directory(Allocator allocator) => @pool() +{ + $switch env::OS_TYPE: + $case IOS: + $case MACOS: + $case TVOS: + $case WATCHOS: + $case FREEBSD: + $case KFREEBSD: + $case LINUX: + $case NETBSD: + $case OPENBSD: + $case HAIKU: + return path::new(allocator, env::tget_var("HOME")) ?? io::PATH_COULD_NOT_BE_FOUND?; + $case WIN32: + return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_PROFILE)); + $default: + return io::PATH_COULD_NOT_BE_FOUND?; + $endswitch +} + +fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => @pool() +{ + $switch env::OS_TYPE: + $case FREEBSD: + $case KFREEBSD: + $case LINUX: + $case NETBSD: + $case OPENBSD: + $case HAIKU: + switch (dir) + { + case DESKTOP: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "DESKTOP")); + case DOWNLOADS: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "DOWNLOAD")); + case DOCUMENTS: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "DOCUMENTS")); + case MUSIC: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "MUSIC")); + case VIDEOS: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "VIDEOS")); + case PICTURES: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "PICTURES")); + case PUBLIC_SHARE: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "PUBLICSHARE")); + case TEMPLATES: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "TEMPLATES")); + case SAVED_GAMES: + case SCREENSHOTS: nextcase; + default: return io::PATH_COULD_NOT_BE_FOUND?; + } + $case IOS: + $case MACOS: + $case WATCHOS: + $case TVOS: + switch (dir) + { + case DESKTOP: return path::new(allocator, darwin::find_first_directory_temp(DESKTOP, USER)); + case DOWNLOADS: return path::new(allocator, darwin::find_first_directory_temp(DOWNLOADS, USER)); + case DOCUMENTS: return path::new(allocator, darwin::find_first_directory_temp(DOCUMENT, USER)); + case MUSIC: return path::new(allocator, darwin::find_first_directory_temp(MUSIC, USER)); + case VIDEOS: return path::new(allocator, darwin::find_first_directory_temp(MOVIES, USER)); + case PICTURES: return path::new(allocator, darwin::find_first_directory_temp(PICTURES, USER)); + case PUBLIC_SHARE: return path::new(allocator, darwin::find_first_directory_temp(SHARED_PUBLIC, USER)); + case SAVED_GAMES: + case SCREENSHOTS: + case TEMPLATES: nextcase; + default: return io::PATH_COULD_NOT_BE_FOUND?; + } + $case WIN32: + switch (dir) + { + case DOWNLOADS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_DOWNLOADS)); + case DOCUMENTS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_DOCUMENTS)); + case DESKTOP: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_DESKTOP)); + case MUSIC: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_MUSIC)); + case VIDEOS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_VIDEOS)); + case PICTURES: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_PICTURES)); + case SAVED_GAMES: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_SAVED_GAMES)); + case SCREENSHOTS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_SCREENSHOTS)); + case TEMPLATES: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_TEMPLATES)); + case PUBLIC_SHARE: nextcase; + default: return io::PATH_COULD_NOT_BE_FOUND?; + } + $default: + return io::PATH_COULD_NOT_BE_FOUND?; + $endswitch +} + fn Path? native_temp_directory(Allocator allocator) @if(!env::WIN32) { @@ -23,7 +130,6 @@ fn Path? native_temp_directory(Allocator allocator) @if(env::WIN32) => @pool() module std::io::os @if(env::NO_LIBC); import std::io::path; -macro Path? native_temp_directory(Allocator allocator) -{ - return io::UNSUPPORTED_OPERATION?; -} +macro Path? native_home_directory(Allocator allocator) => io::PATH_COULD_NOT_BE_FOUND?; +macro Path? native_temp_directory(Allocator allocator) => io::PATH_COULD_NOT_BE_FOUND?; +fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => io::PATH_COULD_NOT_BE_FOUND?; diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index a99e79d2d..e729b018a 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -57,6 +57,18 @@ macro void? chdir(path) fn Path? temp_directory(Allocator allocator) => os::native_temp_directory(allocator); +fn Path? home_directory(Allocator allocator) => os::native_home_directory(allocator); +fn Path? desktop_directory(Allocator allocator) => os::native_user_directory(allocator, DESKTOP); +fn Path? videos_directory(Allocator allocator) => os::native_user_directory(allocator, VIDEOS); +fn Path? music_directory(Allocator allocator) => os::native_user_directory(allocator, MUSIC); +fn Path? documents_directory(Allocator allocator) => os::native_user_directory(allocator, DOCUMENTS); +fn Path? screenshots_directory(Allocator allocator) => os::native_user_directory(allocator, SCREENSHOTS); +fn Path? saved_games_directory(Allocator allocator) => os::native_user_directory(allocator, SAVED_GAMES); +fn Path? downloads_directory(Allocator allocator) => os::native_user_directory(allocator, DOWNLOADS); +fn Path? pictures_directory(Allocator allocator) => os::native_user_directory(allocator, PICTURES); +fn Path? templates_directory(Allocator allocator) => os::native_user_directory(allocator, TEMPLATES); +fn Path? public_share_directory(Allocator allocator) => os::native_user_directory(allocator, PUBLIC_SHARE); + fn void? delete(Path path) => os::native_remove(path.str_view()) @inline; macro bool @is_pathlike(#path) @const => $typeof(#path) == String ||| $typeof(#path) == Path; diff --git a/lib/std/os/macos/cf_array.c3 b/lib/std/os/macos/cf_array.c3 index aa9c05bab..8bbeb24ba 100644 --- a/lib/std/os/macos/cf_array.c3 +++ b/lib/std/os/macos/cf_array.c3 @@ -1,11 +1,18 @@ module std::os::macos::cf @if(env::DARWIN) @link(env::DARWIN, "CoreFoundation.framework"); -typedef CFArrayRef = void*; +typedef CFArray = inline CFType; +alias CFArrayRef = CFArray*; typedef CFArrayCallBacksRef = void*; -typedef CFMutableArrayRef = void*; +typedef CFMutableArray = inline CFArray; +typedef CFMutableArrayRef = CFMutableArray*; + +extern fn CFIndex CFArray.getCount(&self) @extern("CFArrayGetCount"); +extern fn void* CFArray.getValueAtIndex(&self, CFIndex i) @extern("CFArrayGetValueAtIndex"); + extern fn CFArrayRef macos_CFArrayCreate(CFAllocatorRef allocator, void** values, CFIndex num_values, CFArrayCallBacksRef callBacks) @extern("CFArrayCreate") @builtin; extern fn CFArrayRef macos_CFArrayCopy(CFAllocatorRef allocator, CFArrayRef array) @extern("CFArrayCopy") @builtin; -extern fn CFIndex macos_CFArrayGetCount(CFArrayRef array) @extern("CFArrayGetCount") @builtin; -extern fn void macos_CFArrayAppendArray(CFMutableArrayRef theArray, CFArrayRef otherArray, CFRange otherRange) @extern("CFArrayAppendArray") @builtin; +extern fn void CFMutableArray.appendArray(&self, CFArrayRef otherArray, CFRange otherRange) @extern("CFArrayAppendArray"); +extern fn void CFMutableArray.appendValue(&self, void *value) @extern("CFArrayAppendValue"); + extern fn CFMutableArrayRef macos_CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, CFArrayCallBacksRef callBacks) @extern("CFArrayCreateMutable") @builtin; -extern fn void macos_CFArrayAppendValue(CFMutableArrayRef theArray, void *value) @extern("CFArrayAppendValue") @builtin; + diff --git a/lib/std/os/macos/core_foundation.c3 b/lib/std/os/macos/core_foundation.c3 index 43c585aba..a4dde531e 100644 --- a/lib/std/os/macos/core_foundation.c3 +++ b/lib/std/os/macos/core_foundation.c3 @@ -1,13 +1,42 @@ module std::os::macos::cf @if(env::DARWIN) @link(env::DARWIN, "CoreFoundation.framework"); -typedef CFTypeRef = void*; +typedef CFType = void; +typedef CFTypeRef = CFType*; alias CFIndex = isz; +typedef CFString = inline CFType; +alias CFStringRef = CFString*; + struct CFRange { CFIndex location; CFIndex length; } -extern fn CFTypeRef macos_CFRetain(CFTypeRef cf) @extern("CFRetain") @builtin; -extern fn void macos_CFRelease(CFTypeRef cf) @extern("CFRelease") @builtin; \ No newline at end of file +extern fn ZString CFString.getCStringPtr(&self, CFStringEncoding encoding) @extern("CFStringGetCStringPtr"); +extern fn ZString CFString.getCString(&self, char* buffer, usz len, CFStringEncoding encoding) @extern("CFStringGetCString"); + +extern fn CFTypeRef CFType.retain(&self) @extern("CFRetain"); +extern fn void CFType.release(&self) @extern("CFRelease"); +extern fn CFIndex CFType.getRetainCount(&self) @extern("CFGetRetainCount"); + +enum CFStringEncoding : const uint +{ + INVALID_ID = 0xffffffffU, + MAC_ROMAN = 0, + WINDOWS_LATIN_1 = 0x0500, + ISO_LATIM_1 = 0x0201, + NEXT_STEP_LATIN = 0x0B01, + ASCII = 0x0600, + UNICODE = 0x0100, + UTF8 = 0x08000100, + NON_LOSSY_ASCII = 0x0BFF, + + UTF16 = 0x0100, + UTF16BE = 0x10000100, + UTF16LE = 0x14000100, + + UTF32 = 0x0c000100, + UTF32BE = 0x18000100, + UTF32LE = 0x1c000100 +} diff --git a/lib/std/os/macos/general.c3 b/lib/std/os/macos/general.c3 index d4c95a6ef..276737047 100644 --- a/lib/std/os/macos/general.c3 +++ b/lib/std/os/macos/general.c3 @@ -1,2 +1,60 @@ -module std::os::darwin @if(env::DARWIN); +module std::os::darwin @if(env::DARWIN) @link("Foundation.framework"); +import std::os::macos::cf, std::os::macos::objc, std::io; +enum NSSearchPathDomainMask : const NSUInteger +{ + USER = 1, + LOCAL = 2, + NETWORK = 4, + SYSTEM = 8, + ALL = 0x0ffff +} + +enum NSSearchPathDirectory : const NSUInteger +{ + APPLICATION = 1, + DEMO_APPLICATION, + DEVELOPER_APPLICATION, + ADMIN_APPLICATION, + LIBRARY, + DEVELOPER, + USER, + DOCUMENTATION, + DOCUMENT, + CORE_SERVICE, + AUTOSAVED_INFORMATION, + DESKTOP = 12, + CACHES = 13, + APPLICATION_SUPPORT = 14, + DOWNLOADS = 15, + INPUT_METHODS = 16, + MOVIES = 17, + MUSIC = 18, + PICTURES = 19, + PRINTER_DESCRIPTION = 20, + SHARED_PUBLIC = 21, + PREFERENCE_PANES = 22, + APPLICATION_SCRIPTS = 23, + ITEM_REPLACEMENT = 99, + ALL_APPLICATIONS = 100, + ALL_LIBRARIES = 101, + TRASH = 102, +} + +// real signature in Foundation +extern fn CFArrayRef nsSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, bool expandTilde) @extern("NSSearchPathForDirectoriesInDomains"); + + + +fn String? find_first_directory_temp(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask) +{ + objc::@autoreleasepool() + { + CFArrayRef arr = nsSearchPathForDirectoriesInDomains(directory, domainMask, true); + if (!arr.getCount()) return io::PATH_COULD_NOT_BE_FOUND?; + CFStringRef str = (CFStringRef)arr.getValueAtIndex(0); + char* buffer = tmalloc(2048); + if (!str.getCString(buffer, 2048, UTF8)) return io::PATH_COULD_NOT_BE_FOUND?; + return ((ZString)buffer).str_view(); + }; +} diff --git a/lib/std/os/macos/objc.c3 b/lib/std/os/macos/objc.c3 index 355b0743a..87f5772cb 100644 --- a/lib/std/os/macos/objc.c3 +++ b/lib/std/os/macos/objc.c3 @@ -20,6 +20,9 @@ macro bool ObjcClass.equals(ObjcClass a, ObjcClass b) => a == b; fn ObjcId alloc(ObjcClass cls) => objc::msg_send(cls, SendVoid, "alloc"); fn void release(ObjcId id) => objc::msg_send(id, SendVoid, "release"); +alias NSUInteger = $typefrom(env::ARCH_64_BIT ??? ulong : uint); +alias NSInteger = $typefrom(env::ARCH_64_BIT ??? long : int); + macro ObjcClass? class_by_name(ZString c) { ObjcClass cls = objc::lookUpClass(c); @@ -43,6 +46,15 @@ macro msg_send(id, $FunctionType, ZString $selector, ...) return (($FunctionType)&msgSend)((ObjcId)id, sel_getUid($selector), $vasplat); } +macro void @autoreleasepool(;@body()) +{ + void* ctx = objc_autoreleasePoolPush(); + defer objc_autoreleasePoolPop(ctx); + @body(); +} + +extern fn void* objc_autoreleasePoolPush(); +extern fn void objc_autoreleasePoolPop(void* context); extern fn ObjcClass getClass(ZString name) @extern("objc_getClass"); extern fn int getClassList(ObjcClass* buffer, int buffer_count) @extern("objc_getClassList"); extern fn ObjcClass lookUpClass(ZString name) @extern("objc_lookUpClass") @builtin; diff --git a/lib/std/os/win32/shell32.c3 b/lib/std/os/win32/shell32.c3 new file mode 100644 index 000000000..42c6a07cb --- /dev/null +++ b/lib/std/os/win32/shell32.c3 @@ -0,0 +1,16 @@ +module std::os::win32 @if(env::WIN32) @link("shell32"); + +typedef Win32_REFKNOWNFOLDERID = Win32_KNOWNFOLDERID*; +typedef Win32_KNOWNFOLDERID = Win32_GUID; +extern fn Win32_HRESULT shGetKnownFolderPath(Win32_REFKNOWNFOLDERID rfid, Win32_DWORD dwFlags, Win32_HANDLE hToken, Win32_PWSTR* ppszPath) @extern("SHGetKnownFolderPath"); + +const Win32_KNOWNFOLDERID FOLDERID_PROFILE = { 0x5E6C858F, 0x0E22, 0x4760, x"9AFEEA3317B67173" }; +const Win32_KNOWNFOLDERID FOLDERID_DESKTOP = { 0xB4BFCC3A, 0xDB2C, 0x424C, x"B0297FE99A87C641" }; +const Win32_KNOWNFOLDERID FOLDERID_DOCUMENTS = { 0xFDD39AD0, 0x238F, 0x46AF, x"ADB46C85480369C7" }; +const Win32_KNOWNFOLDERID FOLDERID_DOWNLOADS = { 0x374de290, 0x123f, 0x4565, x"916439c4925e467b" }; +const Win32_KNOWNFOLDERID FOLDERID_MUSIC = { 0x4BD8D571, 0x6D19, 0x48D3, x"BE97422220080E43" }; +const Win32_KNOWNFOLDERID FOLDERID_PICTURES = { 0x33E28130, 0x4E1E, 0x4676, x"835A98395C3BC3BB" }; +const Win32_KNOWNFOLDERID FOLDERID_SAVED_GAMES = { 0x4c5c32ff, 0xbb9d, 0x43b0, x"b5b42d72e54eaaa4" }; +const Win32_KNOWNFOLDERID FOLDERID_SCREENSHOTS = { 0xb7bede81, 0xdf94, 0x4682, x"a7d857a52620b86f" }; +const Win32_KNOWNFOLDERID FOLDERID_TEMPLATES = { 0xA63293E8, 0x664E, 0x48DB, x"A079DF759E0509F7" }; +const Win32_KNOWNFOLDERID FOLDERID_VIDEOS = { 0x18989B1D, 0x99B5, 0x455B, x"841CAB7C74E4DDFC" }; diff --git a/lib/std/os/xdg.c3 b/lib/std/os/xdg.c3 new file mode 100644 index 000000000..d0d06b93c --- /dev/null +++ b/lib/std/os/xdg.c3 @@ -0,0 +1,53 @@ +module std::os::posix @if(env::POSIX); +import std::io, std::os::env; + +fn String? xdg_user_dir_lookup(Allocator allocator, String type) => @pool() +{ + String home = env::tget_var("HOME")!; + String config_file @noinit; + if (try String config_home = env::tget_var("XDG_CONFIG_HOME") && config_home.len) + { + config_file = config_home.tconcat("/user-dirs.dirs"); + } + else + { + config_file = home.tconcat("/.config/user-dirs.dirs"); + } + File f = file::open(config_file, "r")!; + defer (void)f.close(); + while (try line = io::treadline(&f)) + { + line = line.trim(); + if (!line.starts_with("XDG_")) continue; + line = line[4..]; + if (!line.starts_with(type)) continue; + line = line[type.len ..]; + if (!line.starts_with("_DIR")) continue; + line = line[4..]; + line = line.trim(); + if (!line.starts_with("=")) continue; + line = line[1..].trim(); + if (!line.starts_with("\"")) continue; + line = line[1..]; + bool relative = false; + if (line.starts_with("$HOME/")) + { + relative = true; + line = line[6..]; + } + else + { + if (!line.starts_with("/")) continue; + if (line.len < 2) continue; + line = line[1..]; + } + if (line.len < 1 || line[^1] != '"') continue; + line = line[:^1]; + if (relative) + { + return string::format(allocator, "%s/%s", home, line); + } + return line.copy(allocator); + } + return io::PATH_COULD_NOT_BE_FOUND?; +} \ No newline at end of file diff --git a/releasenotes.md b/releasenotes.md index daee07764..a02cfc128 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -11,9 +11,12 @@ - Returning pointer to index of slice stored in a struct from method taking self incorrectly detected as returning pointer to local variable #2455. - Inlining location when accessing #foo symbols. - Improve inlined-at when checking generic code. +- Fix codegen bug in expressions like `foo(x()) ?? io::EOF?` causing irregular crashes. ### Stdlib changes - Added generic `InterfaceList` to store a list of values that implement a specific interface +- Added `path::home_directory`, `path::documents_directory`, `path::videos_directory`, `path::pictures_directory`, `path::desktop_directory`, `path::screenshots_directory`, + `path::public_share_directory`, `path::templates_directory`, `path::saved_games_directory`, `path::music_directory`, `path::downloads_directory`. ## 0.7.5 Change list diff --git a/resources/testproject/src/hello_world.c3 b/resources/testproject/src/hello_world.c3 index 4fe003928..ea9a2239f 100644 --- a/resources/testproject/src/hello_world.c3 +++ b/resources/testproject/src/hello_world.c3 @@ -1,10 +1,5 @@ module hello_world; -import std; -import bar; -import clib; -import clib2; -import std::core::env; - +import std, bar, clib, clib2; fn int test_doubler(int x) @if(env::WIN32) => x * x; extern fn int test_doubler(int) @if(!env::WIN32); @@ -18,6 +13,10 @@ fn int main() printf("Author emails:"); io::printn(env::AUTHOR_EMAILS); + (void)io::printfn("Home dir: %s", path::home_directory(tmem)); + (void)io::printfn("Desktop dir: %s", path::desktop_directory(tmem)); + (void)io::printfn("Documents dir: %s", path::documents_directory(tmem)); + bar::test(); printf("Hello double: %d\n", test_doubler(11)); if ($feature(ABCD)) io::printn("ABCD"); diff --git a/src/compiler/ast.c b/src/compiler/ast.c index c8b316574..f18fe1248 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -404,10 +404,12 @@ bool decl_needs_prefix(Decl *decl) { switch (decl->decl_kind) { - case DECL_VAR: - case DECL_ALIAS: case DECL_FUNC: case DECL_MACRO: + if (decl->func_decl.type_parent) return false; + FALLTHROUGH; + case DECL_VAR: + case DECL_ALIAS: case DECL_FAULT: return !decl->is_autoimport; default: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index aa022021d..4db1d1a1c 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -3858,7 +3858,10 @@ static void llvm_emit_else(GenContext *c, BEValue *be_value, Expr *expr) // Only jump to phi if we didn't have an immediate jump. That would // for example happen on "{| defer foo(); return Foo.ERR?; |} ?? 123" - if (success_end_block) llvm_emit_br(c, phi_block); + if (success_end_block) + { + if (!llvm_emit_br(c, phi_block)) success_end_block = NULL; + } // Emit else llvm_emit_block(c, else_block); @@ -3881,27 +3884,28 @@ static void llvm_emit_else(GenContext *c, BEValue *be_value, Expr *expr) } } + // If there wasn't a success, then we end here, even if the else was a jump. + if (!success_end_block) + { + *be_value = else_value; + return; + } + LLVMBasicBlockRef else_block_exit = llvm_get_current_block_if_in_use(c); // While the value may not be an optional, we may get a jump // from this construction: foo() ?? (bar()?) // In this case the else block is empty. - if (!else_block_exit) + if (!else_block_exit || !llvm_emit_br(c, phi_block)) { llvm_emit_block(c, phi_block); *be_value = real_value; return; } - llvm_emit_br(c, phi_block); llvm_emit_block(c, phi_block); - // Was there never a success, if so the result is the be_value. - if (!success_end_block) - { - *be_value = else_value; - return; - } + assert(success_end_block && else_block_exit); // Emit an address if the phi is was by address if (was_address) diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index b9a16f247..12aae8fde 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -55,11 +55,12 @@ bool llvm_emit_check_block_branch(GenContext *c) return true; } -void llvm_emit_br(GenContext *c, LLVMBasicBlockRef next_block) +bool llvm_emit_br(GenContext *c, LLVMBasicBlockRef next_block) { - if (!llvm_emit_check_block_branch(c)) return; + if (!llvm_emit_check_block_branch(c)) return false; c->current_block = NULL; LLVMBuildBr(c->builder, next_block); + return true; } diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 9c90d197b..b607db1db 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -424,7 +424,7 @@ INLINE LLVMValueRef llvm_get_struct_of_type(GenContext *c, Type *type, LLVMValue // -- Jumps -- void llvm_emit_cond_br(GenContext *context, BEValue *value, LLVMBasicBlockRef then_block, LLVMBasicBlockRef else_block); void llvm_emit_cond_br_raw(GenContext *context, LLVMValueRef b, LLVMBasicBlockRef then_block, LLVMBasicBlockRef else_block); -void llvm_emit_br(GenContext *c, LLVMBasicBlockRef next_block); +bool llvm_emit_br(GenContext *c, LLVMBasicBlockRef next_block); void llvm_emit_jump_to_optional_exit(GenContext *c, LLVMValueRef opt_value); void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *optional); void llvm_emit_return_implicit(GenContext *c); diff --git a/test/test_suite/errors/macro_err3.c3t b/test/test_suite/errors/macro_err3.c3t index 13e6a8c54..0f95b8815 100644 --- a/test/test_suite/errors/macro_err3.c3t +++ b/test/test_suite/errors/macro_err3.c3t @@ -28,9 +28,6 @@ opt_block_cleanup: ; preds = %entry br label %else_block else_block: ; preds = %opt_block_cleanup - br label %phi_block - -phi_block: ; preds = %else_block %1 = call i32 (ptr, ...) @printf(ptr @.str, i32 2) %2 = call i32 (ptr, ...) @printf(ptr @.str.3) ret void