W1036
W1036 — Adropcallssendorrecv, which wait with no time limit of their own, outside awithinblock. A drop runs with cancellation off, so when the other end never acts, the wait holds up the drop until the limit of the drop: its type'swait_limit, 10 seconds by default. Then the wait gives up, as in a cancelled block. Await_limitthat calls them gets the warning too, because it runs before the drop and should only return a number.
What the compiler reports
Warning[W1036] at {{.*}}a_drop_that_waits_with_no_time_limit.vx:[[@LINE+15]]:{{[0-9]+}}: 'send' waits with no time limit of its own in a 'drop'. A drop runs with cancellation off, so if the other end of the channel never acts, this wait holds up the drop until the limit of the drop: its type's 'wait_limit', 10 seconds by default. Use 'send_for' with a time limit, or put the wait in a 'within' block
Warning[W1036] at {{.*}}a_drop_that_waits_with_no_time_limit.vx:[[@LINE+15]]:{{[0-9]+}}: 'recv' waits with no time limit of its own in a 'drop'. {{.*}} Use 'recv_for' with a time limit
Warning[W1036] at {{.*}}a_drop_that_waits_with_no_time_limit.vx:[[@LINE+26]]:{{[0-9]+}}: 'recv' waits in 'wait_limit'. 'wait_limit' runs before the drop, to say how long its waits can take, so it should return a number and not wait
The fragments the test suite holds the compiler to. An ellipsis marks text the test does not constrain; the emitted message also carries a source location.
A program that triggers it
//
// Part of the Vx Project, under the Apache License v2.0 with LLVM Exceptions.
// See LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// A `drop` runs with cancellation off, so a `send` or `recv` in it can wait until the limit of the
// drop. The compiler warns about each one (W1036). `send_for` and `recv_for` have a time limit, and
// the same `send` in a normal method gets no warning. A wait in a `within` block has the block's
// limit, so it gets no warning. `wait_limit` should only return a number, so a wait in it gets
// the warning too.
//
import std::sync::channel;
struct SlotGuard {
slot : i64,
to_pool : Sender<i64>,
from_pool : Receiver<i64>,
}
impl Drop for SlotGuard {
fn drop(self : &mut SlotGuard) -> void {
// Each of these two calls waits with no time limit.
let _sent = self.to_pool.send(self.slot);
let _got = self.from_pool.recv();
// These two calls have a time limit.
let _sent_for = self.to_pool.send_for(self.slot, 0.1);
let _got_for = self.from_pool.recv_for(0.1);
// So does this one: the limit of its block.
within(0.1) {
let _got_within = self.from_pool.recv();
}
}
fn wait_limit(self : &SlotGuard) -> f64 {
// This call waits before the drop starts.
let _got = self.from_pool.recv();
return 0.5;
}
}
impl SlotGuard {
fn give_back(self : &SlotGuard) -> void {
// Not a drop, so a cancel can stop this wait.
let _sent = self.to_pool.send(self.slot);
}
}
fn main() -> i32 {
let (tx, rx) = channel<i64>(4);
let g = SlotGuard {
slot: 1, to_pool: tx, from_pool: rx
};
g.give_back();
return 0;
}
From tests/frontend/pass/a_drop_that_waits_with_no_time_limit.vx, which asserts this diagnostic on every commit.
Related
A tour of VxThe chapter covering the rule this code enforces.
All diagnosticsEvery code the compiler can emit, grouped by stage.
W1035A
match arm in a loop or while can take Cancelled from a wait and stays in the loop. In a cancelled task each wait gives Cancelled at once, so the loop never ends (F4).