diff --git a/lib/std/io/formatter.c3 b/lib/std/io/formatter.c3 index b4762b4e8..4d5e740bd 100644 --- a/lib/std/io/formatter.c3 +++ b/lib/std/io/formatter.c3 @@ -85,6 +85,7 @@ fn usz! Formatter.print_with_function(&self, Printable arg) self.width = old_width; self.prec = old_prec; } + if (!arg) return self.out_substr("(null)"); return arg.to_format(self); } if (&arg.to_new_string) @@ -98,6 +99,7 @@ fn usz! Formatter.print_with_function(&self, Printable arg) self.width = old_width; self.prec = old_prec; } + if (!arg) return self.out_substr("(null)"); @stack_mem(1024; Allocator mem) { return self.out_substr(arg.to_new_string(mem)); @@ -150,17 +152,8 @@ fn usz! Formatter.out_str(&self, any arg) @private default: } usz! n = self.print_with_function((Printable)arg); - if (catch err = n) - { - case SearchResult.MISSING: - break; - default: - return err?; - } - else - { - return n; - } + if (try n) return n; + if (@catch(n) != SearchResult.MISSING) n!; switch (arg.type.kindof) { case ENUM: @@ -186,9 +179,14 @@ fn usz! Formatter.out_str(&self, any arg) @private } return self.out_str(arg.as_inner()); case POINTER: - if (*(void**)arg == null) + typeid inner = arg.type.inner; + void** pointer = arg.ptr; + if (arg.type.inner != void.typeid) { - return self.out_substr("(null)"); + any deref = any_make(*pointer, inner); + n = self.print_with_function((Printable)deref); + if (try n) return n; + if (@catch(n) != SearchResult.MISSING) n!; } PrintFlags flags = self.flags; uint width = self.width; @@ -197,8 +195,8 @@ fn usz! Formatter.out_str(&self, any arg) @private self.flags = flags; self.width = width; } - self.flags = {}; self.width = 0; + self.out_substr("0x")!; return self.ntoa_any(arg, 16); case ARRAY: // this is SomeType[*] so grab the "SomeType" diff --git a/releasenotes.md b/releasenotes.md index 857d72320..3e4ccb0c8 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -28,6 +28,8 @@ - Added `@tag` `tagof` and `has_tagof` to user defined types and members. - Added `c-include-dirs` project/manifest setting. - The compiler now skips UTF8 BOM. +- Printable values passed to the Formatter as pointers, will print as if passed by value. +- Pointers are rendered with "0x" prefix when passed to '%s'. ### Fixes diff --git a/test/unit/stdlib/core/formatter.c3 b/test/unit/stdlib/core/formatter.c3 new file mode 100644 index 000000000..625910603 --- /dev/null +++ b/test/unit/stdlib/core/formatter.c3 @@ -0,0 +1,20 @@ +module std::core::formatter_test; + +import std; + +struct Foo (Printable) { int a; } +fn usz! Foo.to_format(&self, Formatter *f) @dynamic +{ + return f.printf("Foo[%d]", self.a); +} + +fn void test_ref() @test +{ + Foo* f = &&Foo{ 8 }; + Foo* f0 = null; + int* a = (void*)(uptr)0x40; + int* b = null; + String s = string::new_format("%s %s %s %s %s", a, b, f0, f, *f); + defer free(s); + assert(s == "0x40 0x0 (null) Foo[8] Foo[8]"); +} diff --git a/test/unit/stdlib/core/string.c3 b/test/unit/stdlib/core/string.c3 index 045bd87cd..e9ed50f58 100644 --- a/test/unit/stdlib/core/string.c3 +++ b/test/unit/stdlib/core/string.c3 @@ -19,7 +19,7 @@ fn void test_print_null() ZString w = "hello"; String s = string::new_format("%s %s %s", z, w, y); defer free(s); - assert(s == "(null) hello (null)"); + assert(s == "(null) hello 0x0"); } fn void test_strip()