This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG9308014195e2: [clang][Interp] Diagnose uninitialized array
record fields (authored by tbaeder).
Changed prior to commit:
https://reviews.llvm.org/D136828?vs=473405&id=490424#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D136828/new/
https://reviews.llvm.org/D136828
Files:
clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Pointer.h
clang/test/AST/Interp/cxx20.cpp
Index: clang/test/AST/Interp/cxx20.cpp
===================================================================
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -137,8 +137,8 @@
namespace UninitializedFields {
class A {
public:
- int a; // expected-note {{subobject declared here}} \
- // ref-note {{subobject declared here}}
+ int a; // expected-note 2{{subobject declared here}} \
+ // ref-note 2{{subobject declared here}}
constexpr A() {}
};
constexpr A a; // expected-error {{must be initialized by a constant expression}} \
@@ -164,4 +164,40 @@
// expected-note {{in call to 'Derived()'}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{subobject of type 'int' is not initialized}}
+
+ class C2 {
+ public:
+ A a;
+ constexpr C2() {} // expected-note {{subobject of type 'int' is not initialized}}
+ };
+ constexpr C2 c2; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{in call to 'C2()'}} \
+ // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{subobject of type 'int' is not initialized}}
+
+
+ // FIXME: These two are currently disabled because the array fields
+ // cannot be initialized.
+#if 0
+ class C3 {
+ public:
+ A a[2];
+ constexpr C3() {}
+ };
+ constexpr C3 c3; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{subobject of type 'int' is not initialized}} \
+ // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{subobject of type 'int' is not initialized}}
+
+ class C4 {
+ public:
+ bool B[2][3]; // expected-note {{subobject declared here}} \
+ // ref-note {{subobject declared here}}
+ constexpr C4(){}
+ };
+ constexpr C4 c4; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{subobject of type 'bool' is not initialized}} \
+ // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{subobject of type 'bool' is not initialized}}
+#endif
};
Index: clang/lib/AST/Interp/Pointer.h
===================================================================
--- clang/lib/AST/Interp/Pointer.h
+++ clang/lib/AST/Interp/Pointer.h
@@ -242,6 +242,8 @@
/// Returns the record descriptor of a class.
Record *getRecord() const { return getFieldDesc()->ElemRecord; }
+ // Returns the element record type, if this is a non-primive array.
+ Record *getElemRecord() const { return getFieldDesc()->ElemDesc->ElemRecord; }
/// Returns the field information.
const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
Index: clang/lib/AST/Interp/Interp.cpp
===================================================================
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -401,6 +401,48 @@
return false;
}
+static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI,
+ QualType SubObjType,
+ SourceLocation SubObjLoc) {
+ S.FFDiag(SI, diag::note_constexpr_uninitialized) << true << SubObjType;
+ if (SubObjLoc.isValid())
+ S.Note(SubObjLoc, diag::note_constexpr_subobject_declared_here);
+}
+
+static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr, const Record *R);
+
+static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr,
+ const ConstantArrayType *CAT) {
+ bool Result = true;
+ size_t NumElems = CAT->getSize().getZExtValue();
+ QualType ElemType = CAT->getElementType();
+
+ if (isa<RecordType>(ElemType.getTypePtr())) {
+ const Record *R = BasePtr.getElemRecord();
+ for (size_t I = 0; I != NumElems; ++I) {
+ Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+ Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R);
+ }
+ } else if (auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
+ for (size_t I = 0; I != NumElems; ++I) {
+ Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+ Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT);
+ }
+ } else {
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!BasePtr.atIndex(I).isInitialized()) {
+ DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), ElemType,
+ BasePtr.getFieldDesc()->getLocation());
+ Result = false;
+ }
+ }
+ }
+
+ return Result;
+}
+
static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
const Pointer &BasePtr, const Record *R) {
assert(R);
@@ -408,19 +450,17 @@
// Check all fields of this record are initialized.
for (const Record::Field &F : R->fields()) {
Pointer FieldPtr = BasePtr.atField(F.Offset);
- QualType FieldType = FieldPtr.getType();
+ QualType FieldType = F.Decl->getType();
if (FieldType->isRecordType()) {
Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
} else if (FieldType->isArrayType()) {
- // FIXME: Arrays need to be handled here as well I think.
+ const auto *CAT =
+ cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
+ Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT);
} else if (!FieldPtr.isInitialized()) {
- const SourceInfo &SI = S.Current->getSource(OpPC);
- S.FFDiag(SI, diag::note_constexpr_uninitialized)
- << true << F.Decl->getType();
- SourceLocation SubobjectLoc = F.Decl->getLocation();
- if (SubobjectLoc.isValid())
- S.Note(SubobjectLoc, diag::note_constexpr_subobject_declared_here);
+ DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC),
+ F.Decl->getType(), F.Decl->getLocation());
Result = false;
}
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits