CGCXXABI::~CGCXXABI() {}
+static void ErrorUnsupportedABI(CodeGenFunction &CGF,
+ llvm::StringRef S) {
+ Diagnostic &Diags = CGF.CGM.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot yet compile %s in this ABI");
+ Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()),
+ DiagID)
+ << S;
+}
+
llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
llvm::Value *&This,
llvm::Value *MemPtr,
const MemberPointerType *MPT) {
- Diagnostic &Diags = CGF.CGM.getDiags();
- unsigned DiagID =
- Diags.getCustomDiagID(Diagnostic::Error,
- "cannot yet compile member pointer calls in this ABI");
- Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()),
- DiagID);
+ ErrorUnsupportedABI(CGF, "calls through member pointers");
const FunctionProtoType *FPT =
MPT->getPointeeType()->getAs<FunctionProtoType>();
FPT->isVariadic());
return llvm::Constant::getNullValue(FTy->getPointerTo());
}
+
+void CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src,
+ llvm::Value *Dest,
+ bool VolatileDest) {
+ ErrorUnsupportedABI(CGF, "member pointer conversions");
+}
}
namespace clang {
+ class CastExpr;
class MemberPointerType;
namespace CodeGen {
llvm::Value *&This,
llvm::Value *MemPtr,
const MemberPointerType *MPT);
+
+ virtual void EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src,
+ llvm::Value *Dest,
+ bool VolatileDest);
};
/// Creates an instance of a C++ ABI class.
llvm::Value *Src = CGF.CreateMemTemp(SrcType, "tmp");
CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified());
-
- llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr");
- SrcPtr = Builder.CreateLoad(SrcPtr);
-
- llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj");
- SrcAdj = Builder.CreateLoad(SrcAdj);
-
- llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr");
- Builder.CreateStore(SrcPtr, DstPtr, VolatileDest);
-
- llvm::Value *DstAdj = Builder.CreateStructGEP(DestPtr, 1, "dst.adj");
-
- // Now See if we need to update the adjustment.
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(SrcType->getAs<MemberPointerType>()->
- getClass()->getAs<RecordType>()->getDecl());
- const CXXRecordDecl *DerivedDecl =
- cast<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
- getClass()->getAs<RecordType>()->getDecl());
- if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
- std::swap(DerivedDecl, BaseDecl);
-
- if (llvm::Constant *Adj =
- CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
- E->path_begin(),
- E->path_end())) {
- if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
- SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
- else
- SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
- }
-
- Builder.CreateStore(SrcAdj, DstAdj, VolatileDest);
+
+ // Note that the AST doesn't distinguish between checked and
+ // unchecked member pointer conversions, so we always have to
+ // implement checked conversions here. This is inefficient for
+ // ABIs where an actual null check is thus required; fortunately,
+ // the Itanium and ARM ABIs ignore the adjustment value when
+ // considering null-ness.
+ CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, E, Src,
+ DestPtr, VolatileDest);
break;
}
}
llvm::Value *&This,
llvm::Value *MemFnPtr,
const MemberPointerType *MPT);
+
+ void EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src,
+ llvm::Value *Dest,
+ bool VolatileDest);
};
class ARMCXXABI : public ItaniumCXXABI {
Callee->addIncoming(NonVirtualFn, FnNonVirtual);
return Callee;
}
+
+/// Perform a derived-to-base or base-to-derived member pointer conversion.
+void ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src,
+ llvm::Value *Dest,
+ bool VolatileDest) {
+ assert(E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer ||
+ E->getCastKind() == CastExpr::CK_BaseToDerivedMemberPointer);
+
+ CGBuilderTy &Builder = CGF.Builder;
+
+ const MemberPointerType *SrcTy =
+ E->getSubExpr()->getType()->getAs<MemberPointerType>();
+ const MemberPointerType *DestTy = E->getType()->getAs<MemberPointerType>();
+
+ const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl();
+ const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl();
+
+ llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr");
+ SrcPtr = Builder.CreateLoad(SrcPtr);
+
+ llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj");
+ SrcAdj = Builder.CreateLoad(SrcAdj);
+
+ llvm::Value *DstPtr = Builder.CreateStructGEP(Dest, 0, "dst.ptr");
+ Builder.CreateStore(SrcPtr, DstPtr, VolatileDest);
+
+ llvm::Value *DstAdj = Builder.CreateStructGEP(Dest, 1, "dst.adj");
+
+ bool DerivedToBase =
+ E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer;
+
+ const CXXRecordDecl *BaseDecl, *DerivedDecl;
+ if (DerivedToBase)
+ DerivedDecl = SrcDecl, BaseDecl = DestDecl;
+ else
+ BaseDecl = SrcDecl, DerivedDecl = DestDecl;
+
+ if (llvm::Constant *Adj =
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
+ E->path_begin(),
+ E->path_end())) {
+ if (DerivedToBase)
+ SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
+ else
+ SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
+ }
+
+ Builder.CreateStore(SrcAdj, DstAdj, VolatileDest);
+}