diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fdca8d00d7a75..ad776c8605ac8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1044,20 +1044,23 @@ extern "rust-intrinsic" { /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` /// - /// The volatile parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero. pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` /// - /// The volatile parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero.. pub fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a /// size of `count` * `size_of::()` and an alignment of /// `min_align_of::()`. /// - /// The volatile parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero. pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); /// Perform a volatile load from the `src` pointer. diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 60cf1a2053068..e35777d222c06 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -384,6 +384,11 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// over time. That being said, the semantics will almost always end up pretty /// similar to [C11's definition of volatile][c11]. /// +/// The compiler shouldn't change the relative order or number of volatile +/// memory operations. However, volatile memory operations on zero-sized types +/// (e.g. if a zero-sized type is passed to `read_volatile`) are no-ops +/// and may be ignored. +/// /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf /// /// # Safety @@ -427,6 +432,11 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// over time. That being said, the semantics will almost always end up pretty /// similar to [C11's definition of volatile][c11]. /// +/// The compiler shouldn't change the relative order or number of volatile +/// memory operations. However, volatile memory operations on zero-sized types +/// (e.g. if a zero-sized type is passed to `write_volatile`) are no-ops +/// and may be ignored. +/// /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf /// /// # Safety diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 9956c28e64121..033ef988571dd 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -246,7 +246,11 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let val = if fn_ty.args[1].is_indirect() { bcx.load(llargs[1], None) } else { - from_immediate(bcx, llargs[1]) + if !type_is_zero_size(ccx, tp_ty) { + from_immediate(bcx, llargs[1]) + } else { + C_nil(ccx) + } }; let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to()); let store = bcx.volatile_store(val, ptr); diff --git a/src/test/run-pass/issue-39827.rs b/src/test/run-pass/issue-39827.rs new file mode 100644 index 0000000000000..b753cf5844fa9 --- /dev/null +++ b/src/test/run-pass/issue-39827.rs @@ -0,0 +1,42 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(core_intrinsics)] + +use std::intrinsics::{ volatile_copy_memory, volatile_store, volatile_load, + volatile_copy_nonoverlapping_memory, + volatile_set_memory }; + +// +// This test ensures that volatile intrinsics can be specialised with +// zero-sized types and, in case of copy/set functions, can accept +// number of elements equal to zero. +// +fn main () { + let mut dst_pair = (1, 2); + let src_pair = (3, 4); + let mut dst_empty = (); + let src_empty = (); + + const COUNT_0: usize = 0; + const COUNT_100: usize = 100; + + unsafe { + volatile_copy_memory(&mut dst_pair, &dst_pair, COUNT_0); + volatile_copy_nonoverlapping_memory(&mut dst_pair, &src_pair, 0); + volatile_copy_memory(&mut dst_empty, &dst_empty, 100); + volatile_copy_nonoverlapping_memory(&mut dst_empty, &src_empty, + COUNT_100); + volatile_set_memory(&mut dst_empty, 0, COUNT_100); + volatile_set_memory(&mut dst_pair, 0, COUNT_0); + volatile_store(&mut dst_empty, ()); + volatile_store(&mut dst_empty, src_empty); + volatile_load(&src_empty); + } +}