[clang] 33b5283 - [clang][Interp] Fix using default copy constructors
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 14 01:22:24 PDT 2022
Author: Timm Bäder
Date: 2022-10-14T10:21:53+02:00
New Revision: 33b52836de6e093acea15f24b6ae633f969d194a
URL: https://github.com/llvm/llvm-project/commit/33b52836de6e093acea15f24b6ae633f969d194a
DIFF: https://github.com/llvm/llvm-project/commit/33b52836de6e093acea15f24b6ae633f969d194a.diff
LOG: [clang][Interp] Fix using default copy constructors
Implement ArrayInitLoopExprs, which are used in copy constructors to
copy arrays. Also fix problems encountered while doing that.
Differential Revision: https://reviews.llvm.org/D134361
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/lib/AST/Interp/ByteCodeStmtGen.cpp
clang/test/AST/Interp/records.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 66e373e427c8..b9e7f4e2cdad 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -326,6 +326,18 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
return false;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
+ const ArrayInitIndexExpr *E) {
+ assert(ArrayIndex);
+ return this->emitConstUint64(*ArrayIndex, E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+ return this->visit(E->getSourceExpr());
+}
+
template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
return this->Visit(E);
@@ -628,6 +640,32 @@ bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
return true;
} else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
return this->visitInitializer(DIE->getExpr());
+ } else if (const auto *AILE = dyn_cast<ArrayInitLoopExpr>(Initializer)) {
+ // TODO: This compiles to quite a lot of bytecode if the array is larger.
+ // Investigate compiling this to a loop, or at least try to use
+ // the AILE's Common expr.
+ const Expr *SubExpr = AILE->getSubExpr();
+ size_t Size = AILE->getArraySize().getZExtValue();
+ Optional<PrimType> ElemT = classify(SubExpr->getType());
+
+ if (!ElemT)
+ return false;
+
+ for (size_t I = 0; I != Size; ++I) {
+ ArrayIndexScope<Emitter> IndexScope(this, I);
+ if (!this->emitDupPtr(SubExpr))
+ return false;
+
+ if (!this->visit(SubExpr))
+ return false;
+
+ if (!this->emitInitElem(*ElemT, I, Initializer))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ }
+ return true;
}
assert(false && "Unknown expression for array initialization");
@@ -642,13 +680,20 @@ bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
if (const auto CtorExpr = dyn_cast<CXXConstructExpr>(Initializer)) {
const Function *Func = getFunction(CtorExpr->getConstructor());
- if (!Func)
+ if (!Func || !Func->isConstexpr())
return false;
// The This pointer is already on the stack because this is an initializer,
// but we need to dup() so the call() below has its own copy.
if (!this->emitDupPtr(Initializer))
return false;
+
+ // Constructor arguments.
+ for (const auto *Arg : CtorExpr->arguments()) {
+ if (!this->visit(Arg))
+ return false;
+ }
+
return this->emitCallVoid(Func, Initializer);
} else if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
const Record *R = getRecord(InitList->getType());
@@ -657,15 +702,26 @@ bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
for (const Expr *Init : InitList->inits()) {
const Record::Field *FieldToInit = R->getField(InitIndex);
- if (Optional<PrimType> T = classify(Init->getType())) {
- if (!this->emitDupPtr(Initializer))
- return false;
+ if (!this->emitDupPtr(Initializer))
+ return false;
+ if (Optional<PrimType> T = classify(Init->getType())) {
if (!this->visit(Init))
return false;
if (!this->emitInitField(*T, FieldToInit->Offset, 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;
+
+ if (!this->visitInitializer(Init))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
}
++InitIndex;
}
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 14356ec9cdee..32ff72aa36fb 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -34,6 +34,7 @@ template <class Emitter> class RecordScope;
template <class Emitter> class VariableScope;
template <class Emitter> class DeclScope;
template <class Emitter> class OptionScope;
+template <class Emitter> class ArrayIndexScope;
/// Compilation context for expressions.
template <class Emitter>
@@ -85,6 +86,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitConstantExpr(const ConstantExpr *E);
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitMemberExpr(const MemberExpr *E);
+ bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
+ bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
protected:
bool visitExpr(const Expr *E) override;
@@ -199,6 +202,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
friend class RecordScope<Emitter>;
friend class DeclScope<Emitter>;
friend class OptionScope<Emitter>;
+ friend class ArrayIndexScope<Emitter>;
/// Emits a zero initializer.
bool visitZeroInitializer(PrimType T, const Expr *E);
@@ -260,7 +264,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
/// Current scope.
VariableScope<Emitter> *VarScope = nullptr;
- /// Current argument index.
+ /// Current argument index. Needed to emit ArrayInitIndexExpr.
llvm::Optional<uint64_t> ArrayIndex;
/// Flag indicating if return value is to be discarded.
@@ -362,6 +366,20 @@ template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
}
};
+template <class Emitter> class ArrayIndexScope final {
+public:
+ ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
+ OldArrayIndex = Ctx->ArrayIndex;
+ Ctx->ArrayIndex = Index;
+ }
+
+ ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
+
+private:
+ ByteCodeExprGen<Emitter> *Ctx;
+ Optional<uint64_t> OldArrayIndex;
+};
+
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index b4a61ebed0e7..3aa659822bb8 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -105,7 +105,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
const Record::Field *F = R->getField(Member);
if (Optional<PrimType> T = this->classify(InitExpr->getType())) {
- if (!this->emitDupPtr(InitExpr))
+ if (!this->emitThis(InitExpr))
return false;
if (!this->visit(InitExpr))
@@ -116,7 +116,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
} else {
// Non-primitive case. Get a pointer to the field-to-initialize
// on the stack and call visitInitialzer() for it.
- if (!this->emitDupPtr(InitExpr))
+ if (!this->emitThis(InitExpr))
return false;
if (!this->emitGetPtrField(F->Offset, InitExpr))
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 8d62b53d622a..1e61d4845a43 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -32,6 +32,9 @@ static_assert(ints.a == 20, "");
static_assert(ints.b == 30, "");
static_assert(ints.c, "");
static_assert(ints.getTen() == 10, "");
+static_assert(ints.numbers[0] == 1, "");
+static_assert(ints.numbers[1] == 2, "");
+static_assert(ints.numbers[2] == 3, "");
constexpr const BoolPair &BP = ints.bp;
static_assert(BP.first, "");
@@ -62,11 +65,17 @@ constexpr Ints ints4 = {
static_assert(ints4.a == (40 * 50), "");
static_assert(ints4.b == 0, "");
static_assert(ints4.c, "");
-
-
-// FIXME: Implement initialization by DeclRefExpr.
-//constexpr Ints ints4 = ints3; TODO
-
+static_assert(ints4.numbers[0] == 1, "");
+static_assert(ints4.numbers[1] == 2, "");
+static_assert(ints4.numbers[2] == 3, "");
+
+constexpr Ints ints5 = ints4;
+static_assert(ints5.a == (40 * 50), "");
+static_assert(ints5.b == 0, "");
+static_assert(ints5.c, "");
+static_assert(ints5.numbers[0] == 1, "");
+static_assert(ints5.numbers[1] == 2, "");
+static_assert(ints5.numbers[2] == 3, "");
struct Ints2 {
More information about the cfe-commits
mailing list