diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 41 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/catch-undef-behavior.cpp | 87 |
2 files changed, 118 insertions, 10 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 4eb27c3d540..392fe85f64f 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -741,6 +741,29 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { } namespace { + /// RAII object to indicate that codegen is copying the value representation + /// instead of the object representation. Useful when copying a struct or + /// class which has uninitialized members and we're only performing + /// lvalue-to-rvalue conversion on the object but not its members. + class CopyingValueRepresentation { + public: + explicit CopyingValueRepresentation(CodeGenFunction &CGF) + : CGF(CGF), SO(*CGF.SanOpts), OldSanOpts(CGF.SanOpts) { + SO.Bool = false; + SO.Enum = false; + CGF.SanOpts = &SO; + } + ~CopyingValueRepresentation() { + CGF.SanOpts = OldSanOpts; + } + private: + CodeGenFunction &CGF; + SanitizerOptions SO; + const SanitizerOptions *OldSanOpts; + }; +} + +namespace { class FieldMemcpyizer { public: FieldMemcpyizer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, @@ -939,9 +962,10 @@ namespace { if (AggregatedInits.size() <= 1) { // This memcpy is too small to be worthwhile. Fall back on default // codegen. - for (unsigned i = 0; i < AggregatedInits.size(); ++i) { + if (!AggregatedInits.empty()) { + CopyingValueRepresentation CVR(CGF); EmitMemberInitializer(CGF, ConstructorDecl->getParent(), - AggregatedInits[i], ConstructorDecl, Args); + AggregatedInits[0], ConstructorDecl, Args); } reset(); return; @@ -980,8 +1004,8 @@ namespace { private: // Returns the memcpyable field copied by the given statement, if one - // exists. Otherwise r - FieldDecl* getMemcpyableField(Stmt *S) { + // exists. Otherwise returns null. + FieldDecl *getMemcpyableField(Stmt *S) { if (!AssignmentsMemcpyable) return 0; if (BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) { @@ -1075,8 +1099,10 @@ namespace { void emitAggregatedStmts() { if (AggregatedStmts.size() <= 1) { - for (unsigned i = 0; i < AggregatedStmts.size(); ++i) - CGF.EmitStmt(AggregatedStmts[i]); + if (!AggregatedStmts.empty()) { + CopyingValueRepresentation CVR(CGF); + CGF.EmitStmt(AggregatedStmts[0]); + } reset(); } @@ -1672,8 +1698,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, EmitAggregateCopy(This, Src, (*ArgBeg)->getType()); return; } - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, - clang::Ctor_Complete); + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, clang::Ctor_Complete); assert(D->isInstance() && "Trying to emit a member call expr on a static method!"); diff --git a/clang/test/CodeGenCXX/catch-undef-behavior.cpp b/clang/test/CodeGenCXX/catch-undef-behavior.cpp index 217c3fdb0fe..c949506d4ef 100644 --- a/clang/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/clang/test/CodeGenCXX/catch-undef-behavior.cpp @@ -340,7 +340,7 @@ class C : public A, public B // align=16 // offset. The pointer before subtraction doesn't need to be aligned for // the destination type. -// CHECK-LABEL-LABEL: define void @_Z16downcast_pointerP1B(%class.B* %b) +// CHECK-LABEL: define void @_Z16downcast_pointerP1B(%class.B* %b) void downcast_pointer(B *b) { (void) static_cast<C*>(b); // Alignment check from EmitTypeCheck(TCK_DowncastPointer, ...) @@ -357,7 +357,7 @@ void downcast_pointer(B *b) { // CHECK-NEXT: br i1 [[AND]] } -// CHECK-LABEL-LABEL: define void @_Z18downcast_referenceR1B(%class.B* %b) +// CHECK-LABEL: define void @_Z18downcast_referenceR1B(%class.B* %b) void downcast_reference(B &b) { (void) static_cast<C&>(b); // Alignment check from EmitTypeCheck(TCK_DowncastReference, ...) @@ -372,4 +372,87 @@ void downcast_reference(B &b) { // CHECK-NEXT: br i1 [[AND]] } +namespace CopyValueRepresentation { + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S3aSERKS0_ + // CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S4aSEOS0_ + // CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S5C2ERKS0_ + // CHECK-NOT: call {{.*}} __ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S2C2ERKS0_ + // CHECK: __ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S1C2ERKS0_ + // CHECK-NOT: call {{.*}} __ubsan_handle_load_invalid_value + + struct CustomCopy { CustomCopy(); CustomCopy(const CustomCopy&); }; + struct S1 { + CustomCopy CC; + bool b; + }; + void callee1(S1); + void test1() { + S1 s11; + callee1(s11); + S1 s12; + s12 = s11; + } + + static bool some_global_bool; + struct ExprCopy { + ExprCopy(); + ExprCopy(const ExprCopy&, bool b = some_global_bool); + }; + struct S2 { + ExprCopy EC; + bool b; + }; + void callee2(S2); + void test2(void) { + S2 s21; + callee2(s21); + S2 s22; + s22 = s21; + } + + struct CustomAssign { CustomAssign &operator=(const CustomAssign&); }; + struct S3 { + CustomAssign CA; + bool b; + }; + void test3() { + S3 x, y; + x = y; + } + + struct CustomMove { + CustomMove(); + CustomMove(const CustomMove&&); + CustomMove &operator=(const CustomMove&&); + }; + struct S4 { + CustomMove CM; + bool b; + }; + void test4() { + S4 x, y; + x = static_cast<S4&&>(y); + } + + struct EnumCustomCopy { + EnumCustomCopy(); + EnumCustomCopy(const EnumCustomCopy&); + }; + struct S5 { + EnumCustomCopy ECC; + bool b; + }; + void callee5(S5); + void test5() { + S5 s51; + callee5(s51); + S5 s52; + s52 = s51; + } +} + // CHECK: attributes [[NR_NUW]] = { noreturn nounwind } |