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