tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
This is just a humble beginning of course.
Posting this now for your weekend reading. And also to keep the individual
patches small.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D134057
Files:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/lib/AST/Interp/Interp.h
clang/test/AST/Interp/records.cpp
Index: clang/test/AST/Interp/records.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/records.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+struct Ints {
+ int a = 20;
+ int b = 30;
+ bool c = true;
+};
+
+constexpr Ints ints;
+static_assert(ints.a == 20, "");
+static_assert(ints.b == 30, "");
+static_assert(ints.c, "");
+
+struct Ints2 {
+ int a = 10;
+ int b;
+};
+// FIXME: Broken in the new constant interpreter.
+//constexpr Ints2 ints2;
+
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -492,6 +492,9 @@
return true;
}
+/// 1) Pops the value from the stack
+/// 2) Pops a pointer from the stack
+/// 3) Writes the value to field I of the pointer
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
const T &Value = S.Stk.pop<T>();
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -71,6 +71,7 @@
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
bool VisitCallExpr(const CallExpr *E);
+ bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@@ -81,6 +82,7 @@
bool VisitInitListExpr(const InitListExpr *E);
bool VisitConstantExpr(const ConstantExpr *E);
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
+ bool VisitMemberExpr(const MemberExpr *E);
protected:
bool visitExpr(const Expr *E) override;
@@ -138,6 +140,8 @@
bool visitInitializer(const Expr *E);
/// Compiles an array initializer.
bool visitArrayInitializer(const Expr *Initializer);
+ /// Compiles a record initializer.
+ bool visitRecordInitializer(const Expr *Initializer);
/// Visits an expression and converts it to a boolean.
bool visitBool(const Expr *E);
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -303,6 +303,26 @@
return false;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
+ // 'Base.Member'
+ const Expr *Base = E->getBase();
+ const ValueDecl *Member = E->getMemberDecl();
+
+ if (!this->visit(Base))
+ return false;
+
+ // Base above gives us a pointer on the stack.
+ const auto *FD = dyn_cast<FieldDecl>(Member);
+ assert(FD);
+ const RecordDecl *RD = FD->getParent();
+ assert(RD);
+ const Record *R = P.getOrCreateRecord(RD);
+ const Record::Field *F = R->getField(FD);
+ // Leave a pointer to the field on the stack.
+ return this->emitGetPtrField(F->Offset, E);
+}
+
template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
return this->Visit(E);
@@ -607,6 +627,44 @@
return true;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
+ assert(Initializer->getType()->isRecordType());
+
+ if (const auto CtorExpr = dyn_cast<CXXConstructExpr>(Initializer)) {
+ const CXXConstructorDecl *Ctor = CtorExpr->getConstructor();
+ const RecordDecl *RD = Ctor->getParent();
+ const Record *R = P.getOrCreateRecord(RD);
+
+ for (const auto *Init : Ctor->inits()) {
+ const FieldDecl *Member = Init->getMember();
+ const Expr *InitExpr = Init->getInit();
+
+ if (Optional<PrimType> T = classify(InitExpr->getType())) {
+ const Record::Field *F = R->getField(Member);
+
+ if (!this->emitDupPtr(Initializer))
+ return false;
+
+ if (!this->visit(InitExpr))
+ return false;
+
+ if (!this->emitInitField(*T, F->Offset, Initializer))
+ return false;
+ } else {
+ assert(false && "Handle initializer for non-primitive values");
+ }
+ }
+
+ // FIXME
+ const Stmt *Body = Ctor->getBody();
+ (void)Body;
+ return true;
+ }
+
+ return false;
+}
+
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *Initializer) {
QualType InitializerType = Initializer->getType();
@@ -614,6 +672,9 @@
if (InitializerType->isArrayType())
return visitArrayInitializer(Initializer);
+ if (InitializerType->isRecordType())
+ return visitRecordInitializer(Initializer);
+
// Otherwise, visit the expression like normal.
return this->Visit(Initializer);
}
@@ -763,6 +824,12 @@
return false;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr(
+ const CXXDefaultInitExpr *E) {
+ return this->visit(E->getExpr());
+}
+
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr(
const CXXDefaultArgExpr *E) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits