diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 73824afc17ef..0e87d8311c18 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2764,18 +2764,18 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); - // C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is - // performed and the object is not of the derived type. - if (SanitizePerformTypeCheck) - EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(), - LV.getAddress(), E->getType()); - // Perform the base-to-derived conversion llvm::Value *Derived = GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl, E->path_begin(), E->path_end(), /*NullCheckValue=*/false); + // C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is + // performed and the object is not of the derived type. + if (SanitizePerformTypeCheck) + EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(), + Derived, E->getType()); + return MakeAddrLValue(Derived, E->getType()); } case CK_LValueBitCast: { diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index b6bda2847173..287dc6c02315 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1234,15 +1234,18 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { llvm::Value *V = Visit(E); + llvm::Value *Derived = + CGF.GetAddressOfDerivedClass(V, DerivedClassDecl, + CE->path_begin(), CE->path_end(), + ShouldNullCheckClassCastValue(CE)); + // C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is // performed and the object is not of the derived type. if (CGF.SanitizePerformTypeCheck) CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(), - V, DestTy->getPointeeType()); + Derived, DestTy->getPointeeType()); - return CGF.GetAddressOfDerivedClass(V, DerivedClassDecl, - CE->path_begin(), CE->path_end(), - ShouldNullCheckClassCastValue(CE)); + return Derived; } case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { diff --git a/clang/test/CodeGenCXX/catch-undef-behavior.cpp b/clang/test/CodeGenCXX/catch-undef-behavior.cpp index d6d0edfa1edb..6079dcdf0dba 100644 --- a/clang/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/clang/test/CodeGenCXX/catch-undef-behavior.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,bounds -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,bounds -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s struct S { double d; @@ -321,4 +321,55 @@ char string_index(int n) { return "Hello"[n]; } +class A // align=4 +{ + int a1, a2, a3; +}; + +class B // align=8 +{ + long b1, b2; +}; + +class C : public A, public B // align=16 +{ + alignas(16) int c1; +}; + +// Make sure we check the alignment of the pointer after subtracting any +// offset. The pointer before subtraction doesn't need to be aligned for +// the destination type. + +// CHECK-LABEL: define void @_Z16downcast_pointerP1B(%class.B* %b) +void downcast_pointer(B *b) { + (void) static_cast(b); + // Alignment check from EmitTypeCheck(TCK_DowncastPointer, ...) + // CHECK: [[SUB:%sub[.a-z0-9]*]] = getelementptr i8* {{.*}}, i64 -16 + // CHECK-NEXT: [[C:%[0-9]*]] = bitcast i8* [[SUB]] to %class.C* + // null check goes here + // CHECK: [[FROM_PHI:%[0-9]*]] = phi %class.C* [ [[C]], %cast.notnull ], {{.*}} + // Objectsize check goes here + // CHECK: [[C_INT:%[0-9]*]] = ptrtoint %class.C* [[FROM_PHI]] to i64 + // CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15 + // CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0 + // AND the alignment test with the objectsize test. + // CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]] + // CHECK-NEXT: br i1 [[AND]], label %cont, label %handler.type_mismatch +} + +// CHECK-LABEL: define void @_Z18downcast_referenceR1B(%class.B* %b) +void downcast_reference(B &b) { + (void) static_cast(b); + // Alignment check from EmitTypeCheck(TCK_DowncastReference, ...) + // CHECK: [[SUB:%sub[.a-z0-9]*]] = getelementptr i8* {{.*}}, i64 -16 + // CHECK-NEXT: [[C:%[0-9]*]] = bitcast i8* [[SUB]] to %class.C* + // Objectsize check goes here + // CHECK: [[C_INT:%[0-9]*]] = ptrtoint %class.C* [[C]] to i64 + // CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15 + // CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0 + // AND the alignment test with the objectsize test. + // CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]] + // CHECK-NEXT: br i1 [[AND]], label %cont, label %handler.type_mismatch +} + // CHECK: attributes [[NR_NUW]] = { noreturn nounwind }