about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcore/intrinsics.rs9
-rw-r--r--src/libcore/ptr.rs10
-rw-r--r--src/librustc_trans/intrinsic.rs6
-rw-r--r--src/test/run-pass/issue-39827.rs42
4 files changed, 63 insertions, 4 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index fdca8d00d7a..ad776c8605a 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1044,20 +1044,23 @@ extern "rust-intrinsic" {
     /// a size of `count` * `size_of::<T>()` and an alignment of
     /// `min_align_of::<T>()`
     ///
-    /// 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<T>(dst: *mut T, src: *const T,
                                                   count: usize);
     /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with
     /// a size of `count` * `size_of::<T>()` and an alignment of
     /// `min_align_of::<T>()`
     ///
-    /// 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<T>(dst: *mut T, src: *const T, count: usize);
     /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a
     /// size of `count` * `size_of::<T>()` and an alignment of
     /// `min_align_of::<T>()`.
     ///
-    /// 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<T>(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 60cf1a20530..e35777d222c 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -384,6 +384,11 @@ pub unsafe fn write_unaligned<T>(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<T>(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 9956c28e641..033ef988571 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 00000000000..b753cf5844f
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
+    }
+}