зеркало из https://github.com/microsoft/clang.git
Introduce a new kind of derived-to-base cast which bypasses the need for
null checks, and make sure we elide null checks when accessing base class members. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99963 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
658f679b63
Коммит
23cba801e1
|
@ -1552,6 +1552,10 @@ public:
|
|||
/// CK_DerivedToBase - Derived to base class casts.
|
||||
CK_DerivedToBase,
|
||||
|
||||
/// CK_UncheckedDerivedToBase - Derived to base class casts that
|
||||
/// assume that the derived pointer is not null.
|
||||
CK_UncheckedDerivedToBase,
|
||||
|
||||
/// CK_Dynamic - Dynamic cast.
|
||||
CK_Dynamic,
|
||||
|
||||
|
|
|
@ -552,6 +552,8 @@ const char *CastExpr::getCastKindName() const {
|
|||
return "BaseToDerived";
|
||||
case CastExpr::CK_DerivedToBase:
|
||||
return "DerivedToBase";
|
||||
case CastExpr::CK_UncheckedDerivedToBase:
|
||||
return "UncheckedDerivedToBase";
|
||||
case CastExpr::CK_Dynamic:
|
||||
return "Dynamic";
|
||||
case CastExpr::CK_ToUnion:
|
||||
|
|
|
@ -2306,6 +2306,7 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
|
|||
case CastExpr::CK_AnyPointerToObjCPointerCast:
|
||||
case CastExpr::CK_AnyPointerToBlockPointerCast:
|
||||
case CastExpr::CK_DerivedToBase:
|
||||
case CastExpr::CK_UncheckedDerivedToBase:
|
||||
// Delegate to SValuator to process.
|
||||
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
|
||||
ExplodedNode* N = *I;
|
||||
|
|
|
@ -1637,6 +1637,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
|||
case CastExpr::CK_AnyPointerToObjCPointerCast:
|
||||
return EmitLValue(E->getSubExpr());
|
||||
|
||||
case CastExpr::CK_UncheckedDerivedToBase:
|
||||
case CastExpr::CK_DerivedToBase: {
|
||||
const RecordType *DerivedClassTy =
|
||||
E->getSubExpr()->getType()->getAs<RecordType>();
|
||||
|
|
|
@ -769,6 +769,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
|||
|
||||
static bool ShouldNullCheckClassCastValue(const CastExpr *CE) {
|
||||
const Expr *E = CE->getSubExpr();
|
||||
|
||||
if (CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase)
|
||||
return false;
|
||||
|
||||
if (isa<CXXThisExpr>(E)) {
|
||||
// We always assume that 'this' is never null.
|
||||
|
@ -826,6 +829,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
|
|||
return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
|
||||
NullCheckValue);
|
||||
}
|
||||
case CastExpr::CK_UncheckedDerivedToBase:
|
||||
case CastExpr::CK_DerivedToBase: {
|
||||
const RecordType *DerivedClassTy =
|
||||
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
|
||||
|
|
|
@ -1461,7 +1461,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
|
|||
|
||||
if (PointerConversions)
|
||||
QType = Context.getPointerType(QType);
|
||||
ImpCastExprToType(From, QType, CastExpr::CK_DerivedToBase,
|
||||
ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase,
|
||||
/*isLvalue*/ !PointerConversions);
|
||||
|
||||
FromType = QType;
|
||||
|
@ -1497,7 +1497,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
|
|||
QualType UType = URecordType;
|
||||
if (PointerConversions)
|
||||
UType = Context.getPointerType(UType);
|
||||
ImpCastExprToType(From, UType, CastExpr::CK_DerivedToBase,
|
||||
ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase,
|
||||
/*isLvalue*/ !PointerConversions);
|
||||
FromType = UType;
|
||||
FromRecordType = URecordType;
|
||||
|
@ -1517,8 +1517,8 @@ Sema::PerformObjectMemberConversion(Expr *&From,
|
|||
|
||||
// FIXME: isLvalue should be !PointerConversions here, but codegen
|
||||
// does very silly things.
|
||||
ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
|
||||
/*isLvalue=*/ true);
|
||||
ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase,
|
||||
/*isLvalue=*/ !PointerConversions);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,3 +44,43 @@ int f() {
|
|||
return A().foo();
|
||||
}
|
||||
}
|
||||
|
||||
namespace test4 {
|
||||
struct A {
|
||||
int x;
|
||||
};
|
||||
struct B {
|
||||
int x;
|
||||
void foo();
|
||||
};
|
||||
struct C : A, B {
|
||||
};
|
||||
|
||||
extern C *c_ptr;
|
||||
|
||||
// CHECK: define i32 @_ZN5test44testEv()
|
||||
int test() {
|
||||
// CHECK: load {{.*}} @_ZN5test45c_ptrE
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: getelementptr
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: call void @_ZN5test41B3fooEv
|
||||
c_ptr->B::foo();
|
||||
|
||||
// CHECK: load {{.*}} @_ZN5test45c_ptrE
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: getelementptr
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: getelementptr
|
||||
// CHECK-NEXT: store i32 5
|
||||
c_ptr->B::x = 5;
|
||||
|
||||
// CHECK: load {{.*}} @_ZN5test45c_ptrE
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: getelementptr
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: getelementptr
|
||||
// CHECK-NEXT: load i32*
|
||||
return c_ptr->B::x;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче