Skip to content

Commit e1021bb

Browse files
authored
[CIR] Implement CXX field default initialization (#157140)
This adds the code needed to handle default initialization for fields of various types.
1 parent 66f93df commit e1021bb

File tree

6 files changed

+321
-14
lines changed

6 files changed

+321
-14
lines changed

clang/lib/CIR/CodeGen/CIRGenClass.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -517,17 +517,23 @@ void CIRGenFunction::emitInitializerForField(FieldDecl *field, LValue lhs,
517517
QualType fieldType = field->getType();
518518
switch (getEvaluationKind(fieldType)) {
519519
case cir::TEK_Scalar:
520-
if (lhs.isSimple())
520+
if (lhs.isSimple()) {
521521
emitExprAsInit(init, field, lhs, false);
522-
else
523-
cgm.errorNYI(field->getSourceRange(),
524-
"emitInitializerForField: non-simple scalar");
522+
} else {
523+
RValue rhs = RValue::get(emitScalarExpr(init));
524+
emitStoreThroughLValue(rhs, lhs);
525+
}
525526
break;
526527
case cir::TEK_Complex:
527-
cgm.errorNYI(field->getSourceRange(), "emitInitializerForField: complex");
528+
emitComplexExprIntoLValue(init, lhs, /*isInit=*/true);
528529
break;
529530
case cir::TEK_Aggregate: {
530-
cgm.errorNYI(field->getSourceRange(), "emitInitializerForField: aggregate");
531+
assert(!cir::MissingFeatures::aggValueSlotGC());
532+
assert(!cir::MissingFeatures::sanitizers());
533+
AggValueSlot slot = AggValueSlot::forLValue(
534+
lhs, AggValueSlot::IsDestructed, AggValueSlot::IsNotAliased,
535+
getOverlapForFieldInit(field), AggValueSlot::IsNotZeroed);
536+
emitAggExpr(init, slot);
531537
break;
532538
}
533539
}

clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
9191
void visitCXXParenListOrInitListExpr(Expr *e, ArrayRef<Expr *> args,
9292
FieldDecl *initializedFieldInUnion,
9393
Expr *arrayFiller);
94-
94+
void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
95+
CIRGenFunction::CXXDefaultInitExprScope Scope(cgf, die);
96+
Visit(die->getExpr());
97+
}
9598
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *e) {
9699
assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());
97100
Visit(e->getSubExpr());
@@ -232,10 +235,6 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
232235
cgf.cgm.errorNYI(dae->getSourceRange(),
233236
"AggExprEmitter: VisitCXXDefaultArgExpr");
234237
}
235-
void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
236-
cgf.cgm.errorNYI(die->getSourceRange(),
237-
"AggExprEmitter: VisitCXXDefaultInitExpr");
238-
}
239238
void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *e) {
240239
cgf.cgm.errorNYI(e->getSourceRange(),
241240
"AggExprEmitter: VisitCXXInheritedCtorInitExpr");
@@ -794,6 +793,26 @@ void CIRGenFunction::emitAggregateCopy(LValue dest, LValue src, QualType ty,
794793
assert(!cir::MissingFeatures::opTBAA());
795794
}
796795

796+
// TODO(cir): This could be shared with classic codegen.
797+
AggValueSlot::Overlap_t
798+
CIRGenFunction::getOverlapForFieldInit(const FieldDecl *fd) {
799+
if (!fd->hasAttr<NoUniqueAddressAttr>() || !fd->getType()->isRecordType())
800+
return AggValueSlot::DoesNotOverlap;
801+
802+
// If the field lies entirely within the enclosing class's nvsize, its tail
803+
// padding cannot overlap any already-initialized object. (The only subobjects
804+
// with greater addresses that might already be initialized are vbases.)
805+
const RecordDecl *classRD = fd->getParent();
806+
const ASTRecordLayout &layout = getContext().getASTRecordLayout(classRD);
807+
if (layout.getFieldOffset(fd->getFieldIndex()) +
808+
getContext().getTypeSize(fd->getType()) <=
809+
(uint64_t)getContext().toBits(layout.getNonVirtualSize()))
810+
return AggValueSlot::DoesNotOverlap;
811+
812+
// The tail padding may contain values we need to preserve.
813+
return AggValueSlot::MayOverlap;
814+
}
815+
797816
LValue CIRGenFunction::emitAggExprToLValue(const Expr *e) {
798817
assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!");
799818
Address temp = createMemTemp(e->getType(), getLoc(e->getSourceRange()));

clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,8 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
201201
return {};
202202
}
203203
mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
204-
cgf.cgm.errorNYI(die->getExprLoc(),
205-
"ComplexExprEmitter VisitCXXDefaultInitExpr");
206-
return {};
204+
CIRGenFunction::CXXDefaultInitExprScope scope(cgf, die);
205+
return Visit(die->getExpr());
207206
}
208207
mlir::Value VisitExprWithCleanups(ExprWithCleanups *e) {
209208
cgf.cgm.errorNYI(e->getExprLoc(),

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
661661

662662
mlir::Value VisitUnaryImag(const UnaryOperator *e);
663663

664+
mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
665+
CIRGenFunction::CXXDefaultInitExprScope scope(cgf, die);
666+
return Visit(die->getExpr());
667+
}
668+
664669
mlir::Value VisitCXXThisExpr(CXXThisExpr *te) { return cgf.loadCXXThis(); }
665670

666671
mlir::Value VisitExprWithCleanups(ExprWithCleanups *e);

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
#include "clang/AST/ASTContext.h"
2626
#include "clang/AST/BaseSubobject.h"
2727
#include "clang/AST/CharUnits.h"
28+
#include "clang/AST/CurrentSourceLocExprScope.h"
2829
#include "clang/AST/Decl.h"
30+
#include "clang/AST/ExprCXX.h"
2931
#include "clang/AST/Stmt.h"
3032
#include "clang/AST/Type.h"
3133
#include "clang/CIR/Dialect/IR/CIRDialect.h"
@@ -599,6 +601,12 @@ class CIRGenFunction : public CIRGenTypeCache {
599601
/// true when both vcall CFI and whole-program-vtables are enabled.
600602
bool shouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *rd);
601603

604+
/// Source location information about the default argument or member
605+
/// initializer expression we're evaluating, if any.
606+
clang::CurrentSourceLocExprScope curSourceLocExprScope;
607+
using SourceLocExprScopeGuard =
608+
clang::CurrentSourceLocExprScope::SourceLocExprScopeGuard;
609+
602610
/// A scope within which we are constructing the fields of an object which
603611
/// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use if
604612
/// we need to evaluate the CXXDefaultInitExpr within the evaluation.
@@ -617,6 +625,29 @@ class CIRGenFunction : public CIRGenTypeCache {
617625
Address oldCXXDefaultInitExprThis;
618626
};
619627

628+
/// The scope of a CXXDefaultInitExpr. Within this scope, the value of 'this'
629+
/// is overridden to be the object under construction.
630+
class CXXDefaultInitExprScope {
631+
public:
632+
CXXDefaultInitExprScope(CIRGenFunction &cgf, const CXXDefaultInitExpr *e)
633+
: cgf{cgf}, oldCXXThisValue(cgf.cxxThisValue),
634+
oldCXXThisAlignment(cgf.cxxThisAlignment),
635+
sourceLocScope(e, cgf.curSourceLocExprScope) {
636+
cgf.cxxThisValue = cgf.cxxDefaultInitExprThis.getPointer();
637+
cgf.cxxThisAlignment = cgf.cxxDefaultInitExprThis.getAlignment();
638+
}
639+
~CXXDefaultInitExprScope() {
640+
cgf.cxxThisValue = oldCXXThisValue;
641+
cgf.cxxThisAlignment = oldCXXThisAlignment;
642+
}
643+
644+
public:
645+
CIRGenFunction &cgf;
646+
mlir::Value oldCXXThisValue;
647+
clang::CharUnits oldCXXThisAlignment;
648+
SourceLocExprScopeGuard sourceLocScope;
649+
};
650+
620651
LValue makeNaturalAlignPointeeAddrLValue(mlir::Value v, clang::QualType t);
621652
LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty);
622653

@@ -658,6 +689,8 @@ class CIRGenFunction : public CIRGenTypeCache {
658689
const clang::CXXRecordDecl *rd);
659690
void initializeVTablePointer(mlir::Location loc, const VPtr &vptr);
660691

692+
AggValueSlot::Overlap_t getOverlapForFieldInit(const FieldDecl *fd);
693+
661694
/// Return the address of a local variable.
662695
Address getAddrOfLocalVar(const clang::VarDecl *vd) {
663696
auto it = localDeclMap.find(vd);

0 commit comments

Comments
 (0)