blob: 11b28ac038bc93735f5ef3c7b971c5155799288c [file] [log] [blame] [edit]
//@ compile-flags: -Z annotate-moves=1 -Copt-level=0 -g
#![crate_type = "lib"]
// Test with large array (non-struct type, Copy)
type LargeArray = [u64; 20]; // 160 bytes
#[derive(Clone, Default)]
struct NonCopyU64(u64);
// Test with Copy implementation
#[derive(Copy)]
struct ExplicitCopy {
data: [u64; 20], // 160 bytes
}
impl Clone for ExplicitCopy {
// CHECK-LABEL: <integration::ExplicitCopy as core::clone::Clone>::clone
fn clone(&self) -> Self {
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#EXPLICIT_COPY_LOC:]]
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#EXPLICIT_RETURN_LOC:]]
Self { data: self.data }
}
}
// Test with hand-implemented Clone (non-Copy)
struct NonCopyStruct {
data: [u64; 20], // 160 bytes
}
impl Clone for NonCopyStruct {
// CHECK-LABEL: <integration::NonCopyStruct as core::clone::Clone>::clone
fn clone(&self) -> Self {
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#CLONE_COPY_LOC:]]
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#CLONE_RETURN_LOC:]]
NonCopyStruct { data: self.data }
}
}
// CHECK-LABEL: integration::test_pure_assignment_move
pub fn test_pure_assignment_move() {
let arr: LargeArray = [42; 20];
// Arrays are initialized with a loop
// CHECK-NOT: call void @llvm.memcpy{{.*}}, !dbg ![[#]]
let _moved = arr;
}
// CHECK-LABEL: integration::test_pure_assignment_copy
pub fn test_pure_assignment_copy() {
let s = ExplicitCopy { data: [42; 20] };
// Arrays are initialized with a loop
// CHECK-NOT: call void @llvm.memcpy{{.*}}, !dbg ![[#]]
let _copied = s;
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#ASSIGN_COPY2_LOC:]]
let _copied_2 = s;
}
#[derive(Default)]
struct InitializeStruct {
field1: String,
field2: String,
field3: String,
}
// CHECK-LABEL: integration::test_init_struct
pub fn test_init_struct() {
let mut s = InitializeStruct::default();
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#INIT_STRUCT_LOC:]]
s = InitializeStruct {
field1: String::from("Hello"),
field2: String::from("from"),
field3: String::from("Rust"),
};
}
// CHECK-LABEL: integration::test_tuple_of_scalars
pub fn test_tuple_of_scalars() {
// Tuple of scalars (even if large) may use scalar-pair repr, so may not be annotated
let t: (u64, u64, u64, u64) = (1, 2, 3, 4); // 32 bytes
// Copied with explicit stores
// CHECK-NOT: call void @llvm.memcpy{{.*}}, !dbg ![[#]]
let _moved = t;
}
// CHECK-LABEL: integration::test_tuple_of_structs
pub fn test_tuple_of_structs() {
let s1 = NonCopyStruct { data: [1; 20] };
let s2 = NonCopyStruct { data: [2; 20] };
let tuple = (s1, s2); // Large tuple containing structs (320 bytes)
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#TUPLE_MOVE_LOC:]]
let _moved = tuple;
}
// CHECK-LABEL: integration::test_tuple_mixed
pub fn test_tuple_mixed() {
let s = NonCopyStruct { data: [1; 20] };
let tuple = (42u64, s); // Mixed tuple (168 bytes: 8 for u64 + 160 for struct)
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#MIXED_TUPLE_LOC:]]
let _moved = tuple;
}
// CHECK-LABEL: integration::test_explicit_copy_assignment
pub fn test_explicit_copy_assignment() {
let c1 = ExplicitCopy { data: [1; 20] };
// Initialized with loop
// CHECK-NOT: call void @llvm.memcpy{{.*}}, !dbg ![[#]]
let c2 = c1;
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#COPY2_LOC:]]
let _c3 = c1; // Can still use c1 (it was copied)
let _ = c2;
}
// CHECK-LABEL: integration::test_array_move
pub fn test_array_move() {
let arr: [String; 20] = std::array::from_fn(|i| i.to_string());
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#ARRAY_MOVE_LOC:]]
let _moved = arr;
}
// CHECK-LABEL: integration::test_array_in_struct_field
pub fn test_array_in_struct_field() {
let s = NonCopyStruct { data: [1; 20] };
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#FIELD_MOVE_LOC:]]
let data = s.data; // Move array field out of struct
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#FIELD_MOVE2_LOC:]]
let _moved = data;
}
// CHECK-LABEL: integration::test_clone_noncopy
pub fn test_clone_noncopy() {
let s = NonCopyStruct { data: [1; 20] };
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#CALL_CLONE_NONCOPY_LOC:]]
let _cloned = s.clone(); // The copy happens inside the clone() impl above
}
// CHECK-LABEL: integration::test_clone_explicit_copy
pub fn test_clone_explicit_copy() {
let c = ExplicitCopy { data: [1; 20] };
// Derived Clone on Copy type - the copy happens inside the generated clone impl
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#CALL_CLONE_COPY_LOC:]]
let _cloned = c.clone();
}
// CHECK-LABEL: integration::test_copy_ref
pub fn test_copy_ref(x: &ExplicitCopy) {
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#LOCAL_COPY_LOC:]]
let _local = *x;
}
// CHECK-DAG: ![[#EXPLICIT_COPY_LOC]] = !DILocation({{.*}}scope: ![[#EXPLICIT_COPY_SCOPE:]]
// CHECK-DAG: ![[#EXPLICIT_COPY_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_copy<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#EXPLICIT_RETURN_LOC]] = !DILocation({{.*}}scope: ![[#EXPLICIT_RETURN_SCOPE:]]
// CHECK-DAG: ![[#EXPLICIT_RETURN_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#CLONE_COPY_LOC]] = !DILocation({{.*}}scope: ![[#CLONE_COPY_SCOPE:]]
// CHECK-DAG: ![[#CLONE_COPY_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_copy<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#CLONE_RETURN_LOC]] = !DILocation({{.*}}scope: ![[#CLONE_RETURN_SCOPE:]]
// CHECK-DAG: ![[#CLONE_RETURN_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#ASSIGN_COPY2_LOC]] = !DILocation({{.*}}scope: ![[#ASSIGN_COPY2_SCOPE:]]
// CHECK-DAG: ![[#ASSIGN_COPY2_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#INIT_STRUCT_LOC]] = !DILocation({{.*}}scope: ![[#INIT_STRUCT_SCOPE:]]
// CHECK-DAG: ![[#INIT_STRUCT_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<alloc::string::String,{{ *[0-9]+}}>"
// CHECK-DAG: ![[#TUPLE_MOVE_LOC]] = !DILocation({{.*}}scope: ![[#TUPLE_MOVE_SCOPE:]]
// CHECK-DAG: ![[#TUPLE_MOVE_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#MIXED_TUPLE_LOC]] = !DILocation({{.*}}scope: ![[#MIXED_TUPLE_SCOPE:]]
// CHECK-DAG: ![[#MIXED_TUPLE_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#COPY2_LOC]] = !DILocation({{.*}}scope: ![[#COPY2_SCOPE:]]
// CHECK-DAG: ![[#COPY2_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#ARRAY_MOVE_LOC]] = !DILocation({{.*}}scope: ![[#ARRAY_MOVE_SCOPE:]]
// CHECK-DAG: ![[#ARRAY_MOVE_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)alloc::string::String[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#FIELD_MOVE_LOC]] = !DILocation({{.*}}scope: ![[#FIELD_MOVE_SCOPE:]]
// CHECK-DAG: ![[#FIELD_MOVE_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#FIELD_MOVE2_LOC]] = !DILocation({{.*}}scope: ![[#FIELD_MOVE2_SCOPE:]]
// CHECK-DAG: ![[#FIELD_MOVE2_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_copy<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#CALL_CLONE_NONCOPY_LOC]] = !DILocation({{.*}}scope: ![[#CALL_CLONE_NONCOPY_SCOPE:]]
// CHECK-DAG: ![[#CALL_CLONE_NONCOPY_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#CALL_CLONE_COPY_LOC]] = !DILocation({{.*}}scope: ![[#CALL_CLONE_COPY_SCOPE:]]
// CHECK-DAG: ![[#CALL_CLONE_COPY_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_move<{{(array\$<|\[)u64[,;].*}},{{ *[0-9]+}}>"
// CHECK-DAG: ![[#LOCAL_COPY_LOC]] = !DILocation({{.*}}scope: ![[#LOCAL_COPY_SCOPE:]]
// CHECK-DAG: ![[#LOCAL_COPY_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_copy<integration::ExplicitCopy,{{ *[0-9]+}}>"