Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ 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 @@ bool visitConditional(const AbstractConditionalOperator *E, llvm::function_ref V); + bool visitInitList(ArrayRef Inits, const Expr *E); + /// Creates a local primitive value. unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst, bool IsExtended = false); Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -585,6 +585,65 @@ 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 (FieldToInit->isBitField()) { + if (!this->emitInitBitField(*T, FieldToInit, E)) + return false; + } else { + 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. @@ -604,61 +663,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 (FieldToInit->isBitField()) { - if (!this->emitInitBitField(*T, FieldToInit, E)) - return false; - } else { - 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. @@ -691,6 +697,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) { Index: clang/test/AST/Interp/records.cpp =================================================================== --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -931,3 +931,17 @@ } static_assert(BPand(BoolPair{true, false}) == false, ""); #endif + +#if __cplusplus >= 202002L +namespace ParenInit { + struct A { + int a; + }; + + struct B : A { + int b; + }; + + constexpr B b(A(1),2); +} +#endif Index: clang/test/SemaCXX/source_location.cpp =================================================================== --- clang/test/SemaCXX/source_location.cpp +++ clang/test/SemaCXX/source_location.cpp @@ -7,6 +7,7 @@ /// 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