--- /dev/null
+// ignore-windows: Concurrency on Windows is not supported yet.
+
+// Check that we terminate the program when the main thread terminates.
+
+//~^^^^ ERROR: unsupported operation: the main thread terminated without waiting for other threads
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::{mem, ptr};
+
+extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
+ ptr::null_mut()
+}
+
+fn main() {
+ unsafe {
+ let mut native: libc::pthread_t = mem::zeroed();
+ let attr: libc::pthread_attr_t = mem::zeroed();
+ // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
+ assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
+ }
+}
--- /dev/null
+// ignore-windows: Concurrency on Windows is not supported yet.
+
+// Joining a detached thread is undefined behavior.
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::{mem, ptr};
+
+extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
+ ptr::null_mut()
+}
+
+fn main() {
+ unsafe {
+ let mut native: libc::pthread_t = mem::zeroed();
+ let attr: libc::pthread_attr_t = mem::zeroed();
+ // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
+ assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
+ assert_eq!(libc::pthread_detach(native), 0);
+ assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread
+ }
+}
--- /dev/null
+// ignore-windows: Concurrency on Windows is not supported yet.
+
+// Joining an already joined thread is undefined behavior.
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::{mem, ptr};
+
+extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
+ ptr::null_mut()
+}
+
+fn main() {
+ unsafe {
+ let mut native: libc::pthread_t = mem::zeroed();
+ let attr: libc::pthread_attr_t = mem::zeroed();
+ // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
+ assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
+ assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
+ assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread
+ }
+}
--- /dev/null
+// ignore-windows: Concurrency on Windows is not supported yet.
+
+// Joining the same thread multiple times is undefined behavior.
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::thread;
+use std::{mem, ptr};
+
+extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
+ ptr::null_mut()
+}
+
+fn main() {
+ unsafe {
+ let mut native: libc::pthread_t = mem::zeroed();
+ let attr: libc::pthread_attr_t = mem::zeroed();
+ // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
+ assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
+ let mut native_copy: libc::pthread_t = mem::zeroed();
+ ptr::copy_nonoverlapping(&native, &mut native_copy, 1);
+ let handle = thread::spawn(move || {
+ assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread
+ });
+ assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
+ handle.join().unwrap();
+ }
+}
--- /dev/null
+// ignore-windows: Concurrency on Windows is not supported yet.
+
+// Joining itself is undefined behavior.
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::ptr;
+
+fn main() {
+ unsafe {
+ let native: libc::pthread_t = libc::pthread_self();
+ assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join itself
+ }
+}