@@ -951,39 +951,55 @@ Address CIRGenFunction::getAddressOfBaseClass(
951951 bool nullCheckValue, SourceLocation loc) {
952952 assert (!path.empty () && " Base path should not be empty!" );
953953
954+ CastExpr::path_const_iterator start = path.begin ();
955+ const CXXRecordDecl *vBase = nullptr ;
956+
954957 if ((*path.begin ())->isVirtual ()) {
955- // The implementation here is actually complete, but let's flag this
956- // as an error until the rest of the virtual base class support is in place.
957- cgm.errorNYI (loc, " getAddrOfBaseClass: virtual base" );
958- return Address::invalid ();
958+ vBase = (*start)->getType ()->castAsCXXRecordDecl ();
959+ ++start;
959960 }
960961
961962 // Compute the static offset of the ultimate destination within its
962963 // allocating subobject (the virtual base, if there is one, or else
963964 // the "complete" object that we see).
964- CharUnits nonVirtualOffset =
965- cgm.computeNonVirtualBaseClassOffset (derived, path);
965+ CharUnits nonVirtualOffset = cgm.computeNonVirtualBaseClassOffset (
966+ vBase ? vBase : derived, {start, path.end ()});
967+
968+ // If there's a virtual step, we can sometimes "devirtualize" it.
969+ // For now, that's limited to when the derived type is final.
970+ // TODO: "devirtualize" this for accesses to known-complete objects.
971+ if (vBase && derived->hasAttr <FinalAttr>()) {
972+ const ASTRecordLayout &layout = getContext ().getASTRecordLayout (derived);
973+ CharUnits vBaseOffset = layout.getVBaseClassOffset (vBase);
974+ nonVirtualOffset += vBaseOffset;
975+ vBase = nullptr ; // we no longer have a virtual step
976+ }
966977
967978 // Get the base pointer type.
968979 mlir::Type baseValueTy = convertType ((path.end ()[-1 ])->getType ());
969980 assert (!cir::MissingFeatures::addressSpace ());
970981
971- // The if statement here is redundant now, but it will be needed when we add
972- // support for virtual base classes.
973982 // If there is no virtual base, use cir.base_class_addr. It takes care of
974983 // the adjustment and the null pointer check.
975- if (nonVirtualOffset.isZero ()) {
984+ if (nonVirtualOffset.isZero () && !vBase ) {
976985 assert (!cir::MissingFeatures::sanitizers ());
977986 return builder.createBaseClassAddr (getLoc (loc), value, baseValueTy, 0 ,
978987 /* assumeNotNull=*/ true );
979988 }
980989
981990 assert (!cir::MissingFeatures::sanitizers ());
982991
983- // Apply the offset
984- value = builder.createBaseClassAddr (getLoc (loc), value, baseValueTy,
985- nonVirtualOffset.getQuantity (),
986- /* assumeNotNull=*/ true );
992+ // Compute the virtual offset.
993+ mlir::Value virtualOffset = nullptr ;
994+ if (vBase) {
995+ virtualOffset = cgm.getCXXABI ().getVirtualBaseClassOffset (
996+ getLoc (loc), *this , value, derived, vBase);
997+ }
998+
999+ // Apply both offsets.
1000+ value = applyNonVirtualAndVirtualOffset (
1001+ getLoc (loc), *this , value, nonVirtualOffset, virtualOffset, derived,
1002+ vBase, baseValueTy, not nullCheckValue);
9871003
9881004 // Cast to the destination type.
9891005 value = value.withElementType (builder, baseValueTy);
0 commit comments