Skip to content

Commit 06774d6

Browse files
committed
[clang][Interp] Handle CXXInheritedCtorInitExprs
We need to forward all arguments of the current function and call the ctor function.
1 parent d9e9276 commit 06774d6

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,6 +2020,37 @@ bool ByteCodeExprGen<Emitter>::VisitObjCBoolLiteralExpr(
20202020
return this->emitConst(E->getValue(), E);
20212021
}
20222022

2023+
template <class Emitter>
2024+
bool ByteCodeExprGen<Emitter>::VisitCXXInheritedCtorInitExpr(
2025+
const CXXInheritedCtorInitExpr *E) {
2026+
const CXXConstructorDecl *Ctor = E->getConstructor();
2027+
assert(!Ctor->isTrivial() &&
2028+
"Trivial CXXInheritedCtorInitExpr, implement. (possible?)");
2029+
const Function *F = this->getFunction(Ctor);
2030+
assert(F);
2031+
assert(!F->hasRVO());
2032+
assert(F->hasThisPointer());
2033+
2034+
if (!this->emitDupPtr(SourceInfo{}))
2035+
return false;
2036+
2037+
// Forward all arguments of the current function (which should be a
2038+
// constructor itself) to the inherited ctor.
2039+
// This is necessary because the calling code has pushed the pointer
2040+
// of the correct base for us already, but the arguments need
2041+
// to come after.
2042+
unsigned Offset = align(primSize(PT_Ptr)); // instance pointer.
2043+
for (const ParmVarDecl *PD : Ctor->parameters()) {
2044+
PrimType PT = this->classify(PD->getType()).value_or(PT_Ptr);
2045+
2046+
if (!this->emitGetParam(PT, Offset, E))
2047+
return false;
2048+
Offset += align(primSize(PT));
2049+
}
2050+
2051+
return this->emitCall(F, E);
2052+
}
2053+
20232054
template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
20242055
if (E->containsErrors())
20252056
return false;

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
111111
bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);
112112
bool VisitChooseExpr(const ChooseExpr *E);
113113
bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);
114+
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
114115

115116
protected:
116117
bool visitExpr(const Expr *E) override;

clang/test/AST/Interp/records.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,3 +1223,63 @@ namespace IndirectFieldInit {
12231223

12241224
#endif
12251225
}
1226+
1227+
namespace InheritedConstructor {
1228+
namespace PR47555 {
1229+
struct A {
1230+
int c;
1231+
int d;
1232+
constexpr A(int c, int d) : c(c), d(d){}
1233+
};
1234+
struct B : A { using A::A; };
1235+
1236+
constexpr B b = {13, 1};
1237+
static_assert(b.c == 13, "");
1238+
static_assert(b.d == 1, "");
1239+
}
1240+
1241+
namespace PR47555_2 {
1242+
struct A {
1243+
int c;
1244+
int d;
1245+
double e;
1246+
constexpr A(int c, int &d, double e) : c(c), d(++d), e(e){}
1247+
};
1248+
struct B : A { using A::A; };
1249+
1250+
constexpr int f() {
1251+
int a = 10;
1252+
B b = {10, a, 40.0};
1253+
return a;
1254+
}
1255+
static_assert(f() == 11, "");
1256+
}
1257+
1258+
namespace AaronsTest {
1259+
struct T {
1260+
constexpr T(float) {}
1261+
};
1262+
1263+
struct Base {
1264+
constexpr Base(T t = 1.0f) {}
1265+
constexpr Base(float) {}
1266+
};
1267+
1268+
struct FirstMiddle : Base {
1269+
using Base::Base;
1270+
constexpr FirstMiddle() : Base(2.0f) {}
1271+
};
1272+
1273+
struct SecondMiddle : Base {
1274+
constexpr SecondMiddle() : Base(3.0f) {}
1275+
constexpr SecondMiddle(T t) : Base(t) {}
1276+
};
1277+
1278+
struct S : FirstMiddle, SecondMiddle {
1279+
using FirstMiddle::FirstMiddle;
1280+
constexpr S(int i) : S(4.0f) {}
1281+
};
1282+
1283+
constexpr S s(1);
1284+
}
1285+
}

0 commit comments

Comments
 (0)