diff options
author | John McCall <rjmccall@apple.com> | 2012-08-21 04:10:00 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2012-08-21 04:10:00 +0000 |
commit | 929bbfb0b69165b55da3c56abf22aa10e20dadc6 (patch) | |
tree | 3ef079c0dbd094349bc721d47a330a946272cdd0 | |
parent | db309ae1bfa7c30ed3b2b9e59a316b8fef2e56b6 (diff) |
When performing a trivial copy of a C++ type, we must be careful not
to overwrite objects that might have been allocated into the type's
tail padding. This patch is missing some potential optimizations where
the destination is provably a complete object, but it's necessary for
correctness.
Patch by Jonathan Sauer.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162254 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 4 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 21 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 4 | ||||
-rw-r--r-- | test/CodeGenObjCXX/implicit-copy-assign-operator.mm | 95 |
4 files changed, 108 insertions, 16 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index cad3ad2b5f..47827e93f5 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1427,6 +1427,10 @@ public: /// characters. This method does not work on incomplete types. CharUnits getTypeAlignInChars(QualType T) const; CharUnits getTypeAlignInChars(const Type *T) const; + + // getTypeInfoDataSizeInChars - Return the size of a type, in chars. If the + // type is a record, its data size is returned. + std::pair<CharUnits, CharUnits> getTypeInfoDataSizeInChars(QualType T) const; std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T) const; std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T) const; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 0452730201..7c685cf59a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1080,6 +1080,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { return toCharUnitsFromBits(Align); } +// getTypeInfoDataSizeInChars - Return the size of a type, in +// chars. If the type is a record, its data size is returned. This is +// the size of the memcpy that's performed when assigning this type +// using a trivial copy/move assignment operator. +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoDataSizeInChars(QualType T) const { + std::pair<CharUnits, CharUnits> sizeAndAlign = getTypeInfoInChars(T); + + // In C++, objects can sometimes be allocated into the tail padding + // of a base-class subobject. We decide whether that's possible + // during class layout, so here we can just trust the layout results. + if (getLangOpts().CPlusPlus) { + if (const RecordType *RT = T->getAs<RecordType>()) { + const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl()); + sizeAndAlign.first = layout.getDataSize(); + } + } + + return sizeAndAlign; +} + std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { std::pair<uint64_t, unsigned> Info = getTypeInfo(T); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 61f7362eca..287b6dd8c7 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -1300,9 +1300,9 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, // implementation handles this case safely. If there is a libc that does not // safely handle this, we can add a target hook. - // Get size and alignment info for this aggregate. + // Get data size and alignment info for this aggregate. std::pair<CharUnits, CharUnits> TypeInfo = - getContext().getTypeInfoInChars(Ty); + getContext().getTypeInfoDataSizeInChars(Ty); if (alignment.isZero()) alignment = TypeInfo.second; diff --git a/test/CodeGenObjCXX/implicit-copy-assign-operator.mm b/test/CodeGenObjCXX/implicit-copy-assign-operator.mm index 29ec9acd38..a5ce789609 100644 --- a/test/CodeGenObjCXX/implicit-copy-assign-operator.mm +++ b/test/CodeGenObjCXX/implicit-copy-assign-operator.mm @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -fobjc-gc -emit-llvm -triple x86_64-apple-darwin10.0.0 -fobjc-runtime=macosx-fragile-10.5 -o - %s | FileCheck %s +// RUN: %clang_cc1 -fobjc-gc -emit-llvm -triple x86_64-apple-darwin10.0.0 -fobjc-runtime=macosx-fragile-10.5 -o - %s | FileCheck %s -check-prefix=CHECK-OBJ +// RUN: %clang_cc1 -x c++ -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s -check-prefix=CHECK-CPP +#ifdef __OBJC__ struct A { A &operator=(const A&); A &operator=(A&); @@ -41,17 +43,82 @@ void test_D(D d1, D d2) { d1 = d2; } -// CHECK: define linkonce_odr %struct.D* @_ZN1DaSERS_ -// CHECK: {{call.*_ZN1AaSERS_}} -// CHECK: {{call.*_ZN1BaSERS_}} -// CHECK: {{call.*_ZN1CaSERKS_}} -// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}} -// CHECK: {{call.*_ZN1BaSERS_}} -// CHECK: br -// CHECK: {{call.*_ZN1CaSERKS_}} -// CHECK: {{call.*@objc_memmove_collectable}} -// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}} -// CHECK: call void @_ZN11CopyByValueC1ERKS_ -// CHECK: {{call.*_ZN11CopyByValueaSES_}} -// CHECK: ret +// CHECK-OBJ: define linkonce_odr %struct.D* @_ZN1DaSERS_ +// CHECK-OBJ: {{call.*_ZN1AaSERS_}} +// CHECK-OBJ: {{call.*_ZN1BaSERS_}} +// CHECK-OBJ: {{call.*_ZN1CaSERKS_}} +// CHECK-OBJ: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}} +// CHECK-OBJ: {{call.*_ZN1BaSERS_}} +// CHECK-OBJ: br +// CHECK-OBJ: {{call.*_ZN1CaSERKS_}} +// CHECK-OBJ: {{call.*@objc_memmove_collectable}} +// CHECK-OBJ: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}} +// CHECK-OBJ: call void @_ZN11CopyByValueC1ERKS_ +// CHECK-OBJ: {{call.*_ZN11CopyByValueaSES_}} +// CHECK-OBJ: ret +#endif +namespace PR13329 { +#ifndef __OBJC__ + typedef void* id; +#endif + struct POD { + id i; + short s; + }; + + struct NonPOD { + id i; + short s; + + NonPOD(); + }; + + struct DerivedNonPOD: NonPOD { + char c; + }; + + struct DerivedPOD: POD { + char c; + }; + + void testPOD() { + POD a; + POD b; + // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 16 + // CHECK-CPP: @llvm.memcpy{{.*}}i64 16 + b = a; + } + + void testNonPOD() { + NonPOD a; + NonPOD b; + // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 10 + // CHECK-CPP: @llvm.memcpy{{.*}}i64 10 + b = a; + } + + void testDerivedNonPOD() { + DerivedNonPOD a; + NonPOD b; + DerivedNonPOD c; + // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 10 + // CHECK-CPP: @llvm.memcpy{{.*}}i64 10 + (NonPOD&) a = b; + // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 11 + // CHECK-CPP: @llvm.memcpy{{.*}}i64 11 + a = c; + }; + + void testDerivedPOD() { + DerivedPOD a; + POD b; + DerivedPOD c; + // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 16 + // CHECK-CPP: @llvm.memcpy{{.*}}i64 16 + (POD&) a = b; + // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 17 + // CHECK-CPP: @llvm.memcpy{{.*}}i64 17 + a = c; + }; +} |