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 +bool ByteCodeExprGen::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(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 bool ByteCodeExprGen::discard(const Expr *E) { OptionScope Scope(this, /*NewDiscardResult=*/true); return this->Visit(E); @@ -607,6 +627,44 @@ return true; } +template +bool ByteCodeExprGen::visitRecordInitializer(const Expr *Initializer) { + assert(Initializer->getType()->isRecordType()); + + if (const auto CtorExpr = dyn_cast(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 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 bool ByteCodeExprGen::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 +bool ByteCodeExprGen::VisitCXXDefaultInitExpr( + const CXXDefaultInitExpr *E) { + return this->visit(E->getExpr()); +} + template bool ByteCodeExprGen::VisitCXXDefaultArgExpr( const CXXDefaultArgExpr *E) { 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 ::T> bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { const T &Value = S.Stk.pop(); 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; +