// 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. // compile-flags: -C no-prepopulate-passes #![crate_type="lib"] #![feature(repr_transparent, repr_simd)] use std::marker::PhantomData; pub struct Zst1; pub struct Zst2(()); #[repr(transparent)] pub struct F32(f32); // CHECK: define float @test_F32(float %arg0) #[no_mangle] pub extern fn test_F32(_: F32) -> F32 { loop {} } #[repr(transparent)] pub struct Ptr(*mut u8); // CHECK: define i8* @test_Ptr(i8* %arg0) #[no_mangle] pub extern fn test_Ptr(_: Ptr) -> Ptr { loop {} } #[repr(transparent)] pub struct WithZst(u64, Zst1); // CHECK: define i64 @test_WithZst(i64 %arg0) #[no_mangle] pub extern fn test_WithZst(_: WithZst) -> WithZst { loop {} } #[repr(transparent)] pub struct WithZeroSizedArray(*const f32, [i8; 0]); // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever. // CHECK: define i32* @test_WithZeroSizedArray(i32* %arg0) #[no_mangle] pub extern fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} } #[repr(transparent)] pub struct Generic(T); // CHECK: define double @test_Generic(double %arg0) #[no_mangle] pub extern fn test_Generic(_: Generic) -> Generic { loop {} } #[repr(transparent)] pub struct GenericPlusZst(T, Zst2); #[repr(u8)] pub enum Bool { True, False, FileNotFound } // CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %arg0) #[no_mangle] pub extern fn test_Gpz(_: GenericPlusZst) -> GenericPlusZst { loop {} } #[repr(transparent)] pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>); // CHECK: define i16* @test_LifetimePhantom(i16* %arg0) #[no_mangle] pub extern fn test_LifetimePhantom(_: LifetimePhantom) -> LifetimePhantom { loop {} } // This works despite current alignment resrictions because PhantomData is always align(1) #[repr(transparent)] pub struct UnitPhantom { val: T, unit: PhantomData } pub struct Px; // CHECK: define float @test_UnitPhantom(float %arg0) #[no_mangle] pub extern fn test_UnitPhantom(_: UnitPhantom) -> UnitPhantom { loop {} } #[repr(transparent)] pub struct TwoZsts(Zst1, i8, Zst2); // CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %arg0) #[no_mangle] pub extern fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} } #[repr(transparent)] pub struct Nested1(Zst2, Generic); // CHECK: define double @test_Nested1(double %arg0) #[no_mangle] pub extern fn test_Nested1(_: Nested1) -> Nested1 { loop {} } #[repr(transparent)] pub struct Nested2(Nested1, Zst1); // CHECK: define double @test_Nested2(double %arg0) #[no_mangle] pub extern fn test_Nested2(_: Nested2) -> Nested2 { loop {} } #[repr(simd)] struct f32x4(f32, f32, f32, f32); #[repr(transparent)] pub struct Vector(f32x4); // CHECK: define <4 x float> @test_Vector(<4 x float> %arg0) #[no_mangle] pub extern fn test_Vector(_: Vector) -> Vector { loop {} } trait Mirror { type It: ?Sized; } impl Mirror for T { type It = Self; } #[repr(transparent)] pub struct StructWithProjection(::It); // CHECK: define float @test_Projection(float %arg0) #[no_mangle] pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} } // The rest of this file tests newtypes around small aggregates on an ABI where small aggregates are // packed into one register. This is ABI-dependent, so instead we focus on one ABI and supply a // dummy definition for other ABIs to keep FileCheck happy. // // Bigger aggregates are tested in separate files called repr-transparent-aggregate-*.rs because // there, the expected LLVM IR function signatures vary so much that it's not reasonably possible to // cover all of them with a single CHECK line. Instead we group ABIs by the general "shape" of the // signature and have a separate test file for each bin. // // PS: You may be wondering why we don't just compare the return types and argument types for // equality with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on // newtypes containing aggregates. This is OK on all ABIs we support, but because LLVM has not // gotten rid of pointee types yet, the IR function signature will be syntactically different (%Foo* // vs %FooWrapper*). #[repr(C)] pub struct Rgb8 { r: u8, g: u8, b: u8 } #[repr(transparent)] pub struct Rgb8Wrap(Rgb8); // NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not // CHECK: define i32 @test_Rgb8Wrap(i32 #[no_mangle] #[cfg(all(target_arch="x86_64", target_os="linux"))] pub extern fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { loop {} } #[cfg(not(all(target_arch="x86_64", target_os="linux")))] #[no_mangle] pub extern fn test_Rgb8Wrap(_: u32) -> u32 { loop {} } // Same as with the small struct above: ABI-dependent, we only test the interesting case // (ABIs that pack the aggregate into a scalar) and stub it out on other ABIs #[repr(C)] pub union FloatBits { float: f32, bits: u32, } #[repr(transparent)] pub struct SmallUnion(FloatBits); // NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not // CHECK: define i32 @test_SmallUnion(i32 #[no_mangle] #[cfg(all(target_arch="x86_64", target_os="linux"))] pub extern fn test_SmallUnion(_: SmallUnion) -> SmallUnion { loop {} } #[cfg(not(all(target_arch="x86_64", target_os="linux")))] #[no_mangle] pub extern fn test_SmallUnion(_: u32) -> u32 { loop {} }