tbaeder updated this revision to Diff 471161.
tbaeder marked an inline comment as done.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D136694/new/
https://reviews.llvm.org/D136694
Files:
clang/lib/AST/Interp/Descriptor.cpp
clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/InterpFrame.cpp
clang/test/AST/Interp/cxx20.cpp
clang/test/AST/Interp/records.cpp
Index: clang/test/AST/Interp/records.cpp
===================================================================
--- clang/test/AST/Interp/records.cpp
+++ clang/test/AST/Interp/records.cpp
@@ -273,13 +273,14 @@
// ref-note 2{{non-constexpr constructor 'Base' cannot be used in a constant expression}}
};
- // FIXME: This is currently not being diagnosed with the new constant interpreter.
constexpr Derived D(12); // ref-error {{must be initialized by a constant expression}} \
// ref-note {{in call to 'Derived(12)'}} \
// ref-note {{declared here}} \
// expected-error {{must be initialized by a constant expression}}
static_assert(D.Val == 0, ""); // ref-error {{not an integral constant expression}} \
- // ref-note {{initializer of 'D' is not a constant expression}}
+ // ref-note {{initializer of 'D' is not a constant expression}} \
+ // expected-error {{not an integral constant expression}} \
+ // expected-note {{read of object outside its lifetime}}
struct AnotherBase {
int Val;
Index: clang/test/AST/Interp/cxx20.cpp
===================================================================
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -80,3 +80,36 @@
}
static_assert(f());
#endif
+
+
+namespace UninitializedFields {
+ class A {
+ public:
+ int a; // expected-note {{subobject declared here}} \
+ // ref-note {{subobject declared here}}
+ constexpr A() {}
+ };
+ constexpr A a; // 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 Base {
+ public:
+ bool b;
+ int a; // expected-note {{subobject declared here}} \
+ // ref-note {{subobject declared here}}
+ constexpr Base() : b(true) {}
+ };
+
+ class Derived : public Base {
+ public:
+ constexpr Derived() : Base() {} // expected-note {{subobject of type 'int' is not initialized}}
+ };
+
+constexpr Derived D; // expected-error {{must be initialized by a constant expression}} \\
+ // expected-note {{in call to 'Derived()'}} \
+ // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{subobject of type 'int' is not initialized}}
+};
Index: clang/lib/AST/Interp/InterpFrame.cpp
===================================================================
--- clang/lib/AST/Interp/InterpFrame.cpp
+++ clang/lib/AST/Interp/InterpFrame.cpp
@@ -61,8 +61,6 @@
}
InterpFrame::~InterpFrame() {
- if (Func && Func->isConstructor() && This.isBaseClass())
- This.initialize();
for (auto &Param : Params)
S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
}
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -96,6 +96,9 @@
bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status,
const Floating &Result);
+/// Checks that all fields are initialized after a constructor call.
+bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
+
/// Checks if Div/Rem operation on LHS and RHS is valid.
template <typename T>
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
@@ -1338,7 +1341,9 @@
inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
+ Pointer ThisPtr;
if (Func->hasThisPointer()) {
+ ThisPtr = NewFrame->getThis();
if (!CheckInvoke(S, PC, NewFrame->getThis())) {
return false;
}
@@ -1355,6 +1360,13 @@
if (Interpret(S, CallResult)) {
NewFrame.release(); // Frame was delete'd already.
assert(S.Current == FrameBefore);
+
+ // For constructors, check that all fields have been initialized.
+ if (Func->isConstructor()) {
+ if (!CheckCtorCall(S, PC, ThisPtr))
+ return false;
+ }
+
return true;
}
Index: clang/lib/AST/Interp/Interp.cpp
===================================================================
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -435,6 +435,38 @@
return true;
}
+static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr, const Record *R) {
+ assert(R);
+ bool Result = true;
+ // 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();
+
+ 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.
+ } 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);
+ Result = false;
+ }
+ }
+ return Result;
+}
+
+bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) {
+ assert(!This.isZero());
+ const Record *R = This.getRecord();
+ return CheckFieldsInitialized(S, OpPC, This, R);
+}
+
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
llvm::RoundingMode RM) {
Floating F = S.Stk.pop<Floating>();
Index: clang/lib/AST/Interp/Descriptor.cpp
===================================================================
--- clang/lib/AST/Interp/Descriptor.cpp
+++ clang/lib/AST/Interp/Descriptor.cpp
@@ -121,7 +121,7 @@
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
Desc->Offset = SubOff;
Desc->Desc = F;
- Desc->IsInitialized = (B->isStatic() || F->IsArray) && !IsBase;
+ Desc->IsInitialized = F->IsArray && !IsBase;
Desc->IsBase = IsBase;
Desc->IsActive = IsActive && !IsUnion;
Desc->IsConst = IsConst || F->IsConst;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits