Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improved error diagnostics when unable to inline a function #38

Closed
andrewrk opened this issue Dec 22, 2015 · 4 comments · Fixed by #17170
Closed

improved error diagnostics when unable to inline a function #38

andrewrk opened this issue Dec 22, 2015 · 4 comments · Fixed by #17170
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase. frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Milestone

Comments

@andrewrk
Copy link
Member

andrewrk commented Dec 22, 2015

Actual Behavior

test3.zig

test {
    const p = &foo;
    p();
}

inline fn foo() void {}
$ stage2/bin/zig test test3.zig
Global is external, but doesn't have external or weak linkage!
void ()* @test3.foo

Expected Behavior

Allowed, but p is comptime pointer to a comptime-known function body. If var is used instead of const then it should be "error: pointer to inline function must be comptime-known"

@andrewrk andrewrk added the enhancement Solving this issue will likely involve adding new logic or components to the codebase. label Dec 22, 2015
@andrewrk andrewrk added this to the debut milestone Jan 18, 2016
@andrewrk andrewrk changed the title add an error for alwaysinline attribute functions which attempt recursion add an error for attempt to take address of inline functions Jul 29, 2016
@andrewrk
Copy link
Member Author

inline functions can call themselves with #167 and the compiler will complain if there are too many backwards branches.

However, if an inline function calls itself in the generated (post-evaluated) function, then there should be an error.

@andrewrk
Copy link
Member Author

andrewrk commented May 4, 2017

This is actually a really hard problem. We want to catch things like indirect recursion with inline functions, but sometimes indirect recursion is fine, if it terminates.

LLVM handles this by ignoring the alwaysinline attribute when it can't do the inlining.

We can duplicate LLVM's analysis and logic, or we can try to reach back into the module post-optimization and discover if inlining failed.

@andrewrk
Copy link
Member Author

andrewrk commented May 4, 2017

I added a compile error for when an inline function cannot be inlined. It looks at the post-optimization module and sees if the function got inlined. However there are these harder, unsolved problems:

  • There is no note: pointing to the cause of why the function cannot be inlined.
  • There are cases when debug mode and release mode are different, because LLVM optimizations can do crazy stuff like figure out that indirect recursion is tail called and change it to a loop:
export fn foo() {
    bar();
}
inline fn bar() {
    quux();
    baz();
}
inline fn baz() {
    quux();
    bar();
}
extern fn quux();

In debug mode this gives error: unable to inline function but in release mode, it ends up figuring out this:

; Function Attrs: nounwind
define void @foo() local_unnamed_addr #0 !dbg !16 {
Entry:
  br label %tailrecurse.i
tailrecurse.i:                                    ; preds = %tailrecurse.i, %Entry
  tail call void @quux() #0, !dbg !22
  tail call void @quux() #0, !dbg !27
  br label %tailrecurse.i, !dbg !31
}
  • We don't have a way to figure out if callsite inlining worked.

Moving this to another milestone to deal with.

@andrewrk andrewrk modified the milestones: 0.2.0, 0.1.0 May 4, 2017
@andrewrk andrewrk changed the title add an error for attempt to take address of inline functions improved error diagnostics when unable to inline a function May 4, 2017
@andrewrk andrewrk modified the milestones: 0.2.0, 0.3.0 Oct 20, 2017
@andrewrk andrewrk modified the milestones: 0.3.0, 0.4.0 Feb 28, 2018
@andrewrk andrewrk modified the milestones: 0.4.0, 0.5.0 Sep 28, 2018
@andrewrk andrewrk modified the milestones: 0.5.0, 0.6.0 Apr 10, 2019
@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Oct 17, 2019
@andrewrk andrewrk added the stage1 The process of building from source via WebAssembly and the C backend. label Apr 14, 2020
@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Apr 14, 2020
@BarabasGitHub
Copy link
Contributor

BarabasGitHub commented May 10, 2020

zig version
0.6.0+d4d509090

fn number() !void {
    _ = try @import("std").fmt.parseFloat(f64, &[_]u8{ 1, 2, 3, 4, 5 });
}

test "parseFloat" {
    _ = number;
}

gives:

..\lib\zig\std\fmt\parse_float.zig:55:5: error: unable to inline function
    inline fn shiftLeft1(d: *Z96, s: Z96) void {
    ^
..\lib\zig\std\fmt\parse_float.zig:62:5: error: unable to inline function
    inline fn add(d: *Z96, s: Z96) void {
    ^
..\lib\zig\std\fmt\parse_float.zig:48:5: error: unable to inline function
    inline fn shiftRight1(d: *Z96, s: Z96) void {
    ^

calling number works, but in my real code I do call the function (in some other function) and still get the same error.

@andrewrk andrewrk added frontend Tokenization, parsing, AstGen, Sema, and Liveness. and removed stage1 The process of building from source via WebAssembly and the C backend. labels Aug 15, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Jun 4, 2021
@andrewrk andrewrk removed this from the 0.9.0 milestone Nov 21, 2021
@andrewrk andrewrk added this to the 0.10.0 milestone Nov 21, 2021
@andrewrk andrewrk modified the milestones: 0.10.0, 0.11.0 Aug 23, 2022
moosichu added a commit to moosichu/zig that referenced this issue Aug 28, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Aug 30, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Aug 30, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Aug 30, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Sep 5, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Sep 5, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
andrewrk pushed a commit to moosichu/zig that referenced this issue Sep 12, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Sep 16, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Sep 16, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Oct 8, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
andrewrk pushed a commit to moosichu/zig that referenced this issue Oct 12, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Oct 27, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Dec 11, 2022
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
andrewrk pushed a commit to moosichu/zig that referenced this issue Jan 27, 2023
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
moosichu added a commit to moosichu/zig that referenced this issue Feb 17, 2023
Follow the guidance of ziglang#38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.
Vexu pushed a commit that referenced this issue Feb 19, 2023
…2661)

* Scan from line start when finding tag in tokenizer

This resolves a crash that can occur for invalid bytes like carriage
returns that are valid characters when not parsed from within literals.

There are potentially other edge cases this could resolve as well, as
the calling code for this function didn't account for any potential
'pending_invalid_tokens' that could be queued up by the tokenizer from
within another state.

* Fix carriage return crash in multiline string

Follow the guidance of #38:

> However CR directly before NL is interpreted as only a newline and not part of the multiline string. zig fmt will delete the CR.

Zig fmt already had code for deleting carriage returns, but would still
crash - now it no longer does so. Carriage returns encountered before
line-feeds are now appropriately removed on program compilation as well.

* Only accept carriage returns before line feeds

Previous commit was much less strict about this, this more closely
matches the desired spec of only allow CR characters in a CRLF pair, but
not otherwise.

* Fix CR being rejected when used as whitespace

Missed this comment from ziglang/zig-spec#83:

> CR used as whitespace, whether directly preceding NL or stray, is still unambiguously whitespace. It is accepted by the grammar and replaced by the canonical whitespace by zig fmt.

* Add tests for carriage return handling
@andrewrk andrewrk modified the milestones: 0.11.0, 0.12.0 Apr 9, 2023
mlugg added a commit to mlugg/zig that referenced this issue Sep 15, 2023
This is supposed to be the case, similar to how pointers to generic
functions are comptime-only (several pieces of logic already assumed
this). These types being considered runtime was causing `dbg_var_ptr`
AIR instructions to be wrongly emitted for such values, causing codegen
backends to create a runtime reference to the inline function, which (at
least on the LLVM backend) triggers an error.

Resolves: ziglang#38
mlugg added a commit to mlugg/zig that referenced this issue Sep 15, 2023
This is supposed to be the case, similar to how pointers to generic
functions are comptime-only (several pieces of logic already assumed
this). These types being considered runtime was causing `dbg_var_val`
AIR instructions to be wrongly emitted for such values, causing codegen
backends to create a runtime reference to the inline function, which (at
least on the LLVM backend) triggers an error.

Resolves: ziglang#38
andrewrk pushed a commit that referenced this issue Sep 16, 2023
This is supposed to be the case, similar to how pointers to generic
functions are comptime-only (several pieces of logic already assumed
this). These types being considered runtime was causing `dbg_var_val`
AIR instructions to be wrongly emitted for such values, causing codegen
backends to create a runtime reference to the inline function, which (at
least on the LLVM backend) triggers an error.

Resolves: #38
@andrewrk andrewrk modified the milestones: 0.14.0, 0.12.0 Sep 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase. frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants