diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -80,6 +80,7 @@ bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E); bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); bool VisitInitListExpr(const InitListExpr *E); + bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E); bool VisitConstantExpr(const ConstantExpr *E); bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); bool VisitMemberExpr(const MemberExpr *E); @@ -199,6 +200,8 @@ return this->emitPopPtr(I); } + bool visitInitList(ArrayRef Inits, const Expr *E); + /// Creates a local primitive value. unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst, bool IsExtended = false); diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -511,6 +511,58 @@ return this->emitArrayElemPtrPop(IndexT, E); } +template +bool ByteCodeExprGen::visitInitList(ArrayRef Inits, + const Expr *E) { + assert(E->getType()->isRecordType()); + const Record *R = getRecord(E->getType()); + + unsigned InitIndex = 0; + for (const Expr *Init : Inits) { + if (!this->emitDupPtr(E)) + return false; + + if (std::optional T = classify(Init)) { + const Record::Field *FieldToInit = R->getField(InitIndex); + if (!this->visit(Init)) + return false; + if (!this->emitInitField(*T, FieldToInit->Offset, E)) + return false; + if (!this->emitPopPtr(E)) + return false; + ++InitIndex; + } else { + // Initializer for a direct base class. + if (const Record::Base *B = R->getBase(Init->getType())) { + if (!this->emitGetPtrBasePop(B->Offset, Init)) + return false; + + if (!this->visitInitializer(Init)) + return false; + + if (!this->emitPopPtr(E)) + return false; + // Base initializers don't increase InitIndex, since they don't count + // into the Record's fields. + } else { + const Record::Field *FieldToInit = R->getField(InitIndex); + // 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(E)) + return false; + ++InitIndex; + } + } + } + return true; +} + template bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { // Handle discarding first. @@ -530,56 +582,8 @@ } QualType T = E->getType(); - if (T->isRecordType()) { - const Record *R = getRecord(T); - - unsigned InitIndex = 0; - for (const Expr *Init : E->inits()) { - if (!this->emitDupPtr(E)) - return false; - - if (std::optional T = classify(Init)) { - const Record::Field *FieldToInit = R->getField(InitIndex); - if (!this->visit(Init)) - return false; - - if (!this->emitInitField(*T, FieldToInit->Offset, E)) - return false; - - if (!this->emitPopPtr(E)) - return false; - ++InitIndex; - } else { - // Initializer for a direct base class. - if (const Record::Base *B = R->getBase(Init->getType())) { - if (!this->emitGetPtrBasePop(B->Offset, Init)) - return false; - - if (!this->visitInitializer(Init)) - return false; - - if (!this->emitPopPtr(E)) - return false; - // Base initializers don't increase InitIndex, since they don't count - // into the Record's fields. - } else { - const Record::Field *FieldToInit = R->getField(InitIndex); - // 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(E)) - return false; - ++InitIndex; - } - } - } - return true; - } + if (T->isRecordType()) + return this->visitInitList(E->inits(), E); if (T->isArrayType()) { // FIXME: Array fillers. @@ -612,6 +616,21 @@ return false; } +template +bool ByteCodeExprGen::VisitCXXParenListInitExpr( + const CXXParenListInitExpr *E) { + if (DiscardResult) { + for (const Expr *Init : E->getInitExprs()) { + if (!this->discard(Init)) + return false; + } + return true; + } + + assert(E->getType()->isRecordType()); + return this->visitInitList(E->getInitExprs(), E); +} + template bool ByteCodeExprGen::VisitSubstNonTypeTemplateParmExpr( const SubstNonTypeTemplateParmExpr *E) { diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -941,7 +941,7 @@ static_assert(foo(F()) == 0, ""); } -namespace ZeroInit { + namespace ZeroInit { struct F { int a; }; @@ -1052,3 +1052,17 @@ }; #endif } + +#if __cplusplus >= 202002L +namespace ParenInit { + struct A { + int a; + }; + + struct B : A { + int b; + }; + + constexpr B b(A(1),2); +} +#endif diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp --- a/clang/test/SemaCXX/source_location.cpp +++ b/clang/test/SemaCXX/source_location.cpp @@ -4,9 +4,9 @@ // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -verify %s // RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -verify %s // -/// FIXME: The -DPAREN_INIT one is missing for the new interpreter. // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s // RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s +// RUN: %clang_cc1 -std=c++2b -fcxx-exceptions -DUSE_CONSTEVAL -DPAREN_INIT -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s // RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s // expected-no-diagnostics