diff options
-rw-r--r-- | include/clang/AST/OperationKinds.h | 9 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 7 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.cpp | 26 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 18 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGExprComplex.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 122 | ||||
-rw-r--r-- | lib/Sema/SemaCast.cpp | 3 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineC.cpp | 1 | ||||
-rw-r--r-- | test/CodeGenCXX/member-function-pointers.cpp | 40 |
14 files changed, 197 insertions, 44 deletions
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h index 8348033846..8cf79b2bfa 100644 --- a/include/clang/AST/OperationKinds.h +++ b/include/clang/AST/OperationKinds.h @@ -117,6 +117,15 @@ enum CastKind { /// against the null member pointer. CK_MemberPointerToBoolean, + /// CK_ReinterpretMemberPointer - Reinterpret a member pointer as a + /// different kind of member pointer. C++ forbids this from + /// crossing between function and object types, but otherwise does + /// not restrict it. However, the only operation that is permitted + /// on a "punned" member pointer is casting it back to the original + /// type, which is required to be a lossless operation (although + /// many ABIs do not guarantee this on all possible intermediate types). + CK_ReinterpretMemberPointer, + /// CK_UserDefinedConversion - Conversion using a user defined type /// conversion function. /// struct A { operator int(); }; int i = int(A()); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 5b511cc883..f9f7ba542c 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1053,6 +1053,11 @@ void CastExpr::CheckCastConsistency() const { assert(getSubExpr()->getType()->isBlockPointerType()); goto CheckNoBasePath; + case CK_ReinterpretMemberPointer: + assert(getType()->isMemberPointerType()); + assert(getSubExpr()->getType()->isMemberPointerType()); + goto CheckNoBasePath; + case CK_BitCast: // Arbitrary casts to C pointer types count as bitcasts. // Otherwise, we should only have block and ObjC pointer casts @@ -1156,6 +1161,8 @@ const char *CastExpr::getCastKindName() const { return "BaseToDerivedMemberPointer"; case CK_DerivedToBaseMemberPointer: return "DerivedToBaseMemberPointer"; + case CK_ReinterpretMemberPointer: + return "ReinterpretMemberPointer"; case CK_UserDefinedConversion: return "UserDefinedConversion"; case CK_ConstructorConversion: diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index e33ca6dc65..6ad9938906 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -4974,6 +4974,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_NullToMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: + case CK_ReinterpretMemberPointer: case CK_ConstructorConversion: case CK_IntegralToPointer: case CK_ToVoid: @@ -5450,6 +5451,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: case CK_ConstructorConversion: case CK_IntegralToPointer: case CK_PointerToIntegral: diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index e5d3f2da6b..fc3f45d75b 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -71,6 +71,11 @@ llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, return GetBogusMemberPointer(CGM, E->getType()); } +llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E, + llvm::Constant *Src) { + return GetBogusMemberPointer(CGM, E->getType()); +} + llvm::Value * CGCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, llvm::Value *L, @@ -172,3 +177,24 @@ void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, bool PerformInit) { ErrorUnsupportedABI(CGF, "static local variable initialization"); } + +/// Returns the adjustment, in bytes, required for the given +/// member-pointer operation. Returns null if no adjustment is +/// required. +llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) { + assert(E->getCastKind() == CK_DerivedToBaseMemberPointer || + E->getCastKind() == CK_BaseToDerivedMemberPointer); + + QualType derivedType; + if (E->getCastKind() == CK_DerivedToBaseMemberPointer) + derivedType = E->getSubExpr()->getType(); + else + derivedType = E->getType(); + + const CXXRecordDecl *derivedClass = + derivedType->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl(); + + return CGM.GetNonVirtualBaseClassOffset(derivedClass, + E->path_begin(), + E->path_end()); +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 4bacd01403..4e045f5f32 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -100,12 +100,17 @@ public: llvm::Value *MemPtr, const MemberPointerType *MPT); - /// Perform a derived-to-base or base-to-derived member pointer - /// conversion. + /// Perform a derived-to-base, base-to-derived, or bitcast member + /// pointer conversion. virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, const CastExpr *E, llvm::Value *Src); + /// Perform a derived-to-base, base-to-derived, or bitcast member + /// pointer conversion on a constant value. + virtual llvm::Constant *EmitMemberPointerConversion(const CastExpr *E, + llvm::Constant *Src); + /// Return true if the given member pointer can be zero-initialized /// (in the C++ sense) with an LLVM zeroinitializer. virtual bool isZeroInitializable(const MemberPointerType *MPT); @@ -137,6 +142,15 @@ public: llvm::Value *MemPtr, const MemberPointerType *MPT); +protected: + /// A utility method for computing the offset required for the given + /// base-to-derived or derived-to-base member-pointer conversion. + /// Does not handle virtual conversions (in case we ever fully + /// support an ABI that allows this). Returns null if no adjustment + /// is required. + llvm::Constant *getMemberPointerAdjustment(const CastExpr *E); + +public: /// Build the signature of the given constructor variant by adding /// any required parameters. For convenience, ResTy has been /// initialized to 'void', and ArgTys has been initialized with the diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 95bed1b0e6..f67025a32c 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -2090,6 +2090,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_DerivedToBaseMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: case CK_AnyPointerToBlockPointerCast: case CK_ARCProduceObject: case CK_ARCConsumeObject: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index a85cb9dbc3..91f9db0bfe 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -360,6 +360,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: case CK_IntegralToPointer: case CK_PointerToIntegral: case CK_PointerToBoolean: diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 53f7d65ef1..15fa225eb8 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -388,6 +388,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: case CK_ConstructorConversion: case CK_IntegralToPointer: case CK_PointerToIntegral: diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 44531c0992..985e53227e 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -620,6 +620,11 @@ public: case CK_Dependent: llvm_unreachable("saw dependent cast!"); + case CK_ReinterpretMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_BaseToDerivedMemberPointer: + return CGM.getCXXABI().EmitMemberPointerConversion(E, C); + // These will never be supported. case CK_ObjCObjectLValueCast: case CK_ARCProduceObject: @@ -630,18 +635,16 @@ public: // These don't need to be handled here because Evaluate knows how to // evaluate them in the cases where they can be folded. + case CK_BitCast: case CK_ToVoid: case CK_Dynamic: case CK_LValueBitCast: case CK_NullToMemberPointer: - case CK_DerivedToBaseMemberPointer: - case CK_BaseToDerivedMemberPointer: case CK_UserDefinedConversion: case CK_ConstructorConversion: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: - case CK_BitCast: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: case CK_BaseToDerived: diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index d9b0e21238..8bd4c2b5aa 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1122,6 +1122,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT); } + case CK_ReinterpretMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: { Value *Src = Visit(E); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index a8b9942882..8d06b6011c 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -73,6 +73,8 @@ public: llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, const CastExpr *E, llvm::Value *Src); + llvm::Constant *EmitMemberPointerConversion(const CastExpr *E, + llvm::Constant *Src); llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); @@ -312,7 +314,10 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, return Builder.CreateBitCast(Addr, PType); } -/// Perform a derived-to-base or base-to-derived member pointer conversion. +/// Perform a bitcast, derived-to-base, or base-to-derived member pointer +/// conversion. +/// +/// Bitcast conversions are always a no-op under Itanium. /// /// Obligatory offset/adjustment diagram: /// <-- offset --> <-- adjustment --> @@ -335,64 +340,105 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, llvm::Value * ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, const CastExpr *E, - llvm::Value *Src) { + llvm::Value *src) { assert(E->getCastKind() == CK_DerivedToBaseMemberPointer || - E->getCastKind() == CK_BaseToDerivedMemberPointer); + E->getCastKind() == CK_BaseToDerivedMemberPointer || + E->getCastKind() == CK_ReinterpretMemberPointer); + + // Under Itanium, reinterprets don't require any additional processing. + if (E->getCastKind() == CK_ReinterpretMemberPointer) return src; + + // Use constant emission if we can. + if (isa<llvm::Constant>(src)) + return EmitMemberPointerConversion(E, cast<llvm::Constant>(src)); + + llvm::Constant *adj = getMemberPointerAdjustment(E); + if (!adj) return src; CGBuilderTy &Builder = CGF.Builder; + bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer); + + const MemberPointerType *destTy = + E->getType()->castAs<MemberPointerType>(); - const MemberPointerType *SrcTy = - E->getSubExpr()->getType()->getAs<MemberPointerType>(); - const MemberPointerType *DestTy = E->getType()->getAs<MemberPointerType>(); + // For member data pointers, this is just a matter of adding the + // offset if the source is non-null. + if (destTy->isMemberDataPointer()) { + llvm::Value *dst; + if (isDerivedToBase) + dst = Builder.CreateNSWSub(src, adj, "adj"); + else + dst = Builder.CreateNSWAdd(src, adj, "adj"); - const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl(); - const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl(); + // Null check. + llvm::Value *null = llvm::Constant::getAllOnesValue(src->getType()); + llvm::Value *isNull = Builder.CreateICmpEQ(src, null, "memptr.isnull"); + return Builder.CreateSelect(isNull, src, dst); + } - bool DerivedToBase = - E->getCastKind() == CK_DerivedToBaseMemberPointer; + // The this-adjustment is left-shifted by 1 on ARM. + if (IsARM) { + uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue(); + offset <<= 1; + adj = llvm::ConstantInt::get(adj->getType(), offset); + } - const CXXRecordDecl *DerivedDecl; - if (DerivedToBase) - DerivedDecl = SrcDecl; + llvm::Value *srcAdj = Builder.CreateExtractValue(src, 1, "src.adj"); + llvm::Value *dstAdj; + if (isDerivedToBase) + dstAdj = Builder.CreateNSWSub(srcAdj, adj, "adj"); else - DerivedDecl = DestDecl; + dstAdj = Builder.CreateNSWAdd(srcAdj, adj, "adj"); + + return Builder.CreateInsertValue(src, dstAdj, 1); +} + +llvm::Constant * +ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E, + llvm::Constant *src) { + assert(E->getCastKind() == CK_DerivedToBaseMemberPointer || + E->getCastKind() == CK_BaseToDerivedMemberPointer || + E->getCastKind() == CK_ReinterpretMemberPointer); - llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, - E->path_begin(), - E->path_end()); - if (!Adj) return Src; + // Under Itanium, reinterprets don't require any additional processing. + if (E->getCastKind() == CK_ReinterpretMemberPointer) return src; + + // If the adjustment is trivial, we don't need to do anything. + llvm::Constant *adj = getMemberPointerAdjustment(E); + if (!adj) return src; + + bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer); + + const MemberPointerType *destTy = + E->getType()->castAs<MemberPointerType>(); // For member data pointers, this is just a matter of adding the // offset if the source is non-null. - if (SrcTy->isMemberDataPointer()) { - llvm::Value *Dst; - if (DerivedToBase) - Dst = Builder.CreateNSWSub(Src, Adj, "adj"); - else - Dst = Builder.CreateNSWAdd(Src, Adj, "adj"); + if (destTy->isMemberDataPointer()) { + // null maps to null. + if (src->isAllOnesValue()) return src; - // Null check. - llvm::Value *Null = llvm::Constant::getAllOnesValue(Src->getType()); - llvm::Value *IsNull = Builder.CreateICmpEQ(Src, Null, "memptr.isnull"); - return Builder.CreateSelect(IsNull, Src, Dst); + if (isDerivedToBase) + return llvm::ConstantExpr::getNSWSub(src, adj); + else + return llvm::ConstantExpr::getNSWAdd(src, adj); } // The this-adjustment is left-shifted by 1 on ARM. if (IsARM) { - uint64_t Offset = cast<llvm::ConstantInt>(Adj)->getZExtValue(); - Offset <<= 1; - Adj = llvm::ConstantInt::get(Adj->getType(), Offset); + uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue(); + offset <<= 1; + adj = llvm::ConstantInt::get(adj->getType(), offset); } - llvm::Value *SrcAdj = Builder.CreateExtractValue(Src, 1, "src.adj"); - llvm::Value *DstAdj; - if (DerivedToBase) - DstAdj = Builder.CreateNSWSub(SrcAdj, Adj, "adj"); + llvm::Constant *srcAdj = llvm::ConstantExpr::getExtractValue(src, 1); + llvm::Constant *dstAdj; + if (isDerivedToBase) + dstAdj = llvm::ConstantExpr::getNSWSub(srcAdj, adj); else - DstAdj = Builder.CreateNSWAdd(SrcAdj, Adj, "adj"); + dstAdj = llvm::ConstantExpr::getNSWAdd(srcAdj, adj); - return Builder.CreateInsertValue(Src, DstAdj, 1); + return llvm::ConstantExpr::getInsertValue(src, dstAdj, 1); } llvm::Constant * diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index c89582ff00..a36f6cbb00 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1576,7 +1576,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, } // A valid member pointer cast. - Kind = IsLValueCast? CK_LValueBitCast : CK_BitCast; + assert(!IsLValueCast); + Kind = CK_ReinterpretMemberPointer; return TC_Success; } diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 254540468a..c1f804ce09 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -289,6 +289,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_NullToMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: + case CK_ReinterpretMemberPointer: case CK_UserDefinedConversion: case CK_ConstructorConversion: case CK_VectorSplat: diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp index 5ce5fbf760..2417aa4191 100644 --- a/test/CodeGenCXX/member-function-pointers.cpp +++ b/test/CodeGenCXX/member-function-pointers.cpp @@ -28,6 +28,16 @@ void (C::*pc2)() = &C::f; // CHECK: @pc3 = global { i64, i64 } { i64 1, i64 0 }, align 8 void (A::*pc3)() = &A::vf1; +// Tests for test10. +// CHECK: @_ZN6test101aE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 0 }, align 8 +// CHECK: @_ZN6test101bE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8 +// CHECK: @_ZN6test101cE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8 +// CHECK: @_ZN6test101dE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 16 }, align 8 +// CHECK-LP32: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4 +// CHECK-LP32: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4 +// CHECK-LP32: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4 +// CHECK-LP32: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 + void f() { // CHECK: store { i64, i64 } zeroinitializer, { i64, i64 }* @pa pa = 0; @@ -232,3 +242,33 @@ namespace test9 { static S array[] = { (fooptr) &B::foo }; } } + +// rdar://problem/10815683 - Verify that we can emit reinterprets of +// member pointers as constant initializers. For added trickiness, +// we also add some non-trivial adjustments. +namespace test10 { + struct A { + int nonEmpty; + void foo(); + }; + struct B : public A { + virtual void requireNonZeroAdjustment(); + }; + struct C { + int nonEmpty; + }; + struct D : public C { + virtual void requireNonZeroAdjustment(); + }; + + // Non-ARM tests at top of file. + void (A::*a)() = &A::foo; + void (B::*b)() = (void (B::*)()) &A::foo; + void (C::*c)() = (void (C::*)()) (void (B::*)()) &A::foo; + void (D::*d)() = (void (C::*)()) (void (B::*)()) &A::foo; +} +// It's not that the offsets are doubled on ARM, it's that they're left-shifted by 1. +// CHECK-ARM: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4 +// CHECK-ARM: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 +// CHECK-ARM: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 +// CHECK-ARM: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 16 }, align 4 |