diff --git a/NEWS.md b/NEWS.md index 4dce228bc54b1..63d5f01b82351 100644 --- a/NEWS.md +++ b/NEWS.md @@ -67,6 +67,8 @@ Library improvements * New `ordschur` and `ordschur!` functions for sorting a schur factorization by the eigenvalues. * `deepcopy` recurses through immutable types and makes copies of their mutable fields ([#8560]). + + * `@simd` now rejects invalid control flow (`@goto` / break / continue) in the inner loop body at compile time ([#8624]). Julia v0.3.0 Release Notes ========================== diff --git a/base/simdloop.jl b/base/simdloop.jl index 139b10fded8ed..e73c85e8fa921 100644 --- a/base/simdloop.jl +++ b/base/simdloop.jl @@ -19,10 +19,26 @@ function parse_iteration_space(x) x.args # symbol, range end +# reject invalid control flow statements in @simd loop body +function check_body!(x::Expr) + if x.head === :break || x.head == :continue + throw(SimdError("$(x.head) is not allowed inside a @simd loop body")) + elseif x.head === :macrocall && x.args[1] === symbol("@goto") + throw(SimdError("$(x.args[1]) is not allowed inside a @simd loop body")) + end + for arg in x.args + check_body!(arg) + end + return true +end +check_body!(x::QuoteNode) = check_body!(x.value) +check_body!(x) = true + # Compile Expr x in context of @simd. function compile(x) (isa(x, Expr) && x.head == :for) || throw(SimdError("for loop expected")) length(x.args) == 2 || throw(SimdError("1D for loop expected")) + check_body!(x) var,range = parse_iteration_space(x.args[1]) r = gensym("r") # Range value diff --git a/test/simdloop.jl b/test/simdloop.jl index 713f664d9288c..a56c7234090c4 100644 --- a/test/simdloop.jl +++ b/test/simdloop.jl @@ -67,3 +67,26 @@ let j=4 end @test !simd_loop_local_present end + +import Base.SimdLoop.SimdError + +# Test that @simd rejects inner loop body with invalid control flow statements +# issue #8613 +@test_throws SimdError eval(:(begin + @simd for x = 1:10 + x == 1 && break + end +end)) + +@test_throws SimdError eval(:(begin + @simd for x = 1:10 + x < 5 && continue + end +end)) + +@test_throws SimdError eval(:(begin + @simd for x = 1:10 + x == 1 || @goto exit_loop + end + @label exit_loop +end))