unsigned InitIndex = 0;
for (const Expr *Init : InitList->inits()) {
- const Record::Field *FieldToInit = R->getField(InitIndex);
if (!this->emitDupPtr(Initializer))
return false;
if (std::optional<PrimType> T = classify(Init)) {
+ const Record::Field *FieldToInit = R->getField(InitIndex);
if (!this->visit(Init))
return false;
if (!this->emitPopPtr(Initializer))
return false;
} else {
- // Non-primitive case. Get a pointer to the field-to-initialize
- // on the stack and recurse into visitInitializer().
- if (!this->emitGetPtrField(FieldToInit->Offset, Init))
- return false;
+ // Initializer for a direct base class.
+ if (const Record::Base *B = R->getBase(Init->getType())) {
+ if (!this->emitGetPtrBasePop(B->Offset, Init))
+ return false;
- if (!this->visitInitializer(Init))
- return false;
+ if (!this->visitInitializer(Init))
+ return false;
- if (!this->emitPopPtr(Initializer))
- return false;
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ } else {
+ const Record::Field *FieldToInit = R->getField(InitIndex);
+ // Non-primitive case. Get a pointer to the field-to-initialize
+ // on the stack and recurse into visitInitializer().
+ if (!this->emitGetPtrField(FieldToInit->Offset, Init))
+ return false;
+
+ if (!this->visitInitializer(Init))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ }
}
++InitIndex;
}
// Check Fields in all bases
for (const Record::Base &B : R->bases()) {
- Pointer P = Pointer(BasePtr.block(), B.Offset);
+ Pointer P = BasePtr.atField(B.Offset);
Result &= CheckFieldsInitialized(S, OpPC, P, B.R);
}
return It->second;
}
+const Record::Base *Record::getBase(QualType T) const {
+ if (!T->isRecordType())
+ return nullptr;
+
+ const RecordDecl *RD = T->getAs<RecordType>()->getDecl();
+ if (auto It = BaseMap.find(RD); It != BaseMap.end())
+ return It->second;
+ return nullptr;
+}
+
const Record::Base *Record::getVirtualBase(const RecordDecl *FD) const {
auto It = VirtualBaseMap.find(FD);
assert(It != VirtualBaseMap.end() && "Missing virtual base");
const Field *getField(const FieldDecl *FD) const;
/// Returns a base descriptor.
const Base *getBase(const RecordDecl *FD) const;
+ /// Returns a base descriptor.
+ const Base *getBase(QualType T) const;
/// Returns a virtual base descriptor.
const Base *getVirtualBase(const RecordDecl *RD) const;
// Returns the destructor of the record, if any.
// ref-note {{in call to}}
};
+namespace BaseInit {
+ struct Base {
+ int a;
+ };
+
+ struct Intermediate : Base {
+ int b;
+ };
+
+ struct Final : Intermediate {
+ int c;
+
+ constexpr Final(int a, int b, int c) : c(c) {}
+ };
+
+ static_assert(Final{1, 2, 3}.c == 3, ""); // OK
+ static_assert(Final{1, 2, 3}.a == 0, ""); // expected-error {{not an integral constant expression}} \
+ // expected-note {{read of object outside its lifetime}} \
+ // ref-error {{not an integral constant expression}} \
+ // ref-note {{read of uninitialized object}}
+
+
+ struct Mixin {
+ int b;
+
+ constexpr Mixin() = default;
+ constexpr Mixin(int b) : b(b) {}
+ };
+
+ struct Final2 : Base, Mixin {
+ int c;
+
+ constexpr Final2(int a, int b, int c) : Mixin(b), c(c) {}
+ constexpr Final2(int a, int b, int c, bool) : c(c) {}
+ };
+
+ static_assert(Final2{1, 2, 3}.c == 3, ""); // OK
+ static_assert(Final2{1, 2, 3}.b == 2, ""); // OK
+ static_assert(Final2{1, 2, 3}.a == 0, ""); // expected-error {{not an integral constant expression}} \
+ // expected-note {{read of object outside its lifetime}} \
+ // ref-error {{not an integral constant expression}} \
+ // ref-note {{read of uninitialized object}}
+
+
+ struct Mixin3 {
+ int b;
+ };
+
+ struct Final3 : Base, Mixin3 {
+ int c;
+
+ constexpr Final3(int a, int b, int c) : c(c) { this->b = b; }
+ constexpr Final3(int a, int b, int c, bool) : c(c) {}
+ };
+
+ static_assert(Final3{1, 2, 3}.c == 3, ""); // OK
+ static_assert(Final3{1, 2, 3}.b == 2, ""); // OK
+ static_assert(Final3{1, 2, 3}.a == 0, ""); // expected-error {{not an integral constant expression}} \
+ // expected-note {{read of object outside its lifetime}} \
+ // ref-error {{not an integral constant expression}} \
+ // ref-note {{read of uninitialized object}}
+};
+
namespace Destructors {
class Inc final {
#if __cplusplus >= 201703L
namespace BaseInit {
+ class _A {public: int a;};
+ class _B : public _A {};
+ class _C : public _B {};
+
+ constexpr _C c{12};
+ constexpr const _B &b = c;
+ static_assert(b.a == 12);
+
class A {public: int a;};
class B : public A {};
class C : public A {};
class D : public B, public C {};
- // FIXME: Enable this once we support the initialization.
// This initializes D::B::A::a and not D::C::A::a.
- //constexpr D d{12};
- //static_assert(d.B::a == 12);
- //static_assert(d.C::a == 0);
+ constexpr D d{12};
+ static_assert(d.B::a == 12);
+ static_assert(d.C::a == 0);
};
#endif