[clang] f58d54a - [clang][Interp] Diagnose uninitialized bases (#67131)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 2 21:46:36 PDT 2023
Author: Timm Baeder
Date: 2023-10-03T06:46:31+02:00
New Revision: f58d54ab969b2f342a882dfb03334f18f4ec1dcc
URL: https://github.com/llvm/llvm-project/commit/f58d54ab969b2f342a882dfb03334f18f4ec1dcc
DIFF: https://github.com/llvm/llvm-project/commit/f58d54ab969b2f342a882dfb03334f18f4ec1dcc.diff
LOG: [clang][Interp] Diagnose uninitialized bases (#67131)
Added:
clang/test/AST/Interp/constexpr-subobj-initialization.cpp
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeStmtGen.cpp
clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/Opcodes.td
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index e266804a4e75dea..f4ab30a5c8e7238 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -561,7 +561,7 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
if (!this->visitInitializer(Init))
return false;
- if (!this->emitPopPtr(E))
+ if (!this->emitInitPtrPop(E))
return false;
// Base initializers don't increase InitIndex, since they don't count
// into the Record's fields.
@@ -1718,7 +1718,7 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
return false;
if (!this->visitZeroRecordInitializer(B.R, E))
return false;
- if (!this->emitPopPtr(E))
+ if (!this->emitInitPtrPop(E))
return false;
}
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 15eae8e20b3a678..a81c82c38955e9c 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -191,7 +191,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
return false;
if (!this->visitInitializer(InitExpr))
return false;
- if (!this->emitPopPtr(InitExpr))
+ if (!this->emitInitPtrPop(InitExpr))
return false;
}
}
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index e1951574edb6288..8e851595963184c 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -467,6 +467,12 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
// Check Fields in all bases
for (const Record::Base &B : R->bases()) {
Pointer P = BasePtr.atField(B.Offset);
+ if (!P.isInitialized()) {
+ S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
+ diag::note_constexpr_uninitialized_base)
+ << B.Desc->getType();
+ return false;
+ }
Result &= CheckFieldsInitialized(S, OpPC, P, B.R);
}
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 9d5ec3315415cf7..d62e64bedb213ac 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1245,6 +1245,12 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
return true;
}
+inline bool InitPtrPop(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ Ptr.initialize();
+ return true;
+}
+
inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
const Pointer &Ptr) {
Pointer Base = Ptr;
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 9fc4938bb37bde8..50b6c0ac154de30 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -304,6 +304,10 @@ def GetPtrBasePop : Opcode {
let Args = [ArgUint32];
}
+def InitPtrPop : Opcode {
+ let Args = [];
+}
+
def GetPtrDerivedPop : Opcode {
let Args = [ArgUint32];
}
diff --git a/clang/test/AST/Interp/constexpr-subobj-initialization.cpp b/clang/test/AST/Interp/constexpr-subobj-initialization.cpp
new file mode 100644
index 000000000000000..4976b165468bd61
--- /dev/null
+++ b/clang/test/AST/Interp/constexpr-subobj-initialization.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
+
+/// This is like the version in test/SemaCXX/, but some of the
+/// output types and their location has been adapted.
+/// Differences:
+/// 1) The type of the uninitialized base class is printed WITH the namespace,
+/// i.e. 'baseclass_uninit::DelBase' instead of just 'DelBase'.
+/// 2) The location is not the base specifier declaration, but the call site
+/// of the constructor.
+
+
+namespace baseclass_uninit {
+struct DelBase {
+ constexpr DelBase() = delete; // expected-note {{'DelBase' has been explicitly marked deleted here}}
+};
+
+struct Foo : DelBase {
+ constexpr Foo() {}; // expected-error {{call to deleted constructor of 'DelBase'}}
+};
+constexpr Foo f; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{constructor of base class 'baseclass_uninit::DelBase' is not called}}
+
+struct Bar : Foo {
+ constexpr Bar() {};
+};
+constexpr Bar bar; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{constructor of base class 'baseclass_uninit::DelBase' is not called}}
+
+struct Base {};
+struct A : Base {
+ constexpr A() : value() {} // expected-error {{member initializer 'value' does not name a non-static data member or base class}}
+};
+
+constexpr A a; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}}
+
+
+struct B : Base {
+ constexpr B() : {} // expected-error {{expected class member or base class name}}
+};
+
+constexpr B b; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}}
+} // namespace baseclass_uninit
+
+
+struct Foo {
+ constexpr Foo(); // expected-note 2{{declared here}}
+};
+
+constexpr Foo ff; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}}
+
+struct Bar : protected Foo {
+ int i;
+ constexpr Bar() : i(12) {} // expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}}
+};
+
+constexpr Bar bb; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{in call to 'Bar()'}}
+
+template <typename Ty>
+struct Baz {
+ constexpr Baz(); // expected-note {{declared here}}
+};
+
+struct Quux : Baz<Foo>, private Bar {
+ int i;
+ constexpr Quux() : i(12) {} // expected-note {{undefined constructor 'Baz' cannot be used in a constant expression}}
+};
+
+constexpr Quux qx; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{in call to 'Quux()'}}
More information about the cfe-commits
mailing list