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

Reply via email to