Skip to content

New restrictions on generated functions in 1.12? #57701

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

Closed
KristofferC opened this issue Mar 10, 2025 · 5 comments
Closed

New restrictions on generated functions in 1.12? #57701

KristofferC opened this issue Mar 10, 2025 · 5 comments
Milestone

Comments

@KristofferC
Copy link
Member

KristofferC commented Mar 10, 2025

Consider the following generated function:

@generated function constructorof(::Type{T}) where T
    getfield(parentmodule(T), nameof(T))
end

This should (at least from what I can see) be an ok generated function considering the current restrictions the docs places on them. It only calls functions defined before the function and it only reads global constants. However, it currently gives a warning

julia> struct Foo end

julia> constructorof(Foo)
WARNING: Detected access to binding `Main.Foo` in a world prior to its definition world.
  Julia 1.12 has introduced more strict world age semantics for global bindings.
  !!! This code may malfunction under Revise.
  !!! This code will error in future versions of Julia.
Hint: Add an appropriate `invokelatest` around the access to this binding.
Foo

So it seems that there is an additional restriction to generated functions now in that it is only allowed to read a global constant defined before the generated function. If that is the case, the documentation should be updated.

A lot of code in e.g. ConstructionBase uses this pattern:

https://github.com/JuliaObjects/ConstructionBase.jl/blob/72bb19dad11695fd94de66c738db534f89b23878/src/ConstructionBase.jl#L29-L31

https://github.com/JuliaObjects/ConstructionBase.jl/blob/72bb19dad11695fd94de66c738db534f89b23878/src/functions.jl#L11

@KristofferC KristofferC added the breaking This change will break code label Mar 10, 2025
@KristofferC KristofferC added this to the 1.12 milestone Mar 10, 2025
@Keno
Copy link
Member

Keno commented Mar 11, 2025

This was undefined behavior before, the compiler just didn't have the ability to check. E.g. something like:

@generated function foo()
       try; x; return :(1.0) catch; return 1; end
       end

would give you type confusion and segfaults. In fact, with the new 1.12 semantics, this is no longer UB (so it actually removes a restriction on generated functions), you just always get the value (or error of x) at definition time. That said, we do still have the backdate code of course, which does make this UB again, but in the fullness of time, this will no longer be UB.

@Keno
Copy link
Member

Keno commented Mar 11, 2025

In addition, 1.12 gives you the ability to actually write a legal version of that function that does what the authors want, although you do have to manually declare your world bounds and edges, which is a bit tricky and there's likely simpler versions to achieve what that package wants, but at least it's possible, which it wasn't before.

@KristofferC KristofferC removed the breaking This change will break code label Mar 11, 2025
@vtjnash
Copy link
Member

vtjnash commented Mar 11, 2025

It may still be likely UB, since they are using the generated function to bypass the otherwise detected incorrectness of doing egal structural queries on a merely type-equal operator. I think they want typename(T).wrapper here instead, which is still strongly discouraged as a coding antipattern, but at least not unsound like their current version

@Keno
Copy link
Member

Keno commented Mar 12, 2025

Sure, the particular code in the issue may still be UB due to that issue. I was referring specifically to the access to a possibly undefined constant

@vtjnash
Copy link
Member

vtjnash commented Mar 14, 2025

Working on a fix for the package here: JuliaObjects/ConstructionBase.jl#99

@vtjnash vtjnash closed this as not planned Won't fix, can't repro, duplicate, stale Mar 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants