@@ -721,17 +721,16 @@ static const Expr *getSimpleArrayDecayOperand(const Expr *e) {
721721
722722static cir::IntAttr getConstantIndexOrNull (mlir::Value idx) {
723723 // TODO(cir): should we consider using MLIRs IndexType instead of IntegerAttr?
724- if (auto constantOp = dyn_cast <cir::ConstantOp>(idx. getDefiningOp () ))
725- return mlir::dyn_cast <cir::IntAttr>(constantOp. getValue () );
724+ if (auto constantOp = idx. getDefiningOp <cir::ConstantOp>())
725+ return constantOp. getValueAttr <cir::IntAttr>();
726726 return {};
727727}
728728
729729static CharUnits getArrayElementAlign (CharUnits arrayAlign, mlir::Value idx,
730730 CharUnits eltSize) {
731731 // If we have a constant index, we can use the exact offset of the
732732 // element we're accessing.
733- const cir::IntAttr constantIdx = getConstantIndexOrNull (idx);
734- if (constantIdx) {
733+ if (const cir::IntAttr constantIdx = getConstantIndexOrNull (idx)) {
735734 const CharUnits offset = constantIdx.getValue ().getZExtValue () * eltSize;
736735 return arrayAlign.alignmentAtOffset (offset);
737736 }
@@ -1105,6 +1104,151 @@ void CIRGenFunction::emitAnyExprToMem(const Expr *e, Address location,
11051104 llvm_unreachable (" bad evaluation kind" );
11061105}
11071106
1107+ static Address createReferenceTemporary (CIRGenFunction &cgf,
1108+ const MaterializeTemporaryExpr *m,
1109+ const Expr *inner) {
1110+ // TODO(cir): cgf.getTargetHooks();
1111+ switch (m->getStorageDuration ()) {
1112+ case SD_FullExpression:
1113+ case SD_Automatic: {
1114+ QualType ty = inner->getType ();
1115+
1116+ assert (!cir::MissingFeatures::mergeAllConstants ());
1117+
1118+ // The temporary memory should be created in the same scope as the extending
1119+ // declaration of the temporary materialization expression.
1120+ cir::AllocaOp extDeclAlloca;
1121+ if (const ValueDecl *extDecl = m->getExtendingDecl ()) {
1122+ auto extDeclAddrIter = cgf.localDeclMap .find (extDecl);
1123+ if (extDeclAddrIter != cgf.localDeclMap .end ())
1124+ extDeclAlloca = extDeclAddrIter->second .getDefiningOp <cir::AllocaOp>();
1125+ }
1126+ mlir::OpBuilder::InsertPoint ip;
1127+ if (extDeclAlloca)
1128+ ip = {extDeclAlloca->getBlock (), extDeclAlloca->getIterator ()};
1129+ return cgf.createMemTemp (ty, cgf.getLoc (m->getSourceRange ()),
1130+ cgf.getCounterRefTmpAsString (), /* alloca=*/ nullptr ,
1131+ ip);
1132+ }
1133+ case SD_Thread:
1134+ case SD_Static: {
1135+ cgf.cgm .errorNYI (
1136+ m->getSourceRange (),
1137+ " createReferenceTemporary: static/thread storage duration" );
1138+ return Address::invalid ();
1139+ }
1140+
1141+ case SD_Dynamic:
1142+ llvm_unreachable (" temporary can't have dynamic storage duration" );
1143+ }
1144+ llvm_unreachable (" unknown storage duration" );
1145+ }
1146+
1147+ static void pushTemporaryCleanup (CIRGenFunction &cgf,
1148+ const MaterializeTemporaryExpr *m,
1149+ const Expr *e, Address referenceTemporary) {
1150+ // Objective-C++ ARC:
1151+ // If we are binding a reference to a temporary that has ownership, we
1152+ // need to perform retain/release operations on the temporary.
1153+ //
1154+ // FIXME(ogcg): This should be looking at e, not m.
1155+ if (m->getType ().getObjCLifetime ()) {
1156+ cgf.cgm .errorNYI (e->getSourceRange (), " pushTemporaryCleanup: ObjCLifetime" );
1157+ return ;
1158+ }
1159+
1160+ CXXDestructorDecl *referenceTemporaryDtor = nullptr ;
1161+ if (const clang::RecordType *rt = e->getType ()
1162+ ->getBaseElementTypeUnsafe ()
1163+ ->getAs <clang::RecordType>()) {
1164+ // Get the destructor for the reference temporary.
1165+ auto *classDecl = cast<CXXRecordDecl>(rt->getDecl ());
1166+ if (!classDecl->hasTrivialDestructor ())
1167+ referenceTemporaryDtor = classDecl->getDestructor ();
1168+ }
1169+
1170+ if (!referenceTemporaryDtor)
1171+ return ;
1172+
1173+ // Call the destructor for the temporary.
1174+ switch (m->getStorageDuration ()) {
1175+ case SD_Static:
1176+ case SD_Thread:
1177+ cgf.cgm .errorNYI (e->getSourceRange (),
1178+ " pushTemporaryCleanup: static/thread storage duration" );
1179+ return ;
1180+
1181+ case SD_FullExpression:
1182+ cgf.pushDestroy (NormalAndEHCleanup, referenceTemporary, e->getType (),
1183+ CIRGenFunction::destroyCXXObject);
1184+ break ;
1185+
1186+ case SD_Automatic:
1187+ cgf.cgm .errorNYI (e->getSourceRange (),
1188+ " pushTemporaryCleanup: automatic storage duration" );
1189+ break ;
1190+
1191+ case SD_Dynamic:
1192+ llvm_unreachable (" temporary cannot have dynamic storage duration" );
1193+ }
1194+ }
1195+
1196+ LValue CIRGenFunction::emitMaterializeTemporaryExpr (
1197+ const MaterializeTemporaryExpr *m) {
1198+ const Expr *e = m->getSubExpr ();
1199+
1200+ assert ((!m->getExtendingDecl () || !isa<VarDecl>(m->getExtendingDecl ()) ||
1201+ !cast<VarDecl>(m->getExtendingDecl ())->isARCPseudoStrong ()) &&
1202+ " Reference should never be pseudo-strong!" );
1203+
1204+ // FIXME: ideally this would use emitAnyExprToMem, however, we cannot do so
1205+ // as that will cause the lifetime adjustment to be lost for ARC
1206+ auto ownership = m->getType ().getObjCLifetime ();
1207+ if (ownership != Qualifiers::OCL_None &&
1208+ ownership != Qualifiers::OCL_ExplicitNone) {
1209+ cgm.errorNYI (e->getSourceRange (),
1210+ " emitMaterializeTemporaryExpr: ObjCLifetime" );
1211+ return {};
1212+ }
1213+
1214+ SmallVector<const Expr *, 2 > commaLHSs;
1215+ SmallVector<SubobjectAdjustment, 2 > adjustments;
1216+ e = e->skipRValueSubobjectAdjustments (commaLHSs, adjustments);
1217+
1218+ for (const Expr *ignored : commaLHSs)
1219+ emitIgnoredExpr (ignored);
1220+
1221+ if (isa<OpaqueValueExpr>(e)) {
1222+ cgm.errorNYI (e->getSourceRange (),
1223+ " emitMaterializeTemporaryExpr: OpaqueValueExpr" );
1224+ return {};
1225+ }
1226+
1227+ // Create and initialize the reference temporary.
1228+ Address object = createReferenceTemporary (*this , m, e);
1229+
1230+ if (auto var = object.getPointer ().getDefiningOp <cir::GlobalOp>()) {
1231+ // TODO(cir): add something akin to stripPointerCasts() to ptr above
1232+ cgm.errorNYI (e->getSourceRange (), " emitMaterializeTemporaryExpr: GlobalOp" );
1233+ return {};
1234+ } else {
1235+ assert (!cir::MissingFeatures::emitLifetimeMarkers ());
1236+ emitAnyExprToMem (e, object, Qualifiers (), /* isInitializer=*/ true );
1237+ }
1238+ pushTemporaryCleanup (*this , m, e, object);
1239+
1240+ // Perform derived-to-base casts and/or field accesses, to get from the
1241+ // temporary object we created (and, potentially, for which we extended
1242+ // the lifetime) to the subobject we're binding the reference to.
1243+ if (!adjustments.empty ()) {
1244+ cgm.errorNYI (e->getSourceRange (),
1245+ " emitMaterializeTemporaryExpr: Adjustments" );
1246+ return {};
1247+ }
1248+
1249+ return makeAddrLValue (object, m->getType (), AlignmentSource::Decl);
1250+ }
1251+
11081252LValue CIRGenFunction::emitCompoundLiteralLValue (const CompoundLiteralExpr *e) {
11091253 if (e->isFileScope ()) {
11101254 cgm.errorNYI (e->getSourceRange (), " emitCompoundLiteralLValue: FileScope" );
0 commit comments