From 86c09eed3a0c5406cb3bfd8896e0603f3d05a350 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 23 Jun 2026 07:52:03 +0200 Subject: [PATCH 1/3] Generate random non-Number array elements element-wise. Drop the `<:Number` bound on the generic device `rand!` so isbits eltypes with a custom sampler (e.g. ColorTypes colorants) generate on-device instead of falling into the ambiguous host-array/CPU-RNG fallbacks. Matches the unconstrained `rand!` in the Random stdlib. Fixes JuliaGPU/CUDA.jl#3179. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/host/random.jl | 2 +- test/testsuite/random.jl | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/host/random.jl b/src/host/random.jl index 5beb7d31..5cae3de4 100644 --- a/src/host/random.jl +++ b/src/host/random.jl @@ -447,7 +447,7 @@ end end end -function Random.rand!(rng::RNG, A::AnyGPUArray{T}) where T <: Number +function Random.rand!(rng::RNG, A::AnyGPUArray{T}) where T isempty(A) && return A rand_generic_kernel!(get_backend(A))(rng.seed, rng.counter, A; ndrange=length(A)) advance_counter!(rng) diff --git a/test/testsuite/random.jl b/test/testsuite/random.jl index 2cd65a3c..f98a2b16 100644 --- a/test/testsuite/random.jl +++ b/test/testsuite/random.jl @@ -1,3 +1,14 @@ +# A non-`Number` isbits eltype with a custom sampler, mirroring how ColorTypes +# hooks colorants into the Random API. Exercises the generic element-wise rand! +# path; regression cover for JuliaGPU/CUDA.jl#3179. +struct RGBTriplet + r::Float32 + g::Float32 + b::Float32 +end +Random.rand(rng::AbstractRNG, ::Random.SamplerType{RGBTriplet}) = + RGBTriplet(rand(rng, Float32), rand(rng, Float32), rand(rng, Float32)) + @testsuite "random" (AT, eltypes)->begin rng = if AT <: AbstractGPUArray GPUArrays.RNG{AT}() @@ -88,4 +99,16 @@ @test (randn!(cpu_rng, A); true) end end + + # non-`Number` eltypes with a custom sampler must generate element-wise + # rather than hit an ambiguous fallback (JuliaGPU/CUDA.jl#3179) + if AT <: AbstractGPUArray + @testset "non-Number eltype" begin + A = AT{RGBTriplet}(undef, 1024) + rand!(rng, A) + h = Array(A) + @test all(t -> 0f0 <= t.r <= 1f0 && 0f0 <= t.g <= 1f0 && 0f0 <= t.b <= 1f0, h) + @test any(t -> t.r != h[1].r, h) + end + end end From 6ff5539441e8b0a724054dcff86d68b0ccda4aae Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 23 Jun 2026 07:52:37 +0200 Subject: [PATCH 2/3] Restrict randn! array fallback to float eltypes. The host-array `randn!` fallback was unconstrained, so for a GPU RNG and a non-float eltype it matched itself recursively (`similar(AT{T})` is again a GPU array) and stack-overflowed. Constrain it to floats, like the sibling `randn!` methods, so non-float eltypes raise a clean MethodError instead. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/host/random.jl | 3 ++- test/testsuite/random.jl | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/host/random.jl b/src/host/random.jl index 5cae3de4..389ac790 100644 --- a/src/host/random.jl +++ b/src/host/random.jl @@ -586,7 +586,8 @@ function Random.rand!(rng::RNG{AT}, A::AbstractArray{T}) where {AT, T} Random.rand!(rng, B) copyto!(A, B) end -function Random.randn!(rng::RNG{AT}, A::AbstractArray{T}) where {AT, T} +function Random.randn!(rng::RNG{AT}, A::AbstractArray{T}) where {AT, T<:Union{AbstractFloat, + Complex{<:AbstractFloat}}} isempty(A) && return A B = similar(AT{T}, size(A)) Random.randn!(rng, B) diff --git a/test/testsuite/random.jl b/test/testsuite/random.jl index f98a2b16..bb028a02 100644 --- a/test/testsuite/random.jl +++ b/test/testsuite/random.jl @@ -110,5 +110,10 @@ Random.rand(rng::AbstractRNG, ::Random.SamplerType{RGBTriplet}) = @test all(t -> 0f0 <= t.r <= 1f0 && 0f0 <= t.g <= 1f0 && 0f0 <= t.b <= 1f0, h) @test any(t -> t.r != h[1].r, h) end + + # randn! on a non-float eltype must error cleanly, not recurse forever + @testset "randn! rejects non-float" begin + @test_throws MethodError randn!(rng, AT{Int32}(undef, 4)) + end end end From 4e0bbb9d76b56168085b540a6dede96adbfad32b Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 23 Jun 2026 07:52:59 +0200 Subject: [PATCH 3/3] Bump version. Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 707ee08d..032844e3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "GPUArrays" uuid = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7" -version = "11.5.8" +version = "11.5.9" [workspace] projects = ["lib/GPUArraysCore", "lib/JLArrays", "test", "docs"]