diff --git a/base/channels.jl b/base/channels.jl index 8882171095e7a..527c22b3d45fd 100644 --- a/base/channels.jl +++ b/base/channels.jl @@ -716,6 +716,15 @@ function iterate(c::Channel, state=nothing) end end else + # If the channel was closed with an exception, it needs to be thrown + if (@atomic :acquire c.state) === :closed + e = c.excp + if isa(e, InvalidStateException) && e.state === :closed + nothing + else + throw(e) + end + end return nothing end end diff --git a/test/channels.jl b/test/channels.jl index f3e5381a62e94..4acf6c94da1b6 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -499,12 +499,35 @@ end end end +struct CustomError <: Exception end + @testset "check_channel_state" begin c = Channel(1) close(c) @test !isopen(c) c.excp === nothing # to trigger the branch @test_throws InvalidStateException Base.check_channel_state(c) + + # Issue 52974 - closed channels with exceptions + # must be thrown on iteration, if channel is empty + c = Channel(2) + put!(c, 5) + close(c, CustomError()) + @test take!(c) == 5 + @test_throws CustomError iterate(c) + + c = Channel(Inf) + put!(c, 1) + close(c) + @test take!(c) == 1 + @test_throws InvalidStateException take!(c) + @test_throws InvalidStateException put!(c, 5) + + c = Channel(3) + put!(c, 1) + close(c) + @test first(iterate(c)) == 1 + @test isnothing(iterate(c)) end # PR #36641