Skip to content

Commit 483efe5

Browse files
committed
[CIR] Unblock simple C++ structure support
This change adds additional checks to a few places where a simple struct in C++ code was triggering `errorNYI` in places where no additional handling was needed, and adds a very small amount of trivial initialization. The code now checks for the conditions that do require extra handling before issuing the diagnostic. New tests are added for declaring and using a simple struct in C++ code.
1 parent e882590 commit 483efe5

File tree

5 files changed

+75
-16
lines changed

5 files changed

+75
-16
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,12 @@ LValue CIRGenFunction::emitLValueForField(LValue base, const FieldDecl *field) {
322322
assert(!cir::MissingFeatures::opTBAA());
323323

324324
Address addr = base.getAddress();
325-
if (isa<CXXRecordDecl>(rec)) {
326-
cgm.errorNYI(field->getSourceRange(), "emitLValueForField: C++ class");
327-
return LValue();
325+
if (auto *classDecl = dyn_cast<CXXRecordDecl>(rec)) {
326+
if (cgm.getCodeGenOpts().StrictVTablePointers &&
327+
classDecl->isDynamicClass()) {
328+
cgm.errorNYI(field->getSourceRange(),
329+
"emitLValueForField: strict vtable for dynamic class");
330+
}
328331
}
329332

330333
unsigned recordCVR = base.getVRQualifiers();

clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,15 @@ mlir::Attribute ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &d) {
365365
if (!d.hasLocalStorage()) {
366366
QualType ty = cgm.getASTContext().getBaseElementType(d.getType());
367367
if (ty->isRecordType())
368-
if (d.getInit() && isa<CXXConstructExpr>(d.getInit())) {
369-
cgm.errorNYI(d.getInit()->getBeginLoc(),
370-
"tryEmitPrivateForVarInit CXXConstructExpr");
371-
return {};
368+
if (const CXXConstructExpr *e =
369+
dyn_cast_or_null<CXXConstructExpr>(d.getInit())) {
370+
const CXXConstructorDecl *cd = e->getConstructor();
371+
// FIXME: we should probably model this more closely to C++ than
372+
// just emitting a global with zero init (mimic what we do for trivial
373+
// assignments and whatnots). Since this is for globals shouldn't
374+
// be a problem for the near future.
375+
if (cd->isTrivial() && cd->isDefaultConstructor())
376+
return cir::ZeroAttr::get(cgm.convertType(d.getType()));
372377
}
373378
}
374379
inConstantContext = d.hasConstantInitialization();

clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,18 +177,26 @@ void CIRRecordLowering::lower() {
177177
return;
178178
}
179179

180-
if (isa<CXXRecordDecl>(recordDecl)) {
181-
cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
182-
"lower: class");
183-
return;
184-
}
185-
186180
assert(!cir::MissingFeatures::cxxSupport());
187181

188182
CharUnits size = astRecordLayout.getSize();
189183

190184
accumulateFields();
191185

186+
if (auto const *cxxRecordDecl = dyn_cast<CXXRecordDecl>(recordDecl)) {
187+
if (cxxRecordDecl->getNumBases() > 0) {
188+
CIRGenModule &cgm = cirGenTypes.getCGModule();
189+
cgm.errorNYI(recordDecl->getSourceRange(),
190+
"CIRRecordLowering::lower: derived CXXRecordDecl");
191+
return;
192+
}
193+
if (members.empty()) {
194+
appendPaddingBytes(size);
195+
assert(!cir::MissingFeatures::bitfields());
196+
return;
197+
}
198+
}
199+
192200
llvm::stable_sort(members);
193201
// TODO: implement clipTailPadding once bitfields are implemented
194202
assert(!cir::MissingFeatures::bitfields());
@@ -295,7 +303,10 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
295303
// If we're in C++, compute the base subobject type.
296304
if (llvm::isa<CXXRecordDecl>(rd) && !rd->isUnion() &&
297305
!rd->hasAttr<FinalAttr>()) {
298-
cgm.errorNYI(rd->getSourceRange(), "computeRecordLayout: CXXRecordDecl");
306+
if (lowering.astRecordLayout.getNonVirtualSize() !=
307+
lowering.astRecordLayout.getSize()) {
308+
cgm.errorNYI(rd->getSourceRange(), "computeRecordLayout: CXXRecordDecl");
309+
}
299310
}
300311

301312
// Fill in the record *after* computing the base type. Filling in the body

clang/lib/CIR/CodeGen/CIRGenTypes.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,11 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *rd) {
237237
assert(insertResult && "isSafeToCovert() should have caught this.");
238238

239239
// Force conversion of non-virtual base classes recursively.
240-
if (isa<CXXRecordDecl>(rd)) {
241-
cgm.errorNYI(rd->getSourceRange(), "CXXRecordDecl");
240+
if (const auto *cxxRecordDecl = dyn_cast<CXXRecordDecl>(rd)) {
241+
if (cxxRecordDecl->getNumBases() > 0) {
242+
cgm.errorNYI(rd->getSourceRange(),
243+
"convertRecordDeclType: derived CXXRecordDecl");
244+
}
242245
}
243246

244247
// Layout fields.

clang/test/CIR/CodeGen/struct.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ IncompleteS *p;
1212
// LLVM: @p = dso_local global ptr null
1313
// OGCG: @p = global ptr null, align 8
1414

15+
struct CompleteS {
16+
int a;
17+
char b;
18+
};
19+
20+
CompleteS cs;
21+
22+
// CIR: cir.global external @cs = #cir.zero : !rec_CompleteS
23+
// LLVM-DAG: @cs = dso_local global %struct.CompleteS zeroinitializer
24+
// OGCG-DAG: @cs = global %struct.CompleteS zeroinitializer, align 4
25+
1526
void f(void) {
1627
IncompleteS *p;
1728
}
@@ -28,3 +39,29 @@ void f(void) {
2839
// OGCG-NEXT: entry:
2940
// OGCG-NEXT: %[[P:.*]] = alloca ptr, align 8
3041
// OGCG-NEXT: ret void
42+
43+
char f2(CompleteS &s) {
44+
return s.b;
45+
}
46+
47+
// CIR: cir.func @_Z2f2R9CompleteS(%[[ARG_S:.*]]: !cir.ptr<!rec_CompleteS>{{.*}})
48+
// CIR: %[[S_ADDR:.*]] = cir.alloca !cir.ptr<!rec_CompleteS>, !cir.ptr<!cir.ptr<!rec_CompleteS>>, ["s", init, const]
49+
// CIR: cir.store %[[ARG_S]], %[[S_ADDR]]
50+
// CIR: %[[S_REF:.*]] = cir.load %[[S_ADDR]]
51+
// CIR: %[[S_ADDR2:.*]] = cir.get_member %[[S_REF]][1] {name = "b"}
52+
// CIR: %[[S_B:.*]] = cir.load %[[S_ADDR2]]
53+
54+
// LLVM: define i8 @_Z2f2R9CompleteS(ptr %[[ARG_S:.*]])
55+
// LLVM: %[[S_ADDR:.*]] = alloca ptr
56+
// LLVM: store ptr %[[ARG_S]], ptr %[[S_ADDR]]
57+
// LLVM: %[[S_REF:.*]] = load ptr, ptr %[[S_ADDR]], align 8
58+
// LLVM: %[[S_ADDR2:.*]] = getelementptr %struct.CompleteS, ptr %[[S_REF]], i32 0, i32 1
59+
// LLVM: %[[S_B:.*]] = load i8, ptr %[[S_ADDR2]]
60+
61+
// OGCG: define{{.*}} i8 @_Z2f2R9CompleteS(ptr{{.*}} %[[ARG_S:.*]])
62+
// OGCG: entry:
63+
// OGCG: %[[S_ADDR:.*]] = alloca ptr
64+
// OGCG: store ptr %[[ARG_S]], ptr %[[S_ADDR]]
65+
// OGCG: %[[S_REF:.*]] = load ptr, ptr %[[S_ADDR]]
66+
// OGCG: %[[S_ADDR2:.*]] = getelementptr inbounds nuw %struct.CompleteS, ptr %[[S_REF]], i32 0, i32 1
67+
// OGCG: %[[S_B:.*]] = load i8, ptr %[[S_ADDR2]]

0 commit comments

Comments
 (0)