@@ -222,13 +222,7 @@ void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd,
222
222
223
223
const CXXRecordDecl *classDecl = cd->getParent ();
224
224
225
- // This code doesn't use range-based iteration because we may need to emit
226
- // code between the virtual base initializers and the non-virtual base or
227
- // between the non-virtual base initializers and the member initializers.
228
- CXXConstructorDecl::init_const_iterator b = cd->init_begin (),
229
- e = cd->init_end ();
230
-
231
- // Virtual base initializers first, if any. They aren't needed if:
225
+ // Virtual base initializers aren't needed if:
232
226
// - This is a base ctor variant
233
227
// - There are no vbases
234
228
// - The class is abstract, so a complete object of it cannot be constructed
@@ -238,31 +232,60 @@ void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd,
238
232
bool constructVBases = ctorType != Ctor_Base &&
239
233
classDecl->getNumVBases () != 0 &&
240
234
!classDecl->isAbstract ();
241
- if (constructVBases) {
242
- cgm.errorNYI (cd->getSourceRange (), " emitCtorPrologue: virtual base" );
243
- return ;
244
- }
245
-
246
- const mlir::Value oldThisValue = cxxThisValue;
247
- if (!constructVBases && b != e && (*b)->isBaseInitializer () &&
248
- (*b)->isBaseVirtual ()) {
235
+ if (constructVBases &&
236
+ !cgm.getTarget ().getCXXABI ().hasConstructorVariants ()) {
249
237
cgm.errorNYI (cd->getSourceRange (),
250
- " emitCtorPrologue: virtual base initializer " );
238
+ " emitCtorPrologue: virtual base without variants " );
251
239
return ;
252
240
}
253
241
254
- // Handle non-virtual base initializers.
255
- for (; b != e && (*b)->isBaseInitializer (); b++) {
256
- assert (!(*b)->isBaseVirtual ());
242
+ // Create three separate ranges for the different types of initializers.
243
+ auto allInits = cd->inits ();
244
+
245
+ // Find the boundaries between the three groups.
246
+ auto virtualBaseEnd = std::find_if (
247
+ allInits.begin (), allInits.end (), [](const CXXCtorInitializer *Init) {
248
+ return !(Init->isBaseInitializer () && Init->isBaseVirtual ());
249
+ });
250
+
251
+ auto nonVirtualBaseEnd = std::find_if (virtualBaseEnd, allInits.end (),
252
+ [](const CXXCtorInitializer *Init) {
253
+ return !Init->isBaseInitializer ();
254
+ });
255
+
256
+ // Create the three ranges.
257
+ auto virtualBaseInits = llvm::make_range (allInits.begin (), virtualBaseEnd);
258
+ auto nonVirtualBaseInits =
259
+ llvm::make_range (virtualBaseEnd, nonVirtualBaseEnd);
260
+ auto memberInits = llvm::make_range (nonVirtualBaseEnd, allInits.end ());
261
+
262
+ const mlir::Value oldThisValue = cxxThisValue;
257
263
264
+ auto emitInitializer = [&](CXXCtorInitializer *baseInit) {
258
265
if (cgm.getCodeGenOpts ().StrictVTablePointers &&
259
266
cgm.getCodeGenOpts ().OptimizationLevel > 0 &&
260
- isInitializerOfDynamicClass (*b)) {
267
+ isInitializerOfDynamicClass (baseInit)) {
268
+ // It's OK to continue after emitting the error here. The missing code
269
+ // just "launders" the 'this' pointer.
261
270
cgm.errorNYI (cd->getSourceRange (),
262
- " emitCtorPrologue: strict vtable pointers" );
263
- return ;
271
+ " emitCtorPrologue: strict vtable pointers for vbase" );
264
272
}
265
- emitBaseInitializer (getLoc (cd->getBeginLoc ()), classDecl, *b);
273
+ emitBaseInitializer (getLoc (cd->getBeginLoc ()), classDecl, baseInit);
274
+ };
275
+
276
+ // Process virtual base initializers.
277
+ for (CXXCtorInitializer *virtualBaseInit : virtualBaseInits) {
278
+ if (!constructVBases)
279
+ continue ;
280
+ emitInitializer (virtualBaseInit);
281
+ }
282
+
283
+ assert (!cir::MissingFeatures::msabi ());
284
+
285
+ // Then, non-virtual base initializers.
286
+ for (CXXCtorInitializer *nonVirtualBaseInit : nonVirtualBaseInits) {
287
+ assert (!nonVirtualBaseInit->isBaseVirtual ());
288
+ emitInitializer (nonVirtualBaseInit);
266
289
}
267
290
268
291
cxxThisValue = oldThisValue;
@@ -276,8 +299,7 @@ void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd,
276
299
// lowering or optimization phases to keep the memory accesses more
277
300
// explicit. For now, we don't insert memcpy at all.
278
301
assert (!cir::MissingFeatures::ctorMemcpyizer ());
279
- for (; b != e; b++) {
280
- CXXCtorInitializer *member = (*b);
302
+ for (CXXCtorInitializer *member : memberInits) {
281
303
assert (!member->isBaseInitializer ());
282
304
assert (member->isAnyMemberInitializer () &&
283
305
" Delegating initializer on non-delegating constructor" );
@@ -370,7 +392,7 @@ void CIRGenFunction::initializeVTablePointers(mlir::Location loc,
370
392
initializeVTablePointer (loc, vptr);
371
393
372
394
if (rd->getNumVBases ())
373
- cgm.errorNYI (loc, " initializeVTablePointers: virtual base " );
395
+ cgm.getCXXABI (). initializeHiddenVirtualInheritanceMembers (* this , rd );
374
396
}
375
397
376
398
CIRGenFunction::VPtrsVector
@@ -418,8 +440,17 @@ void CIRGenFunction::getVTablePointers(BaseSubobject base,
418
440
const CXXRecordDecl *nextBaseDecl;
419
441
420
442
if (nextBase.isVirtual ()) {
421
- cgm.errorNYI (rd->getSourceRange (), " getVTablePointers: virtual base" );
422
- return ;
443
+ // Check if we've visited this virtual base before.
444
+ if (!vbases.insert (baseDecl).second )
445
+ continue ;
446
+
447
+ const ASTRecordLayout &layout =
448
+ getContext ().getASTRecordLayout (vtableClass);
449
+
450
+ nextBaseDecl = nearestVBase;
451
+ baseOffset = layout.getVBaseClassOffset (baseDecl);
452
+ baseOffsetFromNearestVBase = CharUnits::Zero ();
453
+ baseDeclIsNonVirtualPrimaryBase = false ;
423
454
} else {
424
455
const ASTRecordLayout &layout = getContext ().getASTRecordLayout (rd);
425
456
0 commit comments