I think this is pretty simple since we get the proper constructor as out InitExpr anyway.
Details
Diff Detail
Event Timeline
I realize it is not directly related but I don't see it in the test suite (maybe I missed it) but also delegating constructors, default member initializaers Vs mem-init list (mem-init list has priority) and mem-init list items out of order of initialization.
clang/test/AST/Interp/records.cpp | ||
---|---|---|
165 | How about also testing private and virtual as well as multiple bases. |
clang/lib/AST/Interp/ByteCodeExprGen.h | ||
---|---|---|
260 | We are de-pointering here, why not de-referencing? If we are OK with that, we can do this as: if (const auto *RD = T->getPointeeCXXRecordDecl()) return RD; return T->getAsCXXRecordDecl(); and most of the work is done for you. | |
clang/test/AST/Interp/records.cpp | ||
165 | I like the idea of testing virtual bases as well. |
clang/lib/AST/Interp/ByteCodeExprGen.h | ||
---|---|---|
260 | No reason, as usual I just didn't know this was a thing. Thanks! | |
clang/test/AST/Interp/records.cpp | ||
165 | How would that work in a constexpr context? I get: array.cpp:48:15: error: constexpr constructor not allowed in class with virtual base class constexpr D() : A(17) {} ^ array.cpp:45:13: note: virtual base class declared here class B : public virtual A {}; ^~~~~~~~~~~~~~~~ 1 error generated. |
clang/test/AST/Interp/records.cpp | ||
---|---|---|
165 | Ah! TIL, thanks! |
clang/test/AST/Interp/records.cpp | ||
---|---|---|
165 | Ah, this works: https://godbolt.org/z/ern3Yje9q |
clang/test/AST/Interp/records.cpp | ||
---|---|---|
165 | Checking this example, I should've tested a lot more non-constexpr stuff I guess. |
clang/lib/AST/Interp/ByteCodeExprGen.h | ||
---|---|---|
258 | ||
clang/test/AST/Interp/records.cpp | ||
209 | I'd appreciate some more failure test cases, if they're not already covered elsewhere: struct Base { int Val; }; struct Derived : Base { int OtherVal; constexpr Derived(int i) : OtherVal(i) {} }; // Something here should be diagnosed; either because the Derived ctor is not a // valid constexpr function or because we're accessing an uninitialized member. constexpr Derived D(12); static_assert(D.Val == 0); // Another test is when a constexpr ctor calls a non-constexpr base class ctor. struct AnotherBase { int Val; constexpr AnotherBase(int i) : Val(12 / i) {} }; struct AnotherDerived : AnotherBase { constexpr AnotherDerived(int i) : AnotherBase(i) {} }; constexpr AnotherDerived Derp(0); // Skipping the derived class constructor is also // interesting to consider: struct YetAnotherBase { int Val; constexpr YetAnotherBase(int i) : Val(i) {} }; struct YetAnotherDerived : YetAnotherBase { using YetAnotherBase::YetAnotherBase; int OtherVal; constexpr bool doit() const { return Val == OtherVal; } }; constexpr YetAnotherDerived Oops(0); |
clang/test/AST/Interp/records.cpp | ||
---|---|---|
209 | Thanks for the tests. I added them but it doesn't look very good. |
Do you think we should address some of the FIXMEs with base class ctor functionality as part of this patch, given that the failures all seem to be related to that functionality? Or are these failures due to other missing functionality that happened to be exposed here?
IMO it's fine to merge this. From a quick look the problems are:
- We don't reject non-constexpr functions in a constexpr context. (this is a more general problem and can be tested with simple normal functions, so that's probably a better test)
- In ByteCodeExprGen::getFunction(), we ignore any errors returned, so we can't print a reason for the rejection of the last test.
- The AnotherBase test is rejected properly, but we don't compute the value that was passed to the constructor correctly. This might just be an uninitialized APValue because we abort execution, but I'd have to investigate.