This is an archive of the discontinued LLVM Phabricator instance.

[clang][Interp] Support base class constructors
ClosedPublic

Authored by tbaeder on Oct 2 2022, 12:18 AM.

Details

Summary

I think this is pretty simple since we get the proper constructor as out InitExpr anyway.

Diff Detail

Event Timeline

tbaeder created this revision.Oct 2 2022, 12:18 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 2 2022, 12:18 AM
tbaeder requested review of this revision.Oct 2 2022, 12:18 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 2 2022, 12:18 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
tbaeder updated this revision to Diff 464549.Oct 2 2022, 5:22 AM
tbaeder updated this revision to Diff 464618.Oct 3 2022, 1:33 AM
shafik added a comment.Oct 3 2022, 2:20 PM

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
190

How about also testing private and virtual as well as multiple bases.

tbaeder updated this revision to Diff 464913.Oct 4 2022, 1:24 AM
tbaeder updated this revision to Diff 464915.Oct 4 2022, 1:25 AM
shafik added a comment.Oct 4 2022, 7:54 AM

This looks good to me but I would like one other set of eyes on it

erichkeane added inline comments.Oct 4 2022, 7:57 AM
clang/lib/AST/Interp/ByteCodeExprGen.h
251

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
190

I like the idea of testing virtual bases as well.

tbaeder marked an inline comment as done.Oct 4 2022, 8:36 AM
tbaeder added inline comments.
clang/lib/AST/Interp/ByteCodeExprGen.h
251

No reason, as usual I just didn't know this was a thing. Thanks!

clang/test/AST/Interp/records.cpp
190

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.
erichkeane added inline comments.Oct 4 2022, 8:49 AM
clang/test/AST/Interp/records.cpp
190

Ah! TIL, thanks!

tbaeder marked an inline comment as done.Oct 4 2022, 8:56 AM
tbaeder added inline comments.
clang/test/AST/Interp/records.cpp
190
tbaeder added inline comments.Oct 4 2022, 9:41 AM
clang/test/AST/Interp/records.cpp
190

Checking this example, I should've tested a lot more non-constexpr stuff I guess.

tbaeder updated this revision to Diff 465271.Oct 4 2022, 9:21 PM

Anything still missing here?

aaron.ballman added inline comments.Oct 13 2022, 11:14 AM
clang/lib/AST/Interp/ByteCodeExprGen.h
249
clang/test/AST/Interp/records.cpp
234

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);
tbaeder updated this revision to Diff 467699.Oct 14 2022, 12:32 AM
tbaeder marked an inline comment as done.
tbaeder marked an inline comment as done.
tbaeder added inline comments.
clang/test/AST/Interp/records.cpp
234

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?

tbaeder marked an inline comment as done.Oct 17 2022, 6:37 AM

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:

  1. 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)
  2. In ByteCodeExprGen::getFunction(), we ignore any errors returned, so we can't print a reason for the rejection of the last test.
  3. 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.
aaron.ballman accepted this revision.Oct 18 2022, 6:01 AM

Okay, this is incremental progress, so LGTM!

This revision is now accepted and ready to land.Oct 18 2022, 6:01 AM
This revision was landed with ongoing or failed builds.Oct 21 2022, 1:50 AM
This revision was automatically updated to reflect the committed changes.