llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Jason Rice (ricejasonf) <details> <summary>Changes</summary> This is an implementation of P1061 Structure Bindings Introduce a Pack without the ability to use packs outside of templates. There is a couple of ways the AST could have been sliced so let me know what you think. The only part of this change that I am unsure of is the serialization/deserialization stuff. I followed the implementation of other Exprs, but I do not really know how it is tested. Thank you for your time considering this. --- Patch is 65.66 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/121417.diff 45 Files Affected: - (modified) clang/include/clang/AST/Decl.h (+4-4) - (modified) clang/include/clang/AST/DeclCXX.h (+15-7) - (modified) clang/include/clang/AST/ExprCXX.h (+48) - (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+1) - (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+5) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3) - (modified) clang/include/clang/Basic/StmtNodes.td (+1) - (modified) clang/include/clang/Sema/DeclSpec.h (+1) - (modified) clang/include/clang/Sema/Sema.h (+3-1) - (modified) clang/include/clang/Serialization/ASTBitCodes.h (+1) - (modified) clang/lib/AST/ASTContext.cpp (+9-5) - (modified) clang/lib/AST/ASTImporter.cpp (+1-1) - (modified) clang/lib/AST/Decl.cpp (+7-4) - (modified) clang/lib/AST/DeclBase.cpp (+4-2) - (modified) clang/lib/AST/DeclCXX.cpp (+55-5) - (modified) clang/lib/AST/Expr.cpp (+5) - (modified) clang/lib/AST/ExprCXX.cpp (+48) - (modified) clang/lib/AST/ExprClassification.cpp (+7) - (modified) clang/lib/AST/ExprConstant.cpp (+2-3) - (modified) clang/lib/AST/ItaniumMangle.cpp (+1-1) - (modified) clang/lib/AST/StmtPrinter.cpp (+11) - (modified) clang/lib/AST/StmtProfile.cpp (+4) - (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+2-2) - (modified) clang/lib/CodeGen/CGDecl.cpp (+1-4) - (modified) clang/lib/CodeGen/CodeGenModule.cpp (+1-3) - (modified) clang/lib/Parse/ParseDecl.cpp (+22-6) - (modified) clang/lib/Sema/SemaDecl.cpp (+10) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+171-38) - (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+4-3) - (modified) clang/lib/Sema/SemaLambda.cpp (+1) - (modified) clang/lib/Sema/SemaStmt.cpp (+8-6) - (modified) clang/lib/Sema/SemaTemplate.cpp (+4-3) - (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+38-2) - (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+30-2) - (modified) clang/lib/Sema/SemaTemplateVariadic.cpp (+65-8) - (modified) clang/lib/Sema/TreeTransform.h (+7) - (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+11) - (modified) clang/lib/Serialization/ASTWriter.cpp (+1) - (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+11) - (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+1) - (added) clang/test/Parser/cxx2c-binding-pack.cpp (+7) - (added) clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp (+12) - (added) clang/test/SemaCXX/cxx2c-binding-pack.cpp (+82) - (modified) clang/test/SemaCXX/typo-correction-crash.cpp (+2-1) - (modified) clang/tools/libclang/CXCursor.cpp (+1) ``````````diff diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 67ee0bb412692a..bdf6c81732d0bc 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -698,6 +698,10 @@ class ValueDecl : public NamedDecl { return const_cast<ValueDecl *>(this)->getPotentiallyDecomposedVarDecl(); } + /// Determine whether this value is actually a function parameter pack, + /// init-capture pack, or structured binding pack + bool isParameterPack() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; } @@ -1527,10 +1531,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> { NonParmVarDeclBits.IsInitCapture = IC; } - /// Determine whether this variable is actually a function parameter pack or - /// init-capture pack. - bool isParameterPack() const; - /// Whether this local extern variable declaration's previous declaration /// was declared in the same block scope. Only correct in C++. bool isPreviousDeclInSameBlockScope() const { diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index c232556edeff70..12002db17fb3ad 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -4131,8 +4131,9 @@ class BindingDecl : public ValueDecl { /// binding). Expr *Binding = nullptr; - BindingDecl(DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id) - : ValueDecl(Decl::Binding, DC, IdLoc, Id, QualType()) {} + BindingDecl(DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, + QualType T) + : ValueDecl(Decl::Binding, DC, IdLoc, Id, T) {} void anchor() override; @@ -4140,7 +4141,8 @@ class BindingDecl : public ValueDecl { friend class ASTDeclReader; static BindingDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation IdLoc, IdentifierInfo *Id); + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T); static BindingDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// Get the expression to which this declaration is bound. This may be null @@ -4152,10 +4154,6 @@ class BindingDecl : public ValueDecl { /// decomposition of. ValueDecl *getDecomposedDecl() const { return Decomp; } - /// Get the variable (if any) that holds the value of evaluating the binding. - /// Only present for user-defined bindings for tuple-like types. - VarDecl *getHoldingVar() const; - /// Set the binding for this BindingDecl, along with its declared type (which /// should be a possibly-cv-qualified form of the type of the binding, or a /// reference to such a type). @@ -4167,6 +4165,9 @@ class BindingDecl : public ValueDecl { /// Set the decomposed variable for this BindingDecl. void setDecomposedDecl(ValueDecl *Decomposed) { Decomp = Decomposed; } + VarDecl *getHoldingVar() const; + static VarDecl *getHoldingVar(Expr *E); + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decl::Binding; } }; @@ -4219,6 +4220,13 @@ class DecompositionDecl final void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override; + /// Visit the variables (if any) that hold the values of evaluating the + /// binding. Only present for user-defined bindings for tuple-like types. + void VisitHoldingVars(llvm::function_ref<void(VarDecl *)> F) const; + + // Visit the concrete bindings. (workaround) + void VisitBindings(llvm::function_ref<void(BindingDecl *)> F) const; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decomposition; } }; diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 4cec89c979f775..6162c712c90dc3 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5321,6 +5321,54 @@ class BuiltinBitCastExpr final } }; +class ResolvedUnexpandedPackExpr final + : public Expr, + private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Stmt *> { + friend TrailingObjects; + + SourceLocation BeginLoc; + unsigned NumExprs; + + ResolvedUnexpandedPackExpr(SourceLocation BL, QualType QT, unsigned NumExprs); + +public: + static ResolvedUnexpandedPackExpr *CreateDeserialized(ASTContext &C, + unsigned NumExprs); + static ResolvedUnexpandedPackExpr * + Create(ASTContext &C, SourceLocation BeginLoc, QualType T, unsigned NumExprs); + static ResolvedUnexpandedPackExpr *Create(ASTContext &C, + SourceLocation BeginLoc, QualType T, + llvm::ArrayRef<Expr *> Exprs); + + unsigned getNumExprs() const { return NumExprs; } + + Expr **getExprs() { + return reinterpret_cast<Expr **>(getTrailingObjects<Stmt *>()); + } + Expr *const *getExprs() const { + return reinterpret_cast<Expr *const *>(getTrailingObjects<Stmt *>()); + } + + Expr *getExpansion(unsigned Idx) { return getExprs()[Idx]; } + Expr *getExpansion(unsigned Idx) const { return getExprs()[Idx]; } + + // Iterators + child_range children() { + return child_range(getTrailingObjects<Stmt *>(), + getTrailingObjects<Stmt *>() + getNumExprs()); + } + + SourceLocation getBeginLoc() const LLVM_READONLY { return BeginLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return BeginLoc; } + + // Returns the resolved pack of a decl or nullptr + static ResolvedUnexpandedPackExpr *getFromDecl(Decl *); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ResolvedUnexpandedPackExprClass; + } +}; + } // namespace clang #endif // LLVM_CLANG_AST_EXPRCXX_H diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f5b32ed51698e0..9f8a8f2a8348f2 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2936,6 +2936,7 @@ DEF_TRAVERSE_STMT(FunctionParmPackExpr, {}) DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) DEF_TRAVERSE_STMT(CXXParenListInitExpr, {}) +DEF_TRAVERSE_STMT(ResolvedUnexpandedPackExpr, {}) DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { if (S->getLifetimeExtendedTemporaryDecl()) { diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 86fcae209c40db..5ee6f9ff28c4c8 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1099,6 +1099,11 @@ def err_lambda_capture_misplaced_ellipsis : Error< "the name of the capture">; def err_lambda_capture_multiple_ellipses : Error< "multiple ellipses in pack capture">; +def err_binding_multiple_ellipses : Error< + "multiple ellipses in structured binding declaration">; +def warn_cxx2c_binding_pack : Warning< + "structured binding pack is incompatible with C++ standards before C++2c">, + DefaultIgnore, InGroup<CXXPre26Compat>; def err_capture_default_first : Error< "capture default must be first">; def ext_decl_attrs_on_lambda : ExtWarn< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 330ae045616aba..22012fb2663534 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5906,6 +5906,9 @@ def warn_cxx23_pack_indexing : Warning< "pack indexing is incompatible with C++ standards before C++2c">, DefaultIgnore, InGroup<CXXPre26Compat>; +def err_pack_outside_template : Error< + "pack declaration outside of template">; + def err_fold_expression_packs_both_sides : Error< "binary fold expression has unexpanded parameter packs in both operands">; def err_fold_expression_empty : Error< diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 31280df93e4c6e..a5ac8eba371f2f 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -162,6 +162,7 @@ def MaterializeTemporaryExpr : StmtNode<Expr>; def LambdaExpr : StmtNode<Expr>; def CXXFoldExpr : StmtNode<Expr>; def CXXParenListInitExpr: StmtNode<Expr>; +def ResolvedUnexpandedPackExpr : StmtNode<Expr>; // C++ Coroutines expressions def CoroutineSuspendExpr : StmtNode<Expr, 1>; diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 06243f2624876f..5f5df3a45d41dc 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1795,6 +1795,7 @@ class DecompositionDeclarator { IdentifierInfo *Name; SourceLocation NameLoc; std::optional<ParsedAttributes> Attrs; + SourceLocation EllipsisLoc; }; private: diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5ee7ea48cc983c..24e13278cb2a89 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -230,7 +230,8 @@ void threadSafetyCleanup(BeforeSet *Cache); // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. -typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>, +typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *, + ResolvedUnexpandedPackExpr *>, SourceLocation> UnexpandedParameterPack; @@ -6012,6 +6013,7 @@ class Sema final : public SemaBase { RecordDecl *ClassDecl, const IdentifierInfo *Name); + unsigned GetDecompositionElementCount(QualType DecompType); void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD); /// Stack containing information needed when in C++2a an 'auto' is encountered diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index dfd82afad40070..bab63be73e58e8 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1890,6 +1890,7 @@ enum StmtCode { EXPR_PACK_EXPANSION, // PackExpansionExpr EXPR_PACK_INDEXING, // PackIndexingExpr EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_RESOLVED_UNEXPANDED_PACK, // ResolvedUnexpandedPackExpr EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8b4ae58e8427a9..6216d896a88ac3 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -12726,11 +12726,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { // Likewise, variables with tuple-like bindings are required if their // bindings have side-effects. - if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) - for (const auto *BD : DD->bindings()) - if (const auto *BindingVD = BD->getHoldingVar()) - if (DeclMustBeEmitted(BindingVD)) - return true; + if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) { + bool BindingResult = false; + DD->VisitHoldingVars([&](VarDecl *BindingVD) { + if (DeclMustBeEmitted(BindingVD)) + BindingResult = true; + }); + if (BindingResult) + return true; + } return false; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 26d33b0d94795f..33b4fe0b8fecc9 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2552,7 +2552,7 @@ ExpectedDecl ASTNodeImporter::VisitBindingDecl(BindingDecl *D) { BindingDecl *ToD; if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, Loc, - Name.getAsIdentifierInfo())) + Name.getAsIdentifierInfo(), D->getType())) return ToD; Error Err = Error::success(); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 741e908cf9bc56..76c208bef6031c 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2659,10 +2659,6 @@ bool VarDecl::checkForConstantInitialization( return Eval->HasConstantInitialization; } -bool VarDecl::isParameterPack() const { - return isa<PackExpansionType>(getType()); -} - template<typename DeclT> static DeclT *getDefinitionOrSelf(DeclT *D) { assert(D); @@ -5397,6 +5393,13 @@ bool ValueDecl::isInitCapture() const { return false; } +bool ValueDecl::isParameterPack() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(this)) + return NTTP->isParameterPack(); + + return isa_and_nonnull<PackExpansionType>(getType().getTypePtrOrNull()); +} + void ImplicitParamDecl::anchor() {} ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index fb701f76231bcd..6a5662f9d074e4 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -237,10 +237,12 @@ bool Decl::isTemplateParameterPack() const { } bool Decl::isParameterPack() const { - if (const auto *Var = dyn_cast<VarDecl>(this)) + if (isTemplateParameterPack()) + return true; + if (const auto *Var = dyn_cast<ValueDecl>(this)) return Var->isParameterPack(); - return isTemplateParameterPack(); + return false; } FunctionDecl *Decl::getAsFunction() { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index af73c658d6a0c5..371bf5dcf02206 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -3395,26 +3395,37 @@ VarDecl *ValueDecl::getPotentiallyDecomposedVarDecl() { if (auto *Var = llvm::dyn_cast<VarDecl>(this)) return Var; if (auto *BD = llvm::dyn_cast<BindingDecl>(this)) - return llvm::dyn_cast<VarDecl>(BD->getDecomposedDecl()); + return llvm::dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl()); return nullptr; } void BindingDecl::anchor() {} BindingDecl *BindingDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation IdLoc, IdentifierInfo *Id) { - return new (C, DC) BindingDecl(DC, IdLoc, Id); + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T) { + return new (C, DC) BindingDecl(DC, IdLoc, Id, T); } BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr); + return new (C, ID) + BindingDecl(nullptr, SourceLocation(), nullptr, QualType()); } VarDecl *BindingDecl::getHoldingVar() const { Expr *B = getBinding(); if (!B) return nullptr; - auto *DRE = dyn_cast<DeclRefExpr>(B->IgnoreImplicit()); + return getHoldingVar(B); +} + +VarDecl *BindingDecl::getHoldingVar(Expr *E) { + auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreImplicit()); + if (!DRE) + return nullptr; + if (auto *BD = dyn_cast<BindingDecl>(DRE->getDecl())) { + DRE = dyn_cast<DeclRefExpr>(BD->getBinding()); + } if (!DRE) return nullptr; @@ -3423,6 +3434,45 @@ VarDecl *BindingDecl::getHoldingVar() const { return VD; } +void DecompositionDecl::VisitHoldingVars( + llvm::function_ref<void(VarDecl *)> F) const { + for (BindingDecl *B : bindings()) { + Expr *BE = B->getBinding(); + // All BindingDecls will contain holding vars or none will + if (!BE) + return; + + llvm::ArrayRef<Expr *> Exprs; + if (auto *RP = dyn_cast<ResolvedUnexpandedPackExpr>(BE)) + Exprs = llvm::ArrayRef(RP->getExprs(), RP->getNumExprs()); + else + Exprs = BE; + + for (Expr *E : Exprs) { + VarDecl *VD = BindingDecl::getHoldingVar(E); + if (!VD) + return; + F(VD); + } + } +} + +void DecompositionDecl::VisitBindings( + llvm::function_ref<void(BindingDecl *)> F) const { + for (BindingDecl *B : bindings()) { + llvm::ArrayRef<Expr *> Exprs; + if (B->isParameterPack()) { + auto *RP = cast<ResolvedUnexpandedPackExpr>(B->getBinding()); + Exprs = llvm::ArrayRef(RP->getExprs(), RP->getNumExprs()); + for (Expr *E : Exprs) { + auto *DRE = cast<DeclRefExpr>(E); + F(cast<BindingDecl>(DRE->getDecl())); + } + } else + F(B); + } +} + void DecompositionDecl::anchor() {} DecompositionDecl *DecompositionDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 8c8ccdb61dc01c..39f02ebf85b2ce 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3656,6 +3656,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, // These never have a side-effect. return false; + // ResolvedUnexpandedPackExpr is currently only used for + // structed bindings which have no side effects + case ResolvedUnexpandedPackExprClass: + return false; + case ConstantExprClass: // FIXME: Move this into the "return false;" block above. return cast<ConstantExpr>(this)->getSubExpr()->HasSideEffects( diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index fc09d24fc30cb4..190af789d306ed 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1965,3 +1965,51 @@ CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee, SubExprs[SubExpr::RHS] = RHS; setDependence(computeDependence(this)); } + +ResolvedUnexpandedPackExpr::ResolvedUnexpandedPackExpr(SourceLocation BL, + QualType QT, + unsigned NumExprs) + : Expr(ResolvedUnexpandedPackExprClass, QT, VK_PRValue, OK_Ordinary), + BeginLoc(BL), NumExprs(NumExprs) { + setDependence(ExprDependence::TypeValueInstantiation | + ExprDependence::UnexpandedPack); +} + +ResolvedUnexpandedPackExpr * +ResolvedUnexpandedPackExpr::CreateDeserialized(ASTContext &Ctx, + unsigned NumExprs) { + void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumExprs), + alignof(ResolvedUnexpandedPackExpr)); + return new (Mem) + ResolvedUnexpandedPackExpr(SourceLocation(), QualType(), NumExprs); +} + +ResolvedUnexpandedPackExpr * +ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL, + QualType T, unsigned NumExprs) { + void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumExprs), + alignof(ResolvedUnexpandedPackExpr)); + ResolvedUnexpandedPackExpr *New = + new (Mem) ResolvedUnexpandedPackExpr(BL, T, NumExprs); + + auto Exprs = llvm::MutableArrayRef(New->getExprs(), New->getNumExprs()); + std::fill(Exprs.begin(), Exprs.end(), nullptr); + + return New; +} + +ResolvedUnexpandedPackExpr * +ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL, + QualType T, ArrayRef<Expr *> Exprs) { + auto *New = Create(Ctx, BL, T, Exprs.size()); + std::copy(Exprs.begin(), Exprs.end(), New->getExprs()); + return New; +} + +ResolvedUnexpandedPackExpr *ResolvedUnexpandedPackExpr::getFromDecl(Decl *D) { + // TODO P1858: Extend to VarDecls for P1858 + if (auto *BD = dyn_cast<BindingDecl>(D)) { + return dyn_cast_or_null<ResolvedUnexpandedPackExpr>(BD->getBinding()); + } + return nullptr; +} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 3f37d06cc8f3a0..29a869bd76ca37 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -451,6 +451,13 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::PackExpansionExprClass: return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern()); + case Expr::ResolvedUnexpandedPackExprClass: { + if (cast<ResolvedUnexpandedPackExpr>(E)->getNumExprs() > 0) + return ClassifyInternal( + Ctx, cast<ResolvedUnexpandedPackExpr>(E)->getExpansion(0)); + return Cl::CL_PRVa... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/121417 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits