[clang] 9308014 - [clang][Interp] Diagnose uninitialized array record fields
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 19 02:08:08 PST 2023
Author: Timm Bäder
Date: 2023-01-19T11:07:51+01:00
New Revision: 9308014195e2f091c0025ef4aa26ece080b7da8d
URL: https://github.com/llvm/llvm-project/commit/9308014195e2f091c0025ef4aa26ece080b7da8d
DIFF: https://github.com/llvm/llvm-project/commit/9308014195e2f091c0025ef4aa26ece080b7da8d.diff
LOG: [clang][Interp] Diagnose uninitialized array record fields
Just like we do for record members, diagnose uninitialized array record
fields.
Differential Revision: https://reviews.llvm.org/D136828
Added:
Modified:
clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Pointer.h
clang/test/AST/Interp/cxx20.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index d493a50486b7..6a600b306bad 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -401,6 +401,48 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
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 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
// 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;
}
}
diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index c0628314e869..ce113a54e122 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -242,6 +242,8 @@ class Pointer {
/// 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(); }
diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp
index de15cc9c259e..e9505b3cf718 100644
--- a/clang/test/AST/Interp/cxx20.cpp
+++ b/clang/test/AST/Interp/cxx20.cpp
@@ -137,8 +137,8 @@ static_assert(!b4); // ref-error {{not an integral constant expression}} \
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 @@ constexpr Derived D; // expected-error {{must be initialized by a constant expre
// 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
};
More information about the cfe-commits
mailing list