Skip to content

Commit

Permalink
[clang][Interp] Handle CXXInheritedCtorInitExprs
Browse files Browse the repository at this point in the history
We need to forward all arguments of the current function and
call the ctor function.
  • Loading branch information
tbaederr committed Feb 8, 2024
1 parent d9e9276 commit 06774d6
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
31 changes: 31 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2020,6 +2020,37 @@ bool ByteCodeExprGen<Emitter>::VisitObjCBoolLiteralExpr(
return this->emitConst(E->getValue(), E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitCXXInheritedCtorInitExpr(
const CXXInheritedCtorInitExpr *E) {
const CXXConstructorDecl *Ctor = E->getConstructor();
assert(!Ctor->isTrivial() &&
"Trivial CXXInheritedCtorInitExpr, implement. (possible?)");
const Function *F = this->getFunction(Ctor);
assert(F);
assert(!F->hasRVO());
assert(F->hasThisPointer());

if (!this->emitDupPtr(SourceInfo{}))
return false;

// Forward all arguments of the current function (which should be a
// constructor itself) to the inherited ctor.
// This is necessary because the calling code has pushed the pointer
// of the correct base for us already, but the arguments need
// to come after.
unsigned Offset = align(primSize(PT_Ptr)); // instance pointer.
for (const ParmVarDecl *PD : Ctor->parameters()) {
PrimType PT = this->classify(PD->getType()).value_or(PT_Ptr);

if (!this->emitGetParam(PT, Offset, E))
return false;
Offset += align(primSize(PT));
}

return this->emitCall(F, E);
}

template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
if (E->containsErrors())
return false;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);
bool VisitChooseExpr(const ChooseExpr *E);
bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);

protected:
bool visitExpr(const Expr *E) override;
Expand Down
60 changes: 60 additions & 0 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1223,3 +1223,63 @@ namespace IndirectFieldInit {

#endif
}

namespace InheritedConstructor {
namespace PR47555 {
struct A {
int c;
int d;
constexpr A(int c, int d) : c(c), d(d){}
};
struct B : A { using A::A; };

constexpr B b = {13, 1};
static_assert(b.c == 13, "");
static_assert(b.d == 1, "");
}

namespace PR47555_2 {
struct A {
int c;
int d;
double e;
constexpr A(int c, int &d, double e) : c(c), d(++d), e(e){}
};
struct B : A { using A::A; };

constexpr int f() {
int a = 10;
B b = {10, a, 40.0};
return a;
}
static_assert(f() == 11, "");
}

namespace AaronsTest {
struct T {
constexpr T(float) {}
};

struct Base {
constexpr Base(T t = 1.0f) {}
constexpr Base(float) {}
};

struct FirstMiddle : Base {
using Base::Base;
constexpr FirstMiddle() : Base(2.0f) {}
};

struct SecondMiddle : Base {
constexpr SecondMiddle() : Base(3.0f) {}
constexpr SecondMiddle(T t) : Base(t) {}
};

struct S : FirstMiddle, SecondMiddle {
using FirstMiddle::FirstMiddle;
constexpr S(int i) : S(4.0f) {}
};

constexpr S s(1);
}
}

0 comments on commit 06774d6

Please sign in to comment.