Skip to content

Commit f3cf206

Browse files
committed
Auto merge of #43836 - taleks:issue-39827, r=arielb1
Fix for issue #39827 *Cause of the issue* While preparing for `trans_intrinsic_call()` invoke arguments are processed with `trans_argument()` method which excludes zero-sized types from argument list (to be more correct - all arguments for which `ArgKind` is `Ignore` are filtered out). As result `volatile_store()` intrinsic gets one argument instead of expected address and value. *How it is fixed* Modification of the `trans_argument()` method may cause side effects, therefore change was implemented in `volatile_store()` intrinsic building code itself. Now it checks function signature and if it was specialised with zero-sized type, then emits `C_nil()` instead of accessing non-existing second argument.
2 parents ab40a7c + faf6b84 commit f3cf206

File tree

4 files changed

+63
-4
lines changed

4 files changed

+63
-4
lines changed

src/libcore/intrinsics.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,20 +1044,23 @@ extern "rust-intrinsic" {
10441044
/// a size of `count` * `size_of::<T>()` and an alignment of
10451045
/// `min_align_of::<T>()`
10461046
///
1047-
/// The volatile parameter is set to `true`, so it will not be optimized out.
1047+
/// The volatile parameter is set to `true`, so it will not be optimized out
1048+
/// unless size is equal to zero.
10481049
pub fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
10491050
count: usize);
10501051
/// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with
10511052
/// a size of `count` * `size_of::<T>()` and an alignment of
10521053
/// `min_align_of::<T>()`
10531054
///
1054-
/// The volatile parameter is set to `true`, so it will not be optimized out.
1055+
/// The volatile parameter is set to `true`, so it will not be optimized out
1056+
/// unless size is equal to zero..
10551057
pub fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize);
10561058
/// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a
10571059
/// size of `count` * `size_of::<T>()` and an alignment of
10581060
/// `min_align_of::<T>()`.
10591061
///
1060-
/// The volatile parameter is set to `true`, so it will not be optimized out.
1062+
/// The volatile parameter is set to `true`, so it will not be optimized out
1063+
/// unless size is equal to zero.
10611064
pub fn volatile_set_memory<T>(dst: *mut T, val: u8, count: usize);
10621065

10631066
/// Perform a volatile load from the `src` pointer.

src/libcore/ptr.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,11 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
384384
/// over time. That being said, the semantics will almost always end up pretty
385385
/// similar to [C11's definition of volatile][c11].
386386
///
387+
/// The compiler shouldn't change the relative order or number of volatile
388+
/// memory operations. However, volatile memory operations on zero-sized types
389+
/// (e.g. if a zero-sized type is passed to `read_volatile`) are no-ops
390+
/// and may be ignored.
391+
///
387392
/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
388393
///
389394
/// # Safety
@@ -427,6 +432,11 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
427432
/// over time. That being said, the semantics will almost always end up pretty
428433
/// similar to [C11's definition of volatile][c11].
429434
///
435+
/// The compiler shouldn't change the relative order or number of volatile
436+
/// memory operations. However, volatile memory operations on zero-sized types
437+
/// (e.g. if a zero-sized type is passed to `write_volatile`) are no-ops
438+
/// and may be ignored.
439+
///
430440
/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
431441
///
432442
/// # Safety

src/librustc_trans/intrinsic.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,11 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
246246
let val = if fn_ty.args[1].is_indirect() {
247247
bcx.load(llargs[1], None)
248248
} else {
249-
from_immediate(bcx, llargs[1])
249+
if !type_is_zero_size(ccx, tp_ty) {
250+
from_immediate(bcx, llargs[1])
251+
} else {
252+
C_nil(ccx)
253+
}
250254
};
251255
let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to());
252256
let store = bcx.volatile_store(val, ptr);

src/test/run-pass/issue-39827.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
#![feature(core_intrinsics)]
11+
12+
use std::intrinsics::{ volatile_copy_memory, volatile_store, volatile_load,
13+
volatile_copy_nonoverlapping_memory,
14+
volatile_set_memory };
15+
16+
//
17+
// This test ensures that volatile intrinsics can be specialised with
18+
// zero-sized types and, in case of copy/set functions, can accept
19+
// number of elements equal to zero.
20+
//
21+
fn main () {
22+
let mut dst_pair = (1, 2);
23+
let src_pair = (3, 4);
24+
let mut dst_empty = ();
25+
let src_empty = ();
26+
27+
const COUNT_0: usize = 0;
28+
const COUNT_100: usize = 100;
29+
30+
unsafe {
31+
volatile_copy_memory(&mut dst_pair, &dst_pair, COUNT_0);
32+
volatile_copy_nonoverlapping_memory(&mut dst_pair, &src_pair, 0);
33+
volatile_copy_memory(&mut dst_empty, &dst_empty, 100);
34+
volatile_copy_nonoverlapping_memory(&mut dst_empty, &src_empty,
35+
COUNT_100);
36+
volatile_set_memory(&mut dst_empty, 0, COUNT_100);
37+
volatile_set_memory(&mut dst_pair, 0, COUNT_0);
38+
volatile_store(&mut dst_empty, ());
39+
volatile_store(&mut dst_empty, src_empty);
40+
volatile_load(&src_empty);
41+
}
42+
}

0 commit comments

Comments
 (0)