| // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s -o - | FileCheck %s | |
| union U { | |
| int a; | |
| float b; | |
| }; | |
| // Odr-use both defaulted assignment operators out of line so their bodies are | |
| // emitted (a trivial assignment at a call site is otherwise memcpy'd directly). | |
| auto get_copy = static_cast<U &(U::*)(const U &)>(&U::operator=); | |
| auto get_move = static_cast<U &(U::*)(U &&)>(&U::operator=); | |
| // Exactly one whole-object memcpy per assignment body. | |
| // CHECK-LABEL: define linkonce_odr noundef nonnull align 4 dereferenceable(4) ptr @_ZN1UaSERKS_(ptr noundef nonnull align 4 dereferenceable(4) %{{.+}}, ptr noundef nonnull align 4 dereferenceable(4) %{{.+}}) | |
| // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr align 4 %{{.+}}, i64 4, i1 false) | |
| // CHECK-NOT: memcpy | |
| // CHECK: ret ptr | |
| // CHECK-LABEL: define linkonce_odr noundef nonnull align 4 dereferenceable(4) ptr @_ZN1UaSEOS_(ptr noundef nonnull align 4 dereferenceable(4) %{{.+}}, ptr noundef nonnull align 4 dereferenceable(4) %{{.+}}) | |
| // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr align 4 %{{.+}}, i64 4, i1 false) | |
| // CHECK-NOT: memcpy | |
| // CHECK: ret ptr | |
| union Padded { | |
| int a; | |
| char b[5]; | |
| }; | |
| // sizeof(Padded) == 8, so the whole-object copy includes the tail padding. | |
| auto get_copy_padded = static_cast<Padded &(Padded::*)(const Padded &)>(&Padded::operator=); | |
| // CHECK-LABEL: define linkonce_odr noundef nonnull align 4 dereferenceable(8) ptr @_ZN6PaddedaSERKS_(ptr noundef nonnull align 4 dereferenceable(8) %{{.+}}, ptr noundef nonnull align 4 dereferenceable(8) %{{.+}}) | |
| // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr align 4 %{{.+}}, i64 8, i1 false) | |
| // CHECK-NOT: memcpy | |
| // CHECK: ret ptr | |
| struct WithNamedUnion { | |
| U u; | |
| int x; | |
| }; | |
| // A named union member is copied as part of the containing class's defaulted | |
| // assignment. | |
| void assign_named(WithNamedUnion *d, const WithNamedUnion *s) { *d = *s; } | |
| // CHECK-LABEL: define dso_local void @_Z12assign_namedP14WithNamedUnionPKS_(ptr noundef %{{.+}}, ptr noundef %{{.+}}) | |
| // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr align 4 %{{.+}}, i64 8, i1 false) | |
| struct WithAnonUnion { | |
| union { | |
| int a; | |
| float b; | |
| }; | |
| int x; | |
| }; | |
| // An anonymous union member is likewise copied. | |
| void assign_anon(WithAnonUnion *d, const WithAnonUnion *s) { *d = *s; } | |
| // CHECK-LABEL: define dso_local void @_Z11assign_anonP13WithAnonUnionPKS_(ptr noundef %{{.+}}, ptr noundef %{{.+}}) | |
| // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr align 4 %{{.+}}, i64 8, i1 false) |