https://github.com/Sirraide created 
https://github.com/llvm/llvm-project/pull/169680

None

>From e5f2dd466d5126594a159fc37a96ba6b54978e26 Mon Sep 17 00:00:00 2001
From: Sirraide <[email protected]>
Date: Tue, 25 Nov 2025 17:18:05 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 1)

---
 clang/include/clang/AST/ASTNodeTraverser.h    |   6 +
 clang/include/clang/AST/ComputeDependence.h   |   3 +
 clang/include/clang/AST/Decl.h                |   4 +-
 clang/include/clang/AST/DeclBase.h            |  13 +
 clang/include/clang/AST/DeclTemplate.h        | 114 +++++
 clang/include/clang/AST/ExprCXX.h             | 159 ++++++
 clang/include/clang/AST/RecursiveASTVisitor.h |  17 +
 clang/include/clang/AST/StmtCXX.h             | 478 ++++++++++++++++++
 clang/include/clang/AST/TextNodeDumper.h      |   5 +
 clang/include/clang/Basic/DeclNodes.td        |   1 +
 clang/include/clang/Basic/StmtNodes.td        |  14 +
 .../include/clang/Serialization/ASTBitCodes.h |  41 +-
 clang/lib/AST/ASTImporter.cpp                 | 174 +++++++
 clang/lib/AST/ComputeDependence.cpp           |   7 +
 clang/lib/AST/DeclBase.cpp                    |  14 +-
 clang/lib/AST/DeclPrinter.cpp                 |   6 +
 clang/lib/AST/DeclTemplate.cpp                |  23 +
 clang/lib/AST/Expr.cpp                        |   3 +
 clang/lib/AST/ExprCXX.cpp                     |  58 +++
 clang/lib/AST/ExprClassification.cpp          |   3 +
 clang/lib/AST/ExprConstant.cpp                |   3 +
 clang/lib/AST/ItaniumMangle.cpp               |  10 +-
 clang/lib/AST/StmtCXX.cpp                     | 153 ++++++
 clang/lib/AST/StmtPrinter.cpp                 |  62 ++-
 clang/lib/AST/StmtProfile.cpp                 |  47 ++
 clang/lib/AST/TextNodeDumper.cpp              |  23 +-
 clang/lib/Sema/Sema.cpp                       |   7 +-
 clang/lib/Sema/SemaDecl.cpp                   |   4 +-
 clang/lib/Sema/SemaExceptionSpec.cpp          |   8 +
 clang/lib/Sema/SemaExpr.cpp                   |   5 +-
 clang/lib/Sema/SemaExprCXX.cpp                |   1 -
 clang/lib/Sema/SemaLambda.cpp                 |  28 +-
 clang/lib/Sema/SemaLookup.cpp                 |   4 +-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |   5 +
 clang/lib/Sema/TreeTransform.h                |  53 ++
 clang/lib/Serialization/ASTCommon.cpp         |   1 +
 clang/lib/Serialization/ASTReaderDecl.cpp     |  12 +
 clang/lib/Serialization/ASTReaderStmt.cpp     | 107 ++++
 clang/lib/Serialization/ASTWriterDecl.cpp     |   9 +
 clang/lib/Serialization/ASTWriterStmt.cpp     |  79 +++
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |   8 +
 clang/tools/libclang/CIndex.cpp               |   1 +
 clang/tools/libclang/CXCursor.cpp             |   8 +
 43 files changed, 1744 insertions(+), 37 deletions(-)

diff --git a/clang/include/clang/AST/ASTNodeTraverser.h 
b/clang/include/clang/AST/ASTNodeTraverser.h
index e74bb72571d64..fd64d86f83bfd 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -959,6 +959,12 @@ class ASTNodeTraverser
     }
   }
 
+  void VisitCXXExpansionStmtDecl(const CXXExpansionStmtDecl *Node) {
+    Visit(Node->getExpansionPattern());
+    if (Traversal != TK_IgnoreUnlessSpelledInSource)
+      Visit(Node->getInstantiations());
+  }
+
   void VisitCallExpr(const CallExpr *Node) {
     for (const auto *Child :
          make_filter_range(Node->children(), [this](const Stmt *Child) {
diff --git a/clang/include/clang/AST/ComputeDependence.h 
b/clang/include/clang/AST/ComputeDependence.h
index c298f2620f211..792f45bea5aeb 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -94,6 +94,7 @@ class DesignatedInitExpr;
 class ParenListExpr;
 class PseudoObjectExpr;
 class AtomicExpr;
+class CXXExpansionInitListExpr;
 class ArraySectionExpr;
 class OMPArrayShapingExpr;
 class OMPIteratorExpr;
@@ -191,6 +192,8 @@ ExprDependence computeDependence(ParenListExpr *E);
 ExprDependence computeDependence(PseudoObjectExpr *E);
 ExprDependence computeDependence(AtomicExpr *E);
 
+ExprDependence computeDependence(CXXExpansionInitListExpr *E);
+
 ExprDependence computeDependence(ArraySectionExpr *E);
 ExprDependence computeDependence(OMPArrayShapingExpr *E);
 ExprDependence computeDependence(OMPIteratorExpr *E);
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index ee2321dd158d4..b8f8e002ebcce 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1254,7 +1254,9 @@ class VarDecl : public DeclaratorDecl, public 
Redeclarable<VarDecl> {
     if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
       return false;
     if (const DeclContext *DC = getLexicalDeclContext())
-      return DC->getRedeclContext()->isFunctionOrMethod();
+      return DC->getEnclosingNonExpansionStatementContext()
+          ->getRedeclContext()
+          ->isFunctionOrMethod();
     return false;
   }
 
diff --git a/clang/include/clang/AST/DeclBase.h 
b/clang/include/clang/AST/DeclBase.h
index 5519787d71f88..71e6898f4c94d 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -2195,6 +2195,10 @@ class DeclContext {
     return getDeclKind() == Decl::RequiresExprBody;
   }
 
+  bool isExpansionStmt() const {
+    return getDeclKind() == Decl::CXXExpansionStmt;
+  }
+
   bool isNamespace() const { return getDeclKind() == Decl::Namespace; }
 
   bool isStdNamespace() const;
@@ -2292,6 +2296,15 @@ class DeclContext {
     return const_cast<DeclContext *>(this)->getOuterLexicalRecordContext();
   }
 
+  /// Retrieve the innermost enclosing context that doesn't belong to an
+  /// expansion statement. Returns 'this' if this context is not an expansion
+  /// statement.
+  DeclContext *getEnclosingNonExpansionStatementContext();
+  const DeclContext *getEnclosingNonExpansionStatementContext() const {
+    return const_cast<DeclContext *>(this)
+        ->getEnclosingNonExpansionStatementContext();
+  }
+
   /// Test if this context is part of the enclosing namespace set of
   /// the context NS, as defined in C++0x [namespace.def]p9. If either context
   /// isn't a namespace, this is equivalent to Equals().
diff --git a/clang/include/clang/AST/DeclTemplate.h 
b/clang/include/clang/AST/DeclTemplate.h
index a4a1bb9c13c79..45a58b6589074 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
   static bool classofKind(Kind K) { return K == TemplateParamObject; }
 };
 
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends 
on
+/// the kind of expansion statement); by contrast we may sometimes 
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter 
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and 
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+///   std::tuple<int, int, int> a{1, 2, 3};
+///   template for (auto x : a) {
+///     // ...
+///   }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is 
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion:
+///
+/// \verbatim
+/// {
+///   auto [__u0, __u1, __u2] = a;
+///   {
+///     auto x = __u0;
+///     // ...
+///   }
+///   {
+///     auto x = __u1;
+///     // ...
+///   }
+///   {
+///     auto x = __u2;
+///     // ...
+///   }
+/// }
+/// \endverbatim
+///
+/// The outer braces shown above are implicit; we don't actually create another
+/// CompoundStmt wrapping everything.
+///
+/// \see CXXExpansionStmtPattern
+/// \see CXXExpansionStmtInstantiation
+class CXXExpansionStmtDecl : public Decl, public DeclContext {
+  CXXExpansionStmtPattern *Expansion = nullptr;
+  TemplateParameterList *TParams;
+  CXXExpansionStmtInstantiation *Instantiations = nullptr;
+
+  CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc,
+                       TemplateParameterList *TParams);
+
+public:
+  friend class ASTDeclReader;
+
+  static CXXExpansionStmtDecl *Create(ASTContext &C, DeclContext *DC,
+                                      SourceLocation Loc,
+                                      TemplateParameterList *TParams);
+  static CXXExpansionStmtDecl *CreateDeserialized(ASTContext &C,
+                                                  GlobalDeclID ID);
+
+  CXXExpansionStmtPattern *getExpansionPattern() { return Expansion; }
+  const CXXExpansionStmtPattern *getExpansionPattern() const {
+    return Expansion;
+  }
+  void setExpansionPattern(CXXExpansionStmtPattern *S) { Expansion = S; }
+
+  CXXExpansionStmtInstantiation *getInstantiations() { return Instantiations; }
+  const CXXExpansionStmtInstantiation *getInstantiations() const {
+    return Instantiations;
+  }
+
+  void setInstantiations(CXXExpansionStmtInstantiation *S) {
+    Instantiations = S;
+  }
+
+  NonTypeTemplateParmDecl *getIndexTemplateParm() const {
+    return cast<NonTypeTemplateParmDecl>(TParams->getParam(0));
+  }
+  TemplateParameterList *getTemplateParameters() const { return TParams; }
+
+  SourceRange getSourceRange() const override LLVM_READONLY;
+
+  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+  static bool classofKind(Kind K) { return K == CXXExpansionStmt; }
+};
+
 inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
   if (auto *PD = P.dyn_cast<TemplateTypeParmDecl *>())
     return PD;
diff --git a/clang/include/clang/AST/ExprCXX.h 
b/clang/include/clang/AST/ExprCXX.h
index 9435ab069a520..668a51dad0ae9 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -5499,6 +5499,165 @@ class BuiltinBitCastExpr final
   }
 };
 
+/// Represents an expansion-init-list of an enumerating expansion statement.
+///
+/// \see CXXEnumeratingExpansionStmtPattern
+class CXXExpansionInitListExpr final
+    : public Expr,
+      llvm::TrailingObjects<CXXExpansionInitListExpr, Expr *> {
+  friend class ASTStmtReader;
+  friend TrailingObjects;
+
+  const unsigned NumExprs;
+  SourceLocation LBraceLoc;
+  SourceLocation RBraceLoc;
+
+  CXXExpansionInitListExpr(EmptyShell ES, unsigned NumExprs);
+  CXXExpansionInitListExpr(ArrayRef<Expr *> Exprs, SourceLocation LBraceLoc,
+                           SourceLocation RBraceLoc);
+
+public:
+  static CXXExpansionInitListExpr *Create(const ASTContext &C,
+                                          ArrayRef<Expr *> Exprs,
+                                          SourceLocation LBraceLoc,
+                                          SourceLocation RBraceLoc);
+
+  static CXXExpansionInitListExpr *
+  CreateEmpty(const ASTContext &C, EmptyShell Empty, unsigned NumExprs);
+
+  ArrayRef<Expr *> getExprs() const { return getTrailingObjects(NumExprs); }
+  MutableArrayRef<Expr *> getExprs() { return getTrailingObjects(NumExprs); }
+  unsigned getNumExprs() const { return NumExprs; }
+
+  bool containsPackExpansion() const;
+
+  SourceLocation getBeginLoc() const { return getLBraceLoc(); }
+  SourceLocation getEndLoc() const { return getRBraceLoc(); }
+
+  SourceLocation getLBraceLoc() const { return LBraceLoc; }
+  SourceLocation getRBraceLoc() const { return RBraceLoc; }
+
+  child_range children() {
+    const_child_range CCR =
+        const_cast<const CXXExpansionInitListExpr *>(this)->children();
+    return child_range(cast_away_const(CCR.begin()),
+                       cast_away_const(CCR.end()));
+  }
+
+  const_child_range children() const {
+    Stmt **Stmts = getTrailingStmts();
+    return const_child_range(Stmts, Stmts + NumExprs);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXExpansionInitListExprClass;
+  }
+
+private:
+  Stmt **getTrailingStmts() const {
+    return reinterpret_cast<Stmt **>(const_cast<Expr 
**>(getTrailingObjects()));
+  }
+};
+
+/// Helper that selects an expression from an expansion init list depending
+/// on the current expansion index.
+///
+/// \see CXXEnumeratingExpansionStmtPattern
+class CXXExpansionInitListSelectExpr : public Expr {
+  friend class ASTStmtReader;
+
+  enum SubExpr { RANGE, INDEX, COUNT };
+  Expr *SubExprs[COUNT];
+
+public:
+  CXXExpansionInitListSelectExpr(EmptyShell Empty);
+  CXXExpansionInitListSelectExpr(const ASTContext &C,
+                                 CXXExpansionInitListExpr *Range, Expr *Idx);
+
+  CXXExpansionInitListExpr *getRangeExpr() {
+    return cast<CXXExpansionInitListExpr>(SubExprs[RANGE]);
+  }
+
+  const CXXExpansionInitListExpr *getRangeExpr() const {
+    return cast<CXXExpansionInitListExpr>(SubExprs[RANGE]);
+  }
+
+  void setRangeExpr(CXXExpansionInitListExpr *E) { SubExprs[RANGE] = E; }
+
+  Expr *getIndexExpr() { return SubExprs[INDEX]; }
+  const Expr *getIndexExpr() const { return SubExprs[INDEX]; }
+  void setIndexExpr(Expr *E) { SubExprs[INDEX] = E; }
+
+  SourceLocation getBeginLoc() const { return getRangeExpr()->getBeginLoc(); }
+  SourceLocation getEndLoc() const { return getRangeExpr()->getEndLoc(); }
+
+  child_range children() {
+    return child_range(reinterpret_cast<Stmt **>(SubExprs),
+                       reinterpret_cast<Stmt **>(SubExprs + COUNT));
+  }
+
+  const_child_range children() const {
+    return const_child_range(
+        reinterpret_cast<Stmt **>(const_cast<Expr **>(SubExprs)),
+        reinterpret_cast<Stmt **>(const_cast<Expr **>(SubExprs + COUNT)));
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXExpansionInitListSelectExprClass;
+  }
+};
+
+/// This class serves the same purpose as CXXExpansionInitListSelectExpr, but
+/// for destructuring expansion statements; that is, instead of selecting among
+/// a list of expressions, it selects from a list of 'BindingDecl's.
+///
+/// \see CXXEnumeratingExpansionStmtPattern
+/// \see CXXDestructuringExpansionStmtPattern
+class CXXDestructuringExpansionSelectExpr : public Expr {
+  friend class ASTStmtReader;
+
+  DecompositionDecl *Decomposition;
+  Expr *Index;
+
+public:
+  CXXDestructuringExpansionSelectExpr(EmptyShell Empty);
+  CXXDestructuringExpansionSelectExpr(const ASTContext &C,
+                                      DecompositionDecl *Decomposition,
+                                      Expr *Index);
+
+  DecompositionDecl *getDecompositionDecl() {
+    return cast<DecompositionDecl>(Decomposition);
+  }
+
+  const DecompositionDecl *getDecompositionDecl() const {
+    return cast<DecompositionDecl>(Decomposition);
+  }
+
+  void setDecompositionDecl(DecompositionDecl *E) { Decomposition = E; }
+
+  Expr *getIndexExpr() { return Index; }
+  const Expr *getIndexExpr() const { return Index; }
+  void setIndexExpr(Expr *E) { Index = E; }
+
+  SourceLocation getBeginLoc() const { return Decomposition->getBeginLoc(); }
+  SourceLocation getEndLoc() const { return Decomposition->getEndLoc(); }
+
+  child_range children() {
+    return child_range(reinterpret_cast<Stmt **>(&Index),
+                       reinterpret_cast<Stmt **>(&Index + 1));
+  }
+
+  const_child_range children() const {
+    return const_child_range(
+        reinterpret_cast<Stmt **>(const_cast<Expr **>(&Index)),
+        reinterpret_cast<Stmt **>(const_cast<Expr **>(&Index + 1)));
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXDestructuringExpansionSelectExprClass;
+  }
+};
+
 } // 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 8f427427d71ed..24052df70c7a8 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1881,6 +1881,14 @@ DEF_TRAVERSE_DECL(UsingShadowDecl, {})
 
 DEF_TRAVERSE_DECL(ConstructorUsingShadowDecl, {})
 
+DEF_TRAVERSE_DECL(CXXExpansionStmtDecl, {
+  if (D->getInstantiations() &&
+      getDerived().shouldVisitTemplateInstantiations())
+    TRY_TO(TraverseStmt(D->getInstantiations()));
+
+  TRY_TO(TraverseStmt(D->getExpansionPattern()));
+})
+
 DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
   for (auto *I : D->varlist()) {
     TRY_TO(TraverseStmt(I));
@@ -3117,6 +3125,15 @@ DEF_TRAVERSE_STMT(RequiresExpr, {
     TRY_TO(TraverseConceptRequirement(Req));
 })
 
+DEF_TRAVERSE_STMT(CXXEnumeratingExpansionStmtPattern, {})
+DEF_TRAVERSE_STMT(CXXIteratingExpansionStmtPattern, {})
+DEF_TRAVERSE_STMT(CXXDestructuringExpansionStmtPattern, {})
+DEF_TRAVERSE_STMT(CXXDependentExpansionStmtPattern, {})
+DEF_TRAVERSE_STMT(CXXExpansionStmtInstantiation, {})
+DEF_TRAVERSE_STMT(CXXExpansionInitListExpr, {})
+DEF_TRAVERSE_STMT(CXXExpansionInitListSelectExpr, {})
+DEF_TRAVERSE_STMT(CXXDestructuringExpansionSelectExpr, {})
+
 // These literals (all of them) do not need any action.
 DEF_TRAVERSE_STMT(IntegerLiteral, {})
 DEF_TRAVERSE_STMT(FixedPointLiteral, {})
diff --git a/clang/include/clang/AST/StmtCXX.h 
b/clang/include/clang/AST/StmtCXX.h
index 5d68d3ef64a20..96c3f912d6c3e 100644
--- a/clang/include/clang/AST/StmtCXX.h
+++ b/clang/include/clang/AST/StmtCXX.h
@@ -22,6 +22,7 @@
 namespace clang {
 
 class VarDecl;
+class CXXExpansionStmtDecl;
 
 /// CXXCatchStmt - This represents a C++ catch block.
 ///
@@ -524,6 +525,483 @@ class CoreturnStmt : public Stmt {
   }
 };
 
+/// CXXExpansionStmtPattern - Base class for an unexpanded C++ expansion
+/// statement.
+///
+/// The main purpose for this class is to store the AST nodes common to all
+/// variants of expansion statements; it also provides storage for additional
+/// subexpressions required by its derived classes. This is to simplify the
+/// implementation of 'children()' and friends.
+///
+/// \see CXXExpansionStmtDecl
+/// \see CXXEnumeratingExpansionStmtPattern
+/// \see CXXIteratingExpansionStmtPattern
+/// \see CXXDestructuringExpansionStmtPattern
+/// \see CXXDependentExpansionStmtPattern
+class CXXExpansionStmtPattern : public Stmt {
+  friend class ASTStmtReader;
+
+  CXXExpansionStmtDecl *ParentDecl;
+  SourceLocation LParenLoc;
+  SourceLocation ColonLoc;
+  SourceLocation RParenLoc;
+
+protected:
+  enum SubStmt {
+    INIT,
+    VAR,
+    BODY,
+    FIRST_CHILD_STMT,
+
+    // CXXDependentExpansionStmtPattern
+    EXPANSION_INITIALIZER = FIRST_CHILD_STMT,
+    COUNT_CXXDependentExpansionStmtPattern,
+
+    // CXXDestructuringExpansionStmtPattern
+    DECOMP_DECL = FIRST_CHILD_STMT,
+    COUNT_CXXDestructuringExpansionStmtPattern,
+
+    // CXXIteratingExpansionStmtPattern
+    RANGE = FIRST_CHILD_STMT,
+    BEGIN,
+    END,
+    COUNT_CXXIteratingExpansionStmtPattern,
+
+    MAX_COUNT = COUNT_CXXIteratingExpansionStmtPattern,
+  };
+
+  // Managing the memory for this properly would be rather complicated, and
+  // expansion statements are fairly uncommon, so just allocate space for the
+  // maximum amount of substatements we could possibly have.
+  Stmt *SubStmts[MAX_COUNT];
+
+  CXXExpansionStmtPattern(StmtClass SC, EmptyShell Empty);
+  CXXExpansionStmtPattern(StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init,
+                          DeclStmt *ExpansionVar, SourceLocation LParenLoc,
+                          SourceLocation ColonLoc, SourceLocation RParenLoc);
+
+public:
+  SourceLocation getLParenLoc() const { return LParenLoc; }
+  SourceLocation getColonLoc() const { return ColonLoc; }
+  SourceLocation getRParenLoc() const { return RParenLoc; }
+
+  SourceLocation getBeginLoc() const;
+  SourceLocation getEndLoc() const {
+    return getBody() ? getBody()->getEndLoc() : RParenLoc;
+  }
+
+  bool hasDependentSize() const;
+
+  CXXExpansionStmtDecl *getDecl() { return ParentDecl; }
+  const CXXExpansionStmtDecl *getDecl() const { return ParentDecl; }
+
+  Stmt *getInit() { return SubStmts[INIT]; }
+  const Stmt *getInit() const { return SubStmts[INIT]; }
+  void setInit(Stmt *S) { SubStmts[INIT] = S; }
+
+  VarDecl *getExpansionVariable();
+  const VarDecl *getExpansionVariable() const {
+    return const_cast<CXXExpansionStmtPattern *>(this)->getExpansionVariable();
+  }
+
+  DeclStmt *getExpansionVarStmt() { return cast<DeclStmt>(SubStmts[VAR]); }
+  const DeclStmt *getExpansionVarStmt() const {
+    return cast<DeclStmt>(SubStmts[VAR]);
+  }
+
+  void setExpansionVarStmt(Stmt *S) { SubStmts[VAR] = S; }
+
+  Stmt *getBody() { return SubStmts[BODY]; }
+  const Stmt *getBody() const { return SubStmts[BODY]; }
+  void setBody(Stmt *S) { SubStmts[BODY] = S; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() >= firstCXXExpansionStmtPatternConstant &&
+           T->getStmtClass() <= lastCXXExpansionStmtPatternConstant;
+  }
+
+  child_range children() {
+    return child_range(SubStmts, SubStmts + FIRST_CHILD_STMT);
+  }
+
+  const_child_range children() const {
+    return const_child_range(SubStmts, SubStmts + FIRST_CHILD_STMT);
+  }
+};
+
+/// Represents an unexpanded enumerating expansion statement.
+///
+/// An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// 'CXXExpansionInitListExpr'.
+///
+/// Example:
+/// \verbatim
+///   template for (auto x : { 1, 2, 3 }) {
+///     // ...
+///   }
+/// \endverbatim
+///
+/// Note that the expression-list may also contain pack expansions, e.g.
+/// '{ 1, xs... }', in which case the expansion size is dependent.
+///
+/// Here, the '{ 1, 2, 3 }' is parsed as a 'CXXExpansionInitListExpr'. This 
node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionInitListSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionInitListSelectExpr()': 
for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionInitListSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+class CXXEnumeratingExpansionStmtPattern : public CXXExpansionStmtPattern {
+  friend class ASTStmtReader;
+
+public:
+  CXXEnumeratingExpansionStmtPattern(EmptyShell Empty);
+  CXXEnumeratingExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init,
+                                     DeclStmt *ExpansionVar,
+                                     SourceLocation LParenLoc,
+                                     SourceLocation ColonLoc,
+                                     SourceLocation RParenLoc);
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXEnumeratingExpansionStmtPatternClass;
+  }
+};
+
+/// Represents an expansion statement whose expansion-initializer is
+/// type-dependent.
+///
+/// This will be instantiated as either a 'CXXIteratingExpansionStmtPattern' or
+/// a 'CXXDestructuringExpansionStmtPattern'. Dependent expansion statements 
can
+/// never be enumerating; those are always stored as a
+/// 'CXXEnumeratingExpansionStmtPattern', even if the expansion size is
+/// dependent because the expression-list contains a pack.
+///
+/// Example:
+/// \verbatim
+///   template <typename T>
+///   void f() {
+///     template for (auto x : T()) {
+///       // ...
+///     }
+///   }
+/// \endverbatim
+class CXXDependentExpansionStmtPattern : public CXXExpansionStmtPattern {
+  friend class ASTStmtReader;
+
+public:
+  CXXDependentExpansionStmtPattern(EmptyShell Empty);
+  CXXDependentExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init,
+                                   DeclStmt *ExpansionVar,
+                                   Expr *ExpansionInitializer,
+                                   SourceLocation LParenLoc,
+                                   SourceLocation ColonLoc,
+                                   SourceLocation RParenLoc);
+
+  Expr *getExpansionInitializer() {
+    return cast<Expr>(SubStmts[EXPANSION_INITIALIZER]);
+  }
+  const Expr *getExpansionInitializer() const {
+    return cast<Expr>(SubStmts[EXPANSION_INITIALIZER]);
+  }
+  void setExpansionInitializer(Expr *S) { SubStmts[EXPANSION_INITIALIZER] = S; 
}
+
+  child_range children() {
+    return child_range(SubStmts,
+                       SubStmts + COUNT_CXXDependentExpansionStmtPattern);
+  }
+
+  const_child_range children() const {
+    return const_child_range(SubStmts,
+                             SubStmts + 
COUNT_CXXDependentExpansionStmtPattern);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXDependentExpansionStmtPatternClass;
+  }
+};
+
+/// Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range (i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged]).
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion.
+///
+/// Example:
+/// \verbatim
+///   static constexpr std::string_view foo = "1234";
+///   template for (auto x : foo) {
+///     // ...
+///   }
+/// \endverbatim
+class CXXIteratingExpansionStmtPattern : public CXXExpansionStmtPattern {
+  friend class ASTStmtReader;
+
+public:
+  CXXIteratingExpansionStmtPattern(EmptyShell Empty);
+  CXXIteratingExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init,
+                                   DeclStmt *ExpansionVar, DeclStmt *Range,
+                                   DeclStmt *Begin, DeclStmt *End,
+                                   SourceLocation LParenLoc,
+                                   SourceLocation ColonLoc,
+                                   SourceLocation RParenLoc);
+
+  const DeclStmt *getRangeVarStmt() const {
+    return cast<DeclStmt>(SubStmts[RANGE]);
+  }
+  DeclStmt *getRangeVarStmt() { return cast<DeclStmt>(SubStmts[RANGE]); }
+  void setRangeVarStmt(DeclStmt *S) { SubStmts[RANGE] = S; }
+
+  const VarDecl *getRangeVar() const {
+    return cast<VarDecl>(getRangeVarStmt()->getSingleDecl());
+  }
+
+  VarDecl *getRangeVar() {
+    return cast<VarDecl>(getRangeVarStmt()->getSingleDecl());
+  }
+
+  const DeclStmt *getBeginVarStmt() const {
+    return cast<DeclStmt>(SubStmts[BEGIN]);
+  }
+  DeclStmt *getBeginVarStmt() { return cast<DeclStmt>(SubStmts[BEGIN]); }
+  void setBeginVarStmt(DeclStmt *S) { SubStmts[BEGIN] = S; }
+
+  const VarDecl *getBeginVar() const {
+    return cast<VarDecl>(getBeginVarStmt()->getSingleDecl());
+  }
+
+  VarDecl *getBeginVar() {
+    return cast<VarDecl>(getBeginVarStmt()->getSingleDecl());
+  }
+
+  const DeclStmt *getEndVarStmt() const {
+    return cast<DeclStmt>(SubStmts[END]);
+  }
+  DeclStmt *getEndVarStmt() { return cast<DeclStmt>(SubStmts[END]); }
+  void setEndVarStmt(DeclStmt *S) { SubStmts[END] = S; }
+
+  const VarDecl *getEndVar() const {
+    return cast<VarDecl>(getEndVarStmt()->getSingleDecl());
+  }
+
+  VarDecl *getEndVar() {
+    return cast<VarDecl>(getEndVarStmt()->getSingleDecl());
+  }
+
+  child_range children() {
+    return child_range(SubStmts,
+                       SubStmts + COUNT_CXXIteratingExpansionStmtPattern);
+  }
+
+  const_child_range children() const {
+    return const_child_range(SubStmts,
+                             SubStmts + 
COUNT_CXXIteratingExpansionStmtPattern);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXIteratingExpansionStmtPatternClass;
+  }
+};
+
+/// Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we try,
+/// and if it doesn't work, the program is ill-formed).
+///
+/// This essentially involves treating the expansion-initializer as the
+/// initializer of a structured-binding declarations, with the number of
+/// bindings and expansion size determined by the usual means (array size,
+/// std::tuple_size, etc.).
+///
+/// Example:
+/// \verbatim
+///   std::array<int, 3> a {1, 2, 3};
+///   template for (auto x : a) {
+///     // ...
+///   }
+/// \endverbatim
+///
+/// Sema wraps the initializer with a CXXDestructuringExpansionSelectExpr, 
which
+/// selects a binding based on the current expansion index; this is analogous 
to
+/// how 'CXXExpansionInitListSelectExpr' is used; see the documentation of
+/// 'CXXEnumeratingExpansionStmtPattern' for more details on this.
+class CXXDestructuringExpansionStmtPattern : public CXXExpansionStmtPattern {
+  friend class ASTStmtReader;
+
+public:
+  CXXDestructuringExpansionStmtPattern(EmptyShell Empty);
+  CXXDestructuringExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init,
+                                       DeclStmt *ExpansionVar,
+                                       Stmt *DecompositionDeclStmt,
+                                       SourceLocation LParenLoc,
+                                       SourceLocation ColonLoc,
+                                       SourceLocation RParenLoc);
+
+  Stmt *getDecompositionDeclStmt() { return SubStmts[DECOMP_DECL]; }
+  const Stmt *getDecompositionDeclStmt() const { return SubStmts[DECOMP_DECL]; 
}
+  void setDecompositionDeclStmt(Stmt *S) { SubStmts[DECOMP_DECL] = S; }
+
+  DecompositionDecl *getDecompositionDecl();
+  const DecompositionDecl *getDecompositionDecl() const {
+    return const_cast<CXXDestructuringExpansionStmtPattern *>(this)
+        ->getDecompositionDecl();
+  }
+
+  child_range children() {
+    return child_range(SubStmts,
+                       SubStmts + COUNT_CXXDestructuringExpansionStmtPattern);
+  }
+
+  const_child_range children() const {
+    return const_child_range(
+        SubStmts, SubStmts + COUNT_CXXDestructuringExpansionStmtPattern);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXDestructuringExpansionStmtPatternClass;
+  }
+};
+
+/// Represents the code generated for an expanded expansion statement.
+///
+/// This holds 'shared statements' and 'instantiations'; these encode the
+/// general underlying pattern that all expansion statements desugar to:
+///
+/// \verbatim
+/// {
+///   <shared statements>
+///   {
+///     <1st instantiation>
+///   }
+///   ...
+///   {
+///     <n-th instantiation>
+///   }
+/// }
+/// \endverbatim
+///
+/// Here, the only thing that is stored in the AST are the 'shared statements'
+/// and the 'CompoundStmt's that wrap the 'instantiations'. The outer braces
+/// shown above are implicit.
+///
+/// For example, the CXXExpansionStmtInstantiation that corresponds to the
+/// following expansion statement
+///
+/// \verbatim
+///   std::tuple<int, int, int> a{1, 2, 3};
+///   template for (auto x : a) {
+///     // ...
+///   }
+/// \endverbatim
+///
+/// would be
+///
+/// \verbatim
+/// {
+///   auto [__u0, __u1, __u2] = a;
+///   {
+///     auto x = __u0;
+///     // ...
+///   }
+///   {
+///     auto x = __u1;
+///     // ...
+///   }
+///   {
+///     auto x = __u2;
+///     // ...
+///   }
+/// }
+/// \endverbatim
+class CXXExpansionStmtInstantiation final
+    : public Stmt,
+      llvm::TrailingObjects<CXXExpansionStmtInstantiation, Stmt *> {
+  friend class ASTStmtReader;
+  friend TrailingObjects;
+
+  SourceLocation BeginLoc;
+  SourceLocation EndLoc;
+
+  // Instantiations are stored first, then shared statements.
+  const unsigned NumInstantiations : 20;
+  const unsigned NumSharedStmts : 3;
+  unsigned ShouldApplyLifetimeExtensionToSharedStmts : 1;
+
+  CXXExpansionStmtInstantiation(EmptyShell Empty, unsigned NumInstantiations,
+                                unsigned NumSharedStmts);
+  CXXExpansionStmtInstantiation(SourceLocation BeginLoc, SourceLocation EndLoc,
+                                ArrayRef<Stmt *> Instantiations,
+                                ArrayRef<Stmt *> SharedStmts,
+                                bool 
ShouldApplyLifetimeExtensionToSharedStmts);
+
+public:
+  static CXXExpansionStmtInstantiation *
+  Create(ASTContext &C, SourceLocation BeginLoc, SourceLocation EndLoc,
+         ArrayRef<Stmt *> Instantiations, ArrayRef<Stmt *> SharedStmts,
+         bool ShouldApplyLifetimeExtensionToSharedStmts);
+
+  static CXXExpansionStmtInstantiation *CreateEmpty(ASTContext &C,
+                                                    EmptyShell Empty,
+                                                    unsigned NumInstantiations,
+                                                    unsigned NumSharedStmts);
+
+  ArrayRef<Stmt *> getAllSubStmts() const {
+    return getTrailingObjects(getNumSubStmts());
+  }
+
+  MutableArrayRef<Stmt *> getAllSubStmts() {
+    return getTrailingObjects(getNumSubStmts());
+  }
+
+  unsigned getNumSubStmts() const { return NumInstantiations + NumSharedStmts; 
}
+
+  ArrayRef<Stmt *> getInstantiations() const {
+    return getTrailingObjects(NumInstantiations);
+  }
+
+  ArrayRef<Stmt *> getSharedStmts() const {
+    return getAllSubStmts().drop_front(NumInstantiations);
+  }
+
+  bool shouldApplyLifetimeExtensionToSharedStmts() const {
+    return ShouldApplyLifetimeExtensionToSharedStmts;
+  }
+
+  void setShouldApplyLifetimeExtensionToSharedStmts(bool Apply) {
+    ShouldApplyLifetimeExtensionToSharedStmts = Apply;
+  }
+
+  SourceLocation getBeginLoc() const { return BeginLoc; }
+  SourceLocation getEndLoc() const { return EndLoc; }
+
+  child_range children() {
+    Stmt **S = getTrailingObjects();
+    return child_range(S, S + getNumSubStmts());
+  }
+
+  const_child_range children() const {
+    Stmt *const *S = getTrailingObjects();
+    return const_child_range(S, S + getNumSubStmts());
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXExpansionStmtInstantiationClass;
+  }
+};
+
 }  // end namespace clang
 
 #endif
diff --git a/clang/include/clang/AST/TextNodeDumper.h 
b/clang/include/clang/AST/TextNodeDumper.h
index 88ecd526e3d7e..3db8ce0d5aed3 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -266,6 +266,8 @@ class TextNodeDumper
   void VisitCoawaitExpr(const CoawaitExpr *Node);
   void VisitCoreturnStmt(const CoreturnStmt *Node);
   void VisitCompoundStmt(const CompoundStmt *Node);
+  void
+  VisitCXXExpansionStmtInstantiation(const CXXExpansionStmtInstantiation 
*Node);
   void VisitConstantExpr(const ConstantExpr *Node);
   void VisitCallExpr(const CallExpr *Node);
   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Node);
@@ -310,6 +312,9 @@ class TextNodeDumper
   void VisitSizeOfPackExpr(const SizeOfPackExpr *Node);
   void
   VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *Node);
+  void VisitCXXDestructuringExpansionSelectExpr(
+      const CXXDestructuringExpansionSelectExpr *Node);
+  void VisitCXXExpansionInitListExpr(const CXXExpansionInitListExpr *Node);
   void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
   void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node);
   void VisitObjCMessageExpr(const ObjCMessageExpr *Node);
diff --git a/clang/include/clang/Basic/DeclNodes.td 
b/clang/include/clang/Basic/DeclNodes.td
index 04311055bb600..23f8e47939bdb 100644
--- a/clang/include/clang/Basic/DeclNodes.td
+++ b/clang/include/clang/Basic/DeclNodes.td
@@ -101,6 +101,7 @@ def AccessSpec : DeclNode<Decl>;
 def Friend : DeclNode<Decl>;
 def FriendTemplate : DeclNode<Decl>;
 def StaticAssert : DeclNode<Decl>;
+def CXXExpansionStmt : DeclNode<Decl>, DeclContext;
 def Block : DeclNode<Decl, "blocks">, DeclContext;
 def OutlinedFunction : DeclNode<Decl>, DeclContext;
 def Captured : DeclNode<Decl>, DeclContext;
diff --git a/clang/include/clang/Basic/StmtNodes.td 
b/clang/include/clang/Basic/StmtNodes.td
index bf3686bb372d5..505ed481e0895 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -58,6 +58,15 @@ def CXXForRangeStmt : StmtNode<Stmt>;
 def CoroutineBodyStmt : StmtNode<Stmt>;
 def CoreturnStmt : StmtNode<Stmt>;
 
+// C++ expansion statements (P1306)
+def CXXExpansionStmtPattern : StmtNode<Stmt, 1>;
+def CXXEnumeratingExpansionStmtPattern : StmtNode<CXXExpansionStmtPattern>;
+def CXXIteratingExpansionStmtPattern : StmtNode<CXXExpansionStmtPattern>;
+def CXXDestructuringExpansionStmtPattern : StmtNode<CXXExpansionStmtPattern>;
+def CXXDependentExpansionStmtPattern : StmtNode<CXXExpansionStmtPattern>;
+def CXXExpansionStmtInstantiation
+    : StmtNode<Stmt>; // *Not* derived from CXXExpansionStmtPattern!
+
 // Expressions
 def Expr : StmtNode<ValueStmt, 1>;
 def PredefinedExpr : StmtNode<Expr>;
@@ -177,6 +186,11 @@ def CoyieldExpr : StmtNode<CoroutineSuspendExpr>;
 def ConceptSpecializationExpr : StmtNode<Expr>;
 def RequiresExpr : StmtNode<Expr>;
 
+// C++26 Expansion statement support expressions
+def CXXExpansionInitListExpr : StmtNode<Expr>;
+def CXXExpansionInitListSelectExpr : StmtNode<Expr>;
+def CXXDestructuringExpansionSelectExpr : StmtNode<Expr>;
+
 // Obj-C Expressions.
 def ObjCStringLiteral : StmtNode<Expr>;
 def ObjCBoxedExpr : StmtNode<Expr>;
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h 
b/clang/include/clang/Serialization/ASTBitCodes.h
index d7d429eacd67a..36cccdcbd306e 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1460,6 +1460,9 @@ enum DeclCode {
   /// \brief A StaticAssertDecl record.
   DECL_STATIC_ASSERT,
 
+  /// A C++ expansion statement.
+  DECL_EXPANSION_STMT,
+
   /// A record containing CXXBaseSpecifiers.
   DECL_CXX_BASE_SPECIFIERS,
 
@@ -1833,6 +1836,21 @@ enum StmtCode {
 
   STMT_CXX_FOR_RANGE,
 
+  /// A CXXEnumeratedExpansionStmt.
+  STMT_CXX_ENUMERATING_EXPANSION,
+
+  /// A CXXIteratingExpansionStmtPattern.
+  STMT_CXX_ITERATING_EXPANSION,
+
+  /// A CXXDestructuringExpansionStmtPattern.
+  STMT_CXX_DESTRUCTURING_EXPANSION,
+
+  /// A CXXDependentExpansionStmtPattern,
+  STMT_CXX_DEPENDENT_EXPANSION,
+
+  /// A CXXExpansionStmtInstantiation.
+  STMT_CXX_EXPANSION_INSTANTIATION,
+
   /// A CXXOperatorCallExpr record.
   EXPR_CXX_OPERATOR_CALL,
 
@@ -1914,16 +1932,19 @@ enum StmtCode {
   EXPR_TYPE_TRAIT,                  // TypeTraitExpr
   EXPR_ARRAY_TYPE_TRAIT,            // ArrayTypeTraitIntExpr
 
-  EXPR_PACK_EXPANSION,                    // PackExpansionExpr
-  EXPR_PACK_INDEXING,                     // PackIndexingExpr
-  EXPR_SIZEOF_PACK,                       // SizeOfPackExpr
-  EXPR_SUBST_NON_TYPE_TEMPLATE_PARM,      // SubstNonTypeTemplateParmExpr
-  EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr
-  EXPR_FUNCTION_PARM_PACK,                // FunctionParmPackExpr
-  EXPR_MATERIALIZE_TEMPORARY,             // MaterializeTemporaryExpr
-  EXPR_CXX_FOLD,                          // CXXFoldExpr
-  EXPR_CONCEPT_SPECIALIZATION,            // ConceptSpecializationExpr
-  EXPR_REQUIRES,                          // RequiresExpr
+  EXPR_PACK_EXPANSION,                     // PackExpansionExpr
+  EXPR_PACK_INDEXING,                      // PackIndexingExpr
+  EXPR_SIZEOF_PACK,                        // SizeOfPackExpr
+  EXPR_SUBST_NON_TYPE_TEMPLATE_PARM,       // SubstNonTypeTemplateParmExpr
+  EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,  // SubstNonTypeTemplateParmPackExpr
+  EXPR_FUNCTION_PARM_PACK,                 // FunctionParmPackExpr
+  EXPR_MATERIALIZE_TEMPORARY,              // MaterializeTemporaryExpr
+  EXPR_CXX_FOLD,                           // CXXFoldExpr
+  EXPR_CONCEPT_SPECIALIZATION,             // ConceptSpecializationExpr
+  EXPR_REQUIRES,                           // RequiresExpr
+  EXPR_CXX_EXPANSION_INIT_LIST,            // CXXExpansionInitListExpr
+  EXPR_CXX_EXPANSION_INIT_LIST_SELECT,     // CXXExpansionInitListSelectExpr
+  EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT, // 
CXXDestructuringExpansionSelectExpr
 
   // CUDA
   EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index c1441744c8578..b94c18e60ba58 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -516,6 +516,7 @@ namespace clang {
     ExpectedDecl VisitEmptyDecl(EmptyDecl *D);
     ExpectedDecl VisitAccessSpecDecl(AccessSpecDecl *D);
     ExpectedDecl VisitStaticAssertDecl(StaticAssertDecl *D);
+    ExpectedDecl VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D);
     ExpectedDecl VisitTranslationUnitDecl(TranslationUnitDecl *D);
     ExpectedDecl VisitBindingDecl(BindingDecl *D);
     ExpectedDecl VisitNamespaceDecl(NamespaceDecl *D);
@@ -608,6 +609,16 @@ namespace clang {
     ExpectedStmt VisitCXXCatchStmt(CXXCatchStmt *S);
     ExpectedStmt VisitCXXTryStmt(CXXTryStmt *S);
     ExpectedStmt VisitCXXForRangeStmt(CXXForRangeStmt *S);
+    ExpectedStmt VisitCXXEnumeratingExpansionStmtPattern(
+        CXXEnumeratingExpansionStmtPattern *S);
+    ExpectedStmt
+    VisitCXXIteratingExpansionStmtPattern(CXXIteratingExpansionStmtPattern *S);
+    ExpectedStmt VisitCXXDestructuringExpansionStmtPattern(
+        CXXDestructuringExpansionStmtPattern *S);
+    ExpectedStmt
+    VisitCXXDependentExpansionStmtPattern(CXXDependentExpansionStmtPattern *S);
+    ExpectedStmt
+    VisitCXXExpansionStmtInstantiation(CXXExpansionStmtInstantiation *S);
     // FIXME: MSDependentExistsStmt
     ExpectedStmt VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
     ExpectedStmt VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
@@ -700,6 +711,11 @@ namespace clang {
     VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E);
     ExpectedStmt VisitPseudoObjectExpr(PseudoObjectExpr *E);
     ExpectedStmt VisitCXXParenListInitExpr(CXXParenListInitExpr *E);
+    ExpectedStmt VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E);
+    ExpectedStmt
+    VisitCXXExpansionInitListSelectExpr(CXXExpansionInitListSelectExpr *E);
+    ExpectedStmt VisitCXXDestructuringExpansionSelectExpr(
+        CXXDestructuringExpansionSelectExpr *E);
 
     // Helper for chaining together multiple imports. If an error is detected,
     // subsequent imports will return default constructed nodes, so that 
failure
@@ -2852,6 +2868,34 @@ ExpectedDecl 
ASTNodeImporter::VisitStaticAssertDecl(StaticAssertDecl *D) {
   return ToD;
 }
 
+ExpectedDecl
+ASTNodeImporter::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) {
+  auto DCOrErr = Importer.ImportContext(D->getDeclContext());
+  if (!DCOrErr)
+    return DCOrErr.takeError();
+  DeclContext *DC = *DCOrErr;
+  DeclContext *LexicalDC = DC;
+
+  Error Err = Error::success();
+  auto ToLocation = importChecked(Err, D->getLocation());
+  auto ToExpansion = importChecked(Err, D->getExpansionPattern());
+  auto ToTemplateParams = importChecked(Err, D->getTemplateParameters());
+  auto ToInstantiations = importChecked(Err, D->getInstantiations());
+  if (Err)
+    return std::move(Err);
+
+  CXXExpansionStmtDecl *ToD;
+  if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, ToLocation,
+                              ToTemplateParams))
+    return ToD;
+
+  ToD->setExpansionPattern(ToExpansion);
+  ToD->setInstantiations(ToInstantiations);
+  ToD->setLexicalDeclContext(LexicalDC);
+  LexicalDC->addDeclInternal(ToD);
+  return ToD;
+}
+
 ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
   // Import the major distinguishing characteristics of this namespace.
   DeclContext *DC, *LexicalDC;
@@ -7450,6 +7494,96 @@ ExpectedStmt 
ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
       ToBody, ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc);
 }
 
+ExpectedStmt ASTNodeImporter::VisitCXXEnumeratingExpansionStmtPattern(
+    CXXEnumeratingExpansionStmtPattern *S) {
+  Error Err = Error::success();
+  auto ToESD = importChecked(Err, S->getDecl());
+  auto ToInit = importChecked(Err, S->getInit());
+  auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt());
+  auto ToLParenLoc = importChecked(Err, S->getLParenLoc());
+  auto ToColonLoc = importChecked(Err, S->getColonLoc());
+  auto ToRParenLoc = importChecked(Err, S->getRParenLoc());
+  if (Err)
+    return std::move(Err);
+
+  return new (Importer.getToContext()) CXXEnumeratingExpansionStmtPattern(
+      ToESD, ToInit, ToExpansionVar, ToLParenLoc, ToColonLoc, ToRParenLoc);
+}
+ExpectedStmt ASTNodeImporter::VisitCXXIteratingExpansionStmtPattern(
+    CXXIteratingExpansionStmtPattern *S) {
+  Error Err = Error::success();
+  auto ToESD = importChecked(Err, S->getDecl());
+  auto ToInit = importChecked(Err, S->getInit());
+  auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt());
+  auto ToRange = importChecked(Err, S->getRangeVarStmt());
+  auto ToBegin = importChecked(Err, S->getBeginVarStmt());
+  auto ToEnd = importChecked(Err, S->getEndVarStmt());
+  auto ToLParenLoc = importChecked(Err, S->getLParenLoc());
+  auto ToColonLoc = importChecked(Err, S->getColonLoc());
+  auto ToRParenLoc = importChecked(Err, S->getRParenLoc());
+  if (Err)
+    return std::move(Err);
+
+  return new (Importer.getToContext()) CXXIteratingExpansionStmtPattern(
+      ToESD, ToInit, ToExpansionVar, ToRange, ToBegin, ToEnd, ToLParenLoc,
+      ToColonLoc, ToRParenLoc);
+}
+ExpectedStmt ASTNodeImporter::VisitCXXDestructuringExpansionStmtPattern(
+    CXXDestructuringExpansionStmtPattern *S) {
+  Error Err = Error::success();
+  auto ToESD = importChecked(Err, S->getDecl());
+  auto ToInit = importChecked(Err, S->getInit());
+  auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt());
+  auto ToDecompositionDeclStmt =
+      importChecked(Err, S->getDecompositionDeclStmt());
+  auto ToLParenLoc = importChecked(Err, S->getLParenLoc());
+  auto ToColonLoc = importChecked(Err, S->getColonLoc());
+  auto ToRParenLoc = importChecked(Err, S->getRParenLoc());
+  if (Err)
+    return std::move(Err);
+
+  return new (Importer.getToContext()) CXXDestructuringExpansionStmtPattern(
+      ToESD, ToInit, ToExpansionVar, ToDecompositionDeclStmt, ToLParenLoc,
+      ToColonLoc, ToRParenLoc);
+}
+ExpectedStmt ASTNodeImporter::VisitCXXDependentExpansionStmtPattern(
+    CXXDependentExpansionStmtPattern *S) {
+  Error Err = Error::success();
+  auto ToESD = importChecked(Err, S->getDecl());
+  auto ToInit = importChecked(Err, S->getInit());
+  auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt());
+  auto ToExpansionInitializer =
+      importChecked(Err, S->getExpansionInitializer());
+  auto ToLParenLoc = importChecked(Err, S->getLParenLoc());
+  auto ToColonLoc = importChecked(Err, S->getColonLoc());
+  auto ToRParenLoc = importChecked(Err, S->getRParenLoc());
+  if (Err)
+    return std::move(Err);
+
+  return new (Importer.getToContext()) CXXDependentExpansionStmtPattern(
+      ToESD, ToInit, ToExpansionVar, ToExpansionInitializer, ToLParenLoc,
+      ToColonLoc, ToRParenLoc);
+}
+ExpectedStmt ASTNodeImporter::VisitCXXExpansionStmtInstantiation(
+    CXXExpansionStmtInstantiation *S) {
+  Error Err = Error::success();
+  SmallVector<Stmt *> ToInstantiations;
+  SmallVector<Stmt *> ToSharedStmts;
+  auto ToBeginLoc = importChecked(Err, S->getBeginLoc());
+  auto ToEndLoc = importChecked(Err, S->getEndLoc());
+  for (Stmt *FromInst : S->getInstantiations())
+    ToInstantiations.push_back(importChecked(Err, FromInst));
+  for (Stmt *FromShared : S->getSharedStmts())
+    ToSharedStmts.push_back(importChecked(Err, FromShared));
+
+  if (Err)
+    return std::move(Err);
+
+  return CXXExpansionStmtInstantiation::Create(
+      Importer.getToContext(), ToBeginLoc, ToEndLoc, ToInstantiations,
+      ToSharedStmts, S->shouldApplyLifetimeExtensionToSharedStmts());
+}
+
 ExpectedStmt
 ASTNodeImporter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
   Error Err = Error::success();
@@ -9346,6 +9480,46 @@ 
ASTNodeImporter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
                                       ToInitLoc, ToBeginLoc, ToEndLoc);
 }
 
+ExpectedStmt
+ASTNodeImporter::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) {
+  Error Err = Error::success();
+  SmallVector<Expr *> ToExprs;
+  auto ToLBraceLoc = importChecked(Err, E->getLBraceLoc());
+  auto ToRBraceLoc = importChecked(Err, E->getRBraceLoc());
+  for (Expr *FromInst : E->getExprs())
+    ToExprs.push_back(importChecked(Err, FromInst));
+
+  if (Err)
+    return std::move(Err);
+
+  return CXXExpansionInitListExpr::Create(Importer.getToContext(), ToExprs,
+                                          ToLBraceLoc, ToRBraceLoc);
+}
+
+ExpectedStmt ASTNodeImporter::VisitCXXExpansionInitListSelectExpr(
+    CXXExpansionInitListSelectExpr *E) {
+  Error Err = Error::success();
+  auto ToRange = importChecked(Err, E->getRangeExpr());
+  auto ToIndex = importChecked(Err, E->getIndexExpr());
+  if (Err)
+    return std::move(Err);
+
+  return new (Importer.getToContext())
+      CXXExpansionInitListSelectExpr(Importer.getToContext(), ToRange, 
ToIndex);
+}
+
+ExpectedStmt ASTNodeImporter::VisitCXXDestructuringExpansionSelectExpr(
+    CXXDestructuringExpansionSelectExpr *E) {
+  Error Err = Error::success();
+  auto ToDecompositionDecl = importChecked(Err, E->getDecompositionDecl());
+  auto ToIndex = importChecked(Err, E->getIndexExpr());
+  if (Err)
+    return std::move(Err);
+
+  return new (Importer.getToContext()) CXXDestructuringExpansionSelectExpr(
+      Importer.getToContext(), ToDecompositionDecl, ToIndex);
+}
+
 Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod,
                                                CXXMethodDecl *FromMethod) {
   Error ImportErrors = Error::success();
diff --git a/clang/lib/AST/ComputeDependence.cpp 
b/clang/lib/AST/ComputeDependence.cpp
index 638080ea781a9..2ff9d74f1a8d5 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -959,3 +959,10 @@ ExprDependence 
clang::computeDependence(OpenACCAsteriskSizeExpr *E) {
   // way.
   return ExprDependence::None;
 }
+
+ExprDependence clang::computeDependence(CXXExpansionInitListExpr *ILE) {
+  auto D = ExprDependence::None;
+  for (Expr *E : ILE->getExprs())
+    D |= E->getDependence();
+  return D;
+}
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 30c6d3ed91f1e..3cbe309d75528 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -325,6 +325,9 @@ unsigned Decl::getTemplateDepth() const {
   if (auto *TPL = getDescribedTemplateParams())
     return TPL->getDepth() + 1;
 
+  if (auto *ESD = dyn_cast<CXXExpansionStmtDecl>(this))
+    return ESD->getIndexTemplateParm()->getDepth() + 1;
+
   // If this is a dependent lambda, there might be an enclosing variable
   // template. In this case, the next step is not the parent DeclContext (or
   // even a DeclContext at all).
@@ -1018,6 +1021,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind 
DeclKind) {
     case ImplicitConceptSpecialization:
     case OpenACCDeclare:
     case OpenACCRoutine:
+    case CXXExpansionStmt:
       // Never looked up by name.
       return 0;
   }
@@ -1382,7 +1386,7 @@ bool DeclContext::isDependentContext() const {
   if (isFileContext())
     return false;
 
-  if (isa<ClassTemplatePartialSpecializationDecl>(this))
+  if (isa<ClassTemplatePartialSpecializationDecl, CXXExpansionStmtDecl>(this))
     return true;
 
   if (const auto *Record = dyn_cast<CXXRecordDecl>(this)) {
@@ -1491,6 +1495,7 @@ DeclContext *DeclContext::getPrimaryContext() {
   case Decl::OMPDeclareReduction:
   case Decl::OMPDeclareMapper:
   case Decl::RequiresExprBody:
+  case Decl::CXXExpansionStmt:
     // There is only one DeclContext for these entities.
     return this;
 
@@ -2079,6 +2084,13 @@ RecordDecl *DeclContext::getOuterLexicalRecordContext() {
   return OutermostRD;
 }
 
+DeclContext *DeclContext::getEnclosingNonExpansionStatementContext() {
+  DeclContext *DC = this;
+  while (isa<CXXExpansionStmtDecl>(DC))
+    DC = DC->getParent();
+  return DC;
+}
+
 bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const {
   // For non-file contexts, this is equivalent to Equals.
   if (!isFileContext())
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 47ae613b643b6..9e399b3a81ead 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -113,6 +113,7 @@ namespace {
     void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *NTTP);
     void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *);
     void VisitHLSLBufferDecl(HLSLBufferDecl *D);
+    void VisitCXXExpansionStmtDecl(const CXXExpansionStmtDecl *D);
 
     void VisitOpenACCDeclareDecl(OpenACCDeclareDecl *D);
     void VisitOpenACCRoutineDecl(OpenACCRoutineDecl *D);
@@ -1329,6 +1330,11 @@ void 
DeclPrinter::VisitClassTemplatePartialSpecializationDecl(
   VisitCXXRecordDecl(D);
 }
 
+void DeclPrinter::VisitCXXExpansionStmtDecl(const CXXExpansionStmtDecl *D) {
+  D->getExpansionPattern()->printPretty(Out, nullptr, Policy, Indentation, 
"\n",
+                                        &Context);
+}
+
 //----------------------------------------------------------------------------
 // Objective-C declarations
 //----------------------------------------------------------------------------
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 2f7ae6d6cac63..edfd5cf91196e 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1717,6 +1717,10 @@ clang::getReplacedTemplateParameter(Decl *D, unsigned 
Index) {
     return getReplacedTemplateParameter(
         cast<FunctionDecl>(D)->getTemplateSpecializationInfo()->getTemplate(),
         Index);
+  case Decl::Kind::CXXExpansionStmt:
+    return {
+        
cast<CXXExpansionStmtDecl>(D)->getTemplateParameters()->getParam(Index),
+        {}};
   default:
     llvm_unreachable("Unhandled templated declaration kind");
   }
@@ -1788,3 +1792,22 @@ const Decl &clang::adjustDeclToTemplate(const Decl &D) {
   // FIXME: Adjust alias templates?
   return D;
 }
+
+CXXExpansionStmtDecl::CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc,
+                                           TemplateParameterList *TParams)
+    : Decl(CXXExpansionStmt, DC, Loc), DeclContext(CXXExpansionStmt),
+      TParams(TParams) {}
+
+CXXExpansionStmtDecl *
+CXXExpansionStmtDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation 
Loc,
+                             TemplateParameterList *TParams) {
+  return new (C, DC) CXXExpansionStmtDecl(DC, Loc, TParams);
+}
+CXXExpansionStmtDecl *
+CXXExpansionStmtDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
+  return new (C, ID) CXXExpansionStmtDecl(nullptr, SourceLocation(), nullptr);
+}
+
+SourceRange CXXExpansionStmtDecl::getSourceRange() const {
+  return Expansion ? Expansion->getSourceRange() : SourceRange();
+}
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 340bb4b2ed6a3..c61660c90513f 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3688,6 +3688,9 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
   case FunctionParmPackExprClass:
   case RecoveryExprClass:
   case CXXFoldExprClass:
+  case CXXExpansionInitListSelectExprClass:
+  case CXXExpansionInitListExprClass:
+  case CXXDestructuringExpansionSelectExprClass:
     // Make a conservative assumption for dependent nodes.
     return IncludePossibleEffects;
 
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index c7f0ff040194d..7ba49f74c1f7d 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -2020,3 +2020,61 @@ CXXFoldExpr::CXXFoldExpr(QualType T, 
UnresolvedLookupExpr *Callee,
   SubExprs[SubExpr::RHS] = RHS;
   setDependence(computeDependence(this));
 }
+
+CXXExpansionInitListExpr::CXXExpansionInitListExpr(EmptyShell ES,
+                                                   unsigned NumExprs)
+    : Expr(CXXExpansionInitListExprClass, ES), NumExprs(NumExprs) {}
+
+CXXExpansionInitListExpr::CXXExpansionInitListExpr(ArrayRef<Expr *> Exprs,
+                                                   SourceLocation LBraceLoc,
+                                                   SourceLocation RBraceLoc)
+    : Expr(CXXExpansionInitListExprClass, QualType(), VK_PRValue, OK_Ordinary),
+      NumExprs(static_cast<unsigned>(Exprs.size())), LBraceLoc(LBraceLoc),
+      RBraceLoc(RBraceLoc) {
+  llvm::uninitialized_copy(Exprs, getTrailingObjects());
+  setDependence(computeDependence(this));
+}
+
+CXXExpansionInitListExpr *
+CXXExpansionInitListExpr::Create(const ASTContext &C, ArrayRef<Expr *> Exprs,
+                                 SourceLocation LBraceLoc,
+                                 SourceLocation RBraceLoc) {
+  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Exprs.size()));
+  return new (Mem) CXXExpansionInitListExpr(Exprs, LBraceLoc, RBraceLoc);
+}
+
+CXXExpansionInitListExpr *
+CXXExpansionInitListExpr::CreateEmpty(const ASTContext &C, EmptyShell Empty,
+                                      unsigned NumExprs) {
+  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumExprs));
+  return new (Mem) CXXExpansionInitListExpr(Empty, NumExprs);
+}
+
+CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr(EmptyShell 
Empty)
+    : Expr(CXXExpansionInitListSelectExprClass, Empty) {}
+
+CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr(
+    const ASTContext &C, CXXExpansionInitListExpr *Range, Expr *Idx)
+    : Expr(CXXExpansionInitListSelectExprClass, C.DependentTy, VK_PRValue,
+           OK_Ordinary) {
+  setDependence(ExprDependence::TypeValueInstantiation);
+  SubExprs[RANGE] = Range;
+  SubExprs[INDEX] = Idx;
+}
+
+bool CXXExpansionInitListExpr::containsPackExpansion() const {
+  return llvm::any_of(getExprs(),
+                      [](const Expr *E) { return isa<PackExpansionExpr>(E); });
+}
+
+CXXDestructuringExpansionSelectExpr::CXXDestructuringExpansionSelectExpr(
+    EmptyShell Empty)
+    : Expr(CXXDestructuringExpansionSelectExprClass, Empty) {}
+
+CXXDestructuringExpansionSelectExpr::CXXDestructuringExpansionSelectExpr(
+    const ASTContext &C, DecompositionDecl *Decomposition, Expr *Index)
+    : Expr(CXXDestructuringExpansionSelectExprClass, C.DependentTy, VK_PRValue,
+           OK_Ordinary),
+      Decomposition(Decomposition), Index(Index) {
+  setDependence(ExprDependence::TypeValueInstantiation);
+}
diff --git a/clang/lib/AST/ExprClassification.cpp 
b/clang/lib/AST/ExprClassification.cpp
index aeacd0dc765ef..5521cdf9d04c9 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -216,6 +216,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const 
Expr *E) {
   case Expr::SourceLocExprClass:
   case Expr::ConceptSpecializationExprClass:
   case Expr::RequiresExprClass:
+  case Expr::CXXExpansionInitListExprClass:
+  case Expr::CXXExpansionInitListSelectExprClass:
+  case Expr::CXXDestructuringExpansionSelectExprClass:
     return Cl::CL_PRValue;
 
   case Expr::EmbedExprClass:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 3b91678f7d400..d93f87a27e68d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -20276,6 +20276,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext 
&Ctx) {
   case Expr::SYCLUniqueStableNameExprClass:
   case Expr::CXXParenListInitExprClass:
   case Expr::HLSLOutArgExprClass:
+  case Expr::CXXExpansionInitListExprClass:
+  case Expr::CXXExpansionInitListSelectExprClass:
+  case Expr::CXXDestructuringExpansionSelectExprClass:
     return ICEDiag(IK_NotICE, E->getBeginLoc());
 
   case Expr::InitListExprClass: {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 5572e0a7ae59c..28883edc34e6d 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -42,7 +42,7 @@ using namespace clang;
 namespace {
 
 static bool isLocalContainerContext(const DeclContext *DC) {
-  return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || 
isa<BlockDecl>(DC);
+  return isa<FunctionDecl, ObjCMethodDecl, BlockDecl, 
CXXExpansionStmtDecl>(DC);
 }
 
 static const FunctionDecl *getStructor(const FunctionDecl *fn) {
@@ -1851,6 +1851,8 @@ static GlobalDecl getParentOfLocalEntity(const 
DeclContext *DC) {
     GD = GlobalDecl(CD, Ctor_Complete);
   else if (auto *DD = dyn_cast<CXXDestructorDecl>(DC))
     GD = GlobalDecl(DD, Dtor_Complete);
+  else if (DC->isExpansionStmt())
+    GD = 
getParentOfLocalEntity(DC->getEnclosingNonExpansionStatementContext());
   else
     GD = GlobalDecl(cast<FunctionDecl>(DC));
   return GD;
@@ -2191,6 +2193,9 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, 
bool NoFunction) {
   if (NoFunction && isLocalContainerContext(DC))
     return;
 
+  if (DC->isExpansionStmt())
+    return;
+
   const NamedDecl *ND = cast<NamedDecl>(DC);
   if (mangleSubstitution(ND))
     return;
@@ -4940,6 +4945,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   case Expr::CXXInheritedCtorInitExprClass:
   case Expr::CXXParenListInitExprClass:
   case Expr::PackIndexingExprClass:
+  case Expr::CXXExpansionInitListSelectExprClass:
+  case Expr::CXXExpansionInitListExprClass:
+  case Expr::CXXDestructuringExpansionSelectExprClass:
     llvm_unreachable("unexpected statement kind");
 
   case Expr::ConstantExprClass:
diff --git a/clang/lib/AST/StmtCXX.cpp b/clang/lib/AST/StmtCXX.cpp
index 6a69fe75136f3..87bf376f3770d 100644
--- a/clang/lib/AST/StmtCXX.cpp
+++ b/clang/lib/AST/StmtCXX.cpp
@@ -11,6 +11,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/AST/StmtCXX.h"
+#include "clang/AST/ExprCXX.h"
 
 #include "clang/AST/ASTContext.h"
 
@@ -125,3 +126,155 @@ 
CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
       Args.ReturnStmtOnAllocFailure;
   llvm::copy(Args.ParamMoves, const_cast<Stmt **>(getParamMoves().data()));
 }
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(StmtClass SC, EmptyShell 
Empty)
+    : Stmt(SC, Empty) {}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(
+    StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt 
*ExpansionVar,
+
+    SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation 
RParenLoc)
+    : Stmt(SC), ParentDecl(ESD), LParenLoc(LParenLoc), ColonLoc(ColonLoc),
+      RParenLoc(RParenLoc) {
+  setInit(Init);
+  setExpansionVarStmt(ExpansionVar);
+  setBody(nullptr);
+}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+    EmptyShell Empty)
+    : CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, Empty) 
{}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+    CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+    SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation 
RParenLoc)
+    : CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, ESD,
+                              Init, ExpansionVar, LParenLoc, ColonLoc,
+                              RParenLoc) {}
+
+SourceLocation CXXExpansionStmtPattern::getBeginLoc() const {
+  return ParentDecl->getLocation();
+}
+
+VarDecl *CXXExpansionStmtPattern::getExpansionVariable() {
+  Decl *LV = cast<DeclStmt>(getExpansionVarStmt())->getSingleDecl();
+  assert(LV && "No expansion variable in CXXExpansionStmtPattern");
+  return cast<VarDecl>(LV);
+}
+
+bool CXXExpansionStmtPattern::hasDependentSize() const {
+  if (isa<CXXEnumeratingExpansionStmtPattern>(this))
+    return cast<CXXExpansionInitListSelectExpr>(
+               getExpansionVariable()->getInit())
+        ->getRangeExpr()
+        ->containsPackExpansion();
+
+  if (auto *Iterating = dyn_cast<CXXIteratingExpansionStmtPattern>(this)) {
+    const Expr *Begin = Iterating->getBeginVar()->getInit();
+    const Expr *End = Iterating->getBeginVar()->getInit();
+    return Begin->isTypeDependent() || Begin->isValueDependent() ||
+           End->isTypeDependent() || End->isValueDependent();
+  }
+
+  if (isa<CXXDestructuringExpansionStmtPattern>(this))
+    return false;
+
+  if (isa<CXXDependentExpansionStmtPattern>(this))
+    return true;
+
+  llvm_unreachable("Invalid expansion statement class");
+}
+
+CXXIteratingExpansionStmtPattern::CXXIteratingExpansionStmtPattern(
+    EmptyShell Empty)
+    : CXXExpansionStmtPattern(CXXIteratingExpansionStmtPatternClass, Empty) {}
+
+CXXIteratingExpansionStmtPattern::CXXIteratingExpansionStmtPattern(
+    CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+    DeclStmt *Range, DeclStmt *Begin, DeclStmt *End, SourceLocation LParenLoc,
+    SourceLocation ColonLoc, SourceLocation RParenLoc)
+    : CXXExpansionStmtPattern(CXXIteratingExpansionStmtPatternClass, ESD, Init,
+                              ExpansionVar, LParenLoc, ColonLoc, RParenLoc) {
+  setRangeVarStmt(Range);
+  setBeginVarStmt(Begin);
+  setEndVarStmt(End);
+}
+
+CXXDestructuringExpansionStmtPattern::CXXDestructuringExpansionStmtPattern(
+    EmptyShell Empty)
+    : CXXExpansionStmtPattern(CXXDestructuringExpansionStmtPatternClass,
+                              Empty) {}
+
+CXXDestructuringExpansionStmtPattern::CXXDestructuringExpansionStmtPattern(
+    CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+    Stmt *DecompositionDeclStmt, SourceLocation LParenLoc,
+    SourceLocation ColonLoc, SourceLocation RParenLoc)
+    : CXXExpansionStmtPattern(CXXDestructuringExpansionStmtPatternClass, ESD,
+                              Init, ExpansionVar, LParenLoc, ColonLoc,
+                              RParenLoc) {
+  setDecompositionDeclStmt(DecompositionDeclStmt);
+}
+
+DecompositionDecl *
+CXXDestructuringExpansionStmtPattern::getDecompositionDecl() {
+  return cast<DecompositionDecl>(
+      cast<DeclStmt>(getDecompositionDeclStmt())->getSingleDecl());
+}
+
+CXXDependentExpansionStmtPattern::CXXDependentExpansionStmtPattern(
+    EmptyShell Empty)
+    : CXXExpansionStmtPattern(CXXDependentExpansionStmtPatternClass, Empty) {}
+
+CXXDependentExpansionStmtPattern::CXXDependentExpansionStmtPattern(
+    CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+    Expr *ExpansionInitializer, SourceLocation LParenLoc,
+    SourceLocation ColonLoc, SourceLocation RParenLoc)
+    : CXXExpansionStmtPattern(CXXDependentExpansionStmtPatternClass, ESD, Init,
+                              ExpansionVar, LParenLoc, ColonLoc, RParenLoc) {
+  setExpansionInitializer(ExpansionInitializer);
+}
+
+CXXExpansionStmtInstantiation::CXXExpansionStmtInstantiation(
+    EmptyShell Empty, unsigned NumInstantiations, unsigned NumSharedStmts)
+    : Stmt(CXXExpansionStmtInstantiationClass, Empty),
+      NumInstantiations(NumInstantiations), NumSharedStmts(NumSharedStmts) {
+  assert(NumSharedStmts <= 4 && "might have to allocate more bits for this");
+}
+
+CXXExpansionStmtInstantiation::CXXExpansionStmtInstantiation(
+    SourceLocation BeginLoc, SourceLocation EndLoc,
+    ArrayRef<Stmt *> Instantiations, ArrayRef<Stmt *> SharedStmts,
+    bool ShouldApplyLifetimeExtensionToSharedStmts)
+    : Stmt(CXXExpansionStmtInstantiationClass), BeginLoc(BeginLoc),
+      EndLoc(EndLoc), NumInstantiations(unsigned(Instantiations.size())),
+      NumSharedStmts(unsigned(SharedStmts.size())),
+      ShouldApplyLifetimeExtensionToSharedStmts(
+          ShouldApplyLifetimeExtensionToSharedStmts) {
+  assert(NumSharedStmts <= 4 && "might have to allocate more bits for this");
+  llvm::uninitialized_copy(Instantiations, getTrailingObjects());
+  llvm::uninitialized_copy(SharedStmts,
+                           getTrailingObjects() + NumInstantiations);
+}
+
+CXXExpansionStmtInstantiation *CXXExpansionStmtInstantiation::Create(
+    ASTContext &C, SourceLocation BeginLoc, SourceLocation EndLoc,
+    ArrayRef<Stmt *> Instantiations, ArrayRef<Stmt *> SharedStmts,
+    bool ShouldApplyLifetimeExtensionToSharedStmts) {
+  void *Mem = C.Allocate(
+      totalSizeToAlloc<Stmt *>(Instantiations.size() + SharedStmts.size()),
+      alignof(CXXExpansionStmtInstantiation));
+  return new (Mem) CXXExpansionStmtInstantiation(
+      BeginLoc, EndLoc, Instantiations, SharedStmts,
+      ShouldApplyLifetimeExtensionToSharedStmts);
+}
+
+CXXExpansionStmtInstantiation *
+CXXExpansionStmtInstantiation::CreateEmpty(ASTContext &C, EmptyShell Empty,
+                                           unsigned NumInstantiations,
+                                           unsigned NumSharedStmts) {
+  void *Mem =
+      C.Allocate(totalSizeToAlloc<Stmt *>(NumInstantiations + NumSharedStmts),
+                 alignof(CXXExpansionStmtInstantiation));
+  return new (Mem)
+      CXXExpansionStmtInstantiation(Empty, NumInstantiations, NumSharedStmts);
+}
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index ff8ca01ec5477..6760d3bbe54cc 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -160,6 +160,8 @@ namespace {
     }
 
     void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
+    void VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node,
+                                      Expr *Initializer = nullptr);
 
 #define ABSTRACT_STMT(CLASS)
 #define STMT(CLASS, PARENT) \
@@ -263,7 +265,8 @@ void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
   PrintRawDeclStmt(Node);
   // Certain pragma declarations shouldn't have a semi-colon after them.
   if (!Node->isSingleDecl() ||
-      !isa<OpenACCDeclareDecl, OpenACCRoutineDecl>(Node->getSingleDecl()))
+      !isa<CXXExpansionStmtDecl, OpenACCDeclareDecl, OpenACCRoutineDecl>(
+          Node->getSingleDecl()))
     OS << ";";
   OS << NL;
 }
@@ -447,6 +450,63 @@ void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt 
*Node) {
   PrintControlledStmt(Node->getBody());
 }
 
+void StmtPrinter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node,
+                                               Expr *Initializer) {
+  OS << "template for (";
+  if (Node->getInit())
+    PrintInitStmt(Node->getInit(), 14);
+  PrintingPolicy SubPolicy(Policy);
+  SubPolicy.SuppressInitializers = true;
+  Node->getExpansionVariable()->print(OS, SubPolicy, IndentLevel);
+  OS << " : ";
+  PrintExpr(Initializer ? Initializer
+                        : Node->getExpansionVariable()->getInit());
+  OS << ")";
+  PrintControlledStmt(Node->getBody());
+}
+
+void StmtPrinter::VisitCXXEnumeratingExpansionStmtPattern(
+    CXXEnumeratingExpansionStmtPattern *Node) {
+  VisitCXXExpansionStmtPattern(Node);
+}
+
+void StmtPrinter::VisitCXXIteratingExpansionStmtPattern(
+    CXXIteratingExpansionStmtPattern *Node) {
+  VisitCXXExpansionStmtPattern(Node, Node->getRangeVar()->getInit());
+}
+
+void StmtPrinter::VisitCXXDestructuringExpansionStmtPattern(
+    CXXDestructuringExpansionStmtPattern *Node) {
+  VisitCXXExpansionStmtPattern(Node);
+}
+
+void StmtPrinter::VisitCXXDependentExpansionStmtPattern(
+    CXXDependentExpansionStmtPattern *Node) {
+  VisitCXXExpansionStmtPattern(Node, Node->getExpansionInitializer());
+}
+
+void StmtPrinter::VisitCXXExpansionStmtInstantiation(
+    CXXExpansionStmtInstantiation *) {
+  llvm_unreachable("should never be printed");
+}
+
+void StmtPrinter::VisitCXXExpansionInitListExpr(
+    CXXExpansionInitListExpr *Node) {
+  OS << "{ ";
+  llvm::interleaveComma(Node->getExprs(), OS, [&](Expr *E) { PrintExpr(E); });
+  OS << " }";
+}
+
+void StmtPrinter::VisitCXXExpansionInitListSelectExpr(
+    CXXExpansionInitListSelectExpr *Node) {
+  PrintExpr(Node->getRangeExpr());
+}
+
+void StmtPrinter::VisitCXXDestructuringExpansionSelectExpr(
+    CXXDestructuringExpansionSelectExpr *Node) {
+  PrintExpr(Node->getDecompositionDecl()->getInit());
+}
+
 void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) {
   Indent();
   if (Node->isIfExists())
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 4a8c638c85331..45513c479e1d1 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -364,6 +364,37 @@ void StmtProfiler::VisitCXXForRangeStmt(const 
CXXForRangeStmt *S) {
   VisitStmt(S);
 }
 
+void StmtProfiler::VisitCXXExpansionStmtPattern(
+    const CXXExpansionStmtPattern *S) {
+  VisitStmt(S);
+}
+
+void StmtProfiler::VisitCXXEnumeratingExpansionStmtPattern(
+    const CXXEnumeratingExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+}
+
+void StmtProfiler::VisitCXXIteratingExpansionStmtPattern(
+    const CXXIteratingExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+}
+
+void StmtProfiler::VisitCXXDestructuringExpansionStmtPattern(
+    const CXXDestructuringExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+}
+
+void StmtProfiler::VisitCXXDependentExpansionStmtPattern(
+    const CXXDependentExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+}
+
+void StmtProfiler::VisitCXXExpansionStmtInstantiation(
+    const CXXExpansionStmtInstantiation *S) {
+  VisitStmt(S);
+  ID.AddBoolean(S->shouldApplyLifetimeExtensionToSharedStmts());
+}
+
 void StmtProfiler::VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) {
   VisitStmt(S);
   ID.AddBoolean(S->isIfExists());
@@ -2400,6 +2431,22 @@ void StmtProfiler::VisitSourceLocExpr(const 
SourceLocExpr *E) {
 
 void StmtProfiler::VisitEmbedExpr(const EmbedExpr *E) { VisitExpr(E); }
 
+void StmtProfiler::VisitCXXExpansionInitListExpr(
+    const CXXExpansionInitListExpr *E) {
+  VisitExpr(E);
+}
+
+void StmtProfiler::VisitCXXExpansionInitListSelectExpr(
+    const CXXExpansionInitListSelectExpr *E) {
+  VisitExpr(E);
+}
+
+void StmtProfiler::VisitCXXDestructuringExpansionSelectExpr(
+    const CXXDestructuringExpansionSelectExpr *E) {
+  VisitExpr(E);
+  VisitDecl(E->getDecompositionDecl());
+}
+
 void StmtProfiler::VisitRecoveryExpr(const RecoveryExpr *E) { VisitExpr(E); }
 
 void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 41aebdb8d2f1b..4d19bf63f3536 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -951,7 +951,11 @@ void TextNodeDumper::dumpBareDeclRef(const Decl *D) {
       switch (ND->getKind()) {
       case Decl::Decomposition: {
         auto *DD = cast<DecompositionDecl>(ND);
-        OS << " first_binding '" << DD->bindings()[0]->getDeclName() << '\'';
+
+        // Empty decomposition decls can occur in destructuring expansion
+        // statements.
+        if (!DD->bindings().empty())
+          OS << " first_binding '" << DD->bindings()[0]->getDeclName() << '\'';
         break;
       }
       case Decl::Field: {
@@ -1495,6 +1499,12 @@ void clang::TextNodeDumper::VisitCoreturnStmt(const 
CoreturnStmt *Node) {
     OS << " implicit";
 }
 
+void TextNodeDumper::VisitCXXExpansionStmtInstantiation(
+    const CXXExpansionStmtInstantiation *Node) {
+  if (Node->shouldApplyLifetimeExtensionToSharedStmts())
+    OS << " applies_lifetime_extension";
+}
+
 void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) {
   if (Node->hasAPValueResult())
     AddChild("value",
@@ -1826,6 +1836,17 @@ void TextNodeDumper::VisitCXXDependentScopeMemberExpr(
   OS << " " << (Node->isArrow() ? "->" : ".") << Node->getMember();
 }
 
+void TextNodeDumper::VisitCXXExpansionInitListExpr(
+    const CXXExpansionInitListExpr *Node) {
+  if (Node->containsPackExpansion())
+    OS << " contains_pack";
+}
+
+void TextNodeDumper::VisitCXXDestructuringExpansionSelectExpr(
+    const CXXDestructuringExpansionSelectExpr *Node) {
+  dumpDeclRef(Node->getDecompositionDecl());
+}
+
 void TextNodeDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
   OS << " selector=";
   Node->getSelector().print(OS);
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 46addea232b03..5fbfb4023ee4d 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1632,14 +1632,15 @@ DeclContext *Sema::getFunctionLevelDeclContext(bool 
AllowLambda) const {
   DeclContext *DC = CurContext;
 
   while (true) {
-    if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC) ||
-        isa<RequiresExprBodyDecl>(DC)) {
+    if (isa<BlockDecl, EnumDecl, CapturedDecl, RequiresExprBodyDecl,
+            CXXExpansionStmtDecl>(DC)) {
       DC = DC->getParent();
     } else if (!AllowLambda && isa<CXXMethodDecl>(DC) &&
                cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
                cast<CXXRecordDecl>(DC->getParent())->isLambda()) {
       DC = DC->getParent()->getParent();
-    } else break;
+    } else
+      break;
   }
 
   return DC;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 651437a6f4c30..468376039fae5 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -7437,7 +7437,7 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
   if (DC->getDeclKind() == Decl::HLSLBuffer)
     return false;
 
-  if (isa<RequiresExprBodyDecl>(DC))
+  if (isa<RequiresExprBodyDecl, CXXExpansionStmtDecl>(DC))
     return false;
   llvm_unreachable("Unexpected context");
 }
@@ -7447,7 +7447,7 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) 
{
   if (DC->isFileContext() || DC->isFunctionOrMethod() ||
       isa<OMPDeclareReductionDecl>(DC) || isa<OMPDeclareMapperDecl>(DC))
     return true;
-  if (DC->isRecord())
+  if (DC->isRecord() || isa<CXXExpansionStmtDecl>(DC))
     return false;
   llvm_unreachable("Unexpected context");
 }
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp 
b/clang/lib/Sema/SemaExceptionSpec.cpp
index a0483c3027199..a56f933638190 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1288,6 +1288,9 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Expr::ConvertVectorExprClass:
   case Expr::VAArgExprClass:
   case Expr::CXXParenListInitExprClass:
+  case Expr::CXXExpansionInitListSelectExprClass:
+  case Expr::CXXExpansionInitListExprClass:
+  case Expr::CXXDestructuringExpansionSelectExprClass:
     return canSubStmtsThrow(*this, S);
 
   case Expr::CompoundLiteralExprClass:
@@ -1348,6 +1351,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Expr::DependentScopeDeclRefExprClass:
   case Expr::CXXFoldExprClass:
   case Expr::RecoveryExprClass:
+  case Expr::CXXDependentExpansionStmtPatternClass:
     return CT_Dependent;
 
   case Expr::AsTypeExprClass:
@@ -1538,6 +1542,10 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Stmt::SEHTryStmtClass:
   case Stmt::SwitchStmtClass:
   case Stmt::WhileStmtClass:
+  case Stmt::CXXEnumeratingExpansionStmtPatternClass:
+  case Stmt::CXXIteratingExpansionStmtPatternClass:
+  case Stmt::CXXDestructuringExpansionStmtPatternClass:
+  case Stmt::CXXExpansionStmtInstantiationClass:
     return canSubStmtsThrow(*this, S);
 
   case Stmt::DeclStmtClass: {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d3c2cc559ea20..7fc6d3cff36b0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19300,11 +19300,12 @@ bool Sema::tryCaptureVariable(
     QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) {
   // An init-capture is notionally from the context surrounding its
   // declaration, but its parent DC is the lambda class.
-  DeclContext *VarDC = Var->getDeclContext();
+  DeclContext *VarDC =
+      Var->getDeclContext()->getEnclosingNonExpansionStatementContext();
   DeclContext *DC = CurContext;
 
   // Skip past RequiresExprBodys because they don't constitute function scopes.
-  while (DC->isRequiresExprBody())
+  while (DC->isRequiresExprBody() || DC->isExpansionStmt())
     DC = DC->getParent();
 
   // tryCaptureVariable is called every time a DeclRef is formed,
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 43bcb4f743cfa..0d7e2a9c5b324 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -7600,7 +7600,6 @@ static void 
CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
     Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) {
 
   assert(!S.isUnevaluatedContext());
-  assert(S.CurContext->isDependentContext());
 #ifndef NDEBUG
   DeclContext *DC = S.CurContext;
   while (isa_and_nonnull<CapturedDecl>(DC))
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index f65c55a209622..c618f4e0a70db 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -100,8 +100,9 @@ static inline UnsignedOrNone 
getStackIndexOfNearestEnclosingCaptureReadyLambda(
     // innermost nested lambda are dependent (otherwise we wouldn't have
     // arrived here) - so we don't yet have a lambda that can capture the
     // variable.
-    if (IsCapturingVariable &&
-        VarToCapture->getDeclContext()->Equals(EnclosingDC))
+    if (IsCapturingVariable && VarToCapture->getDeclContext()
+                                   ->getEnclosingNonExpansionStatementContext()
+                                   ->Equals(EnclosingDC))
       return NoLambdaIsCaptureReady;
 
     // For an enclosing lambda to be capture ready for an entity, all
@@ -126,7 +127,8 @@ static inline UnsignedOrNone 
getStackIndexOfNearestEnclosingCaptureReadyLambda(
       if (IsCapturingThis && !LSI->isCXXThisCaptured())
         return NoLambdaIsCaptureReady;
     }
-    EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC);
+    EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC)
+                      ->getEnclosingNonExpansionStatementContext();
 
     assert(CurScopeIndex);
     --CurScopeIndex;
@@ -190,11 +192,6 @@ UnsignedOrNone 
clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
     return NoLambdaIsCaptureCapable;
 
   const unsigned IndexOfCaptureReadyLambda = *OptionalStackIndex;
-  assert(((IndexOfCaptureReadyLambda != (FunctionScopes.size() - 1)) ||
-          S.getCurGenericLambda()) &&
-         "The capture ready lambda for a potential capture can only be the "
-         "current lambda if it is a generic lambda");
-
   const sema::LambdaScopeInfo *const CaptureReadyLambdaLSI =
       cast<sema::LambdaScopeInfo>(FunctionScopes[IndexOfCaptureReadyLambda]);
 
@@ -248,7 +245,7 @@ CXXRecordDecl *
 Sema::createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo 
*Info,
                               unsigned LambdaDependencyKind,
                               LambdaCaptureDefault CaptureDefault) {
-  DeclContext *DC = CurContext;
+  DeclContext *DC = CurContext->getEnclosingNonExpansionStatementContext();
 
   bool IsGenericLambda =
       Info && getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -1376,7 +1373,9 @@ void Sema::ActOnLambdaClosureQualifiers(LambdaIntroducer 
&Intro,
   // odr-use 'this' (in particular, in a default initializer for a non-static
   // data member).
   if (Intro.Default != LCD_None &&
-      !LSI->Lambda->getParent()->isFunctionOrMethod() &&
+      !LSI->Lambda->getParent()
+           ->getEnclosingNonExpansionStatementContext()
+           ->isFunctionOrMethod() &&
       (getCurrentThisType().isNull() ||
        CheckCXXThisCapture(SourceLocation(), /*Explicit=*/true,
                            /*BuildAndDiagnose=*/false)))
@@ -2519,9 +2518,12 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII::
   while (FDPattern && FD) {
     InstantiationAndPatterns.emplace_back(FDPattern, FD);
 
-    FDPattern =
-        dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FDPattern));
-    FD = dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FD));
+    FDPattern = dyn_cast<FunctionDecl>(
+        getLambdaAwareParentOfDeclContext(FDPattern)
+            ->getEnclosingNonExpansionStatementContext());
+    FD = dyn_cast<FunctionDecl>(
+        getLambdaAwareParentOfDeclContext(FD)
+            ->getEnclosingNonExpansionStatementContext());
   }
 
   // Add instantiated parameters and local vars to scopes, starting from the
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 5915d6e57d893..88dcd27d45ad2 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -4455,7 +4455,9 @@ LabelDecl *Sema::LookupExistingLabel(IdentifierInfo *II, 
SourceLocation Loc) {
                                     RedeclarationKind::NotForRedeclaration);
   // If we found a label, check to see if it is in the same context as us.
   // When in a Block, we don't want to reuse a label in an enclosing function.
-  if (!Res || Res->getDeclContext() != CurContext)
+  if (!Res ||
+      Res->getDeclContext()->getEnclosingNonExpansionStatementContext() !=
+          CurContext->getEnclosingNonExpansionStatementContext())
     return nullptr;
   return cast<LabelDecl>(Res);
 }
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 26693514bb278..f8136c3c24a52 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2087,6 +2087,11 @@ Decl 
*TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
       InstantiatedMessageExpr.get(), D->getRParenLoc(), D->isFailed());
 }
 
+Decl *TemplateDeclInstantiator::VisitCXXExpansionStmtDecl(
+    CXXExpansionStmtDecl *OldESD) {
+  llvm_unreachable("TODO");
+}
+
 Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
   EnumDecl *PrevDecl = nullptr;
   if (EnumDecl *PatternPrev = getPreviousDeclForInstantiation(D)) {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 0e8b674a006d0..f181d0abb5dfd 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -9292,6 +9292,59 @@ 
TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
   return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
 }
 
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformCXXEnumeratingExpansionStmtPattern(
+    CXXEnumeratingExpansionStmtPattern *S) {
+  llvm_unreachable("TOOD");
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformCXXIteratingExpansionStmtPattern(
+    CXXIteratingExpansionStmtPattern *S) {
+  llvm_unreachable("TOOD");
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformCXXDependentExpansionStmtPattern(
+    CXXDependentExpansionStmtPattern *S) {
+  llvm_unreachable("TOOD");
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformCXXDestructuringExpansionStmtPattern(
+    CXXDestructuringExpansionStmtPattern *) {
+  // The only time we instantiate an expansion statement is if its expansion
+  // size is dependent (otherwise, we only instantiate the expansions and
+  // leave the underlying CXXExpansionStmtPattern as-is). Since destructuring
+  // expansion statements never have a dependent size, we should never get 
here.
+  llvm_unreachable("Should never be instantiated");
+}
+
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformCXXExpansionInitListExpr(
+    CXXExpansionInitListExpr *E) {
+  llvm_unreachable("TOOD");
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformCXXExpansionStmtInstantiation(
+    CXXExpansionStmtInstantiation *S) {
+  llvm_unreachable("TOOD");
+}
+
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformCXXExpansionInitListSelectExpr(
+    CXXExpansionInitListSelectExpr *E) {
+  llvm_unreachable("TOOD");
+}
+
+template <typename Derived>
+ExprResult 
TreeTransform<Derived>::TransformCXXDestructuringExpansionSelectExpr(
+    CXXDestructuringExpansionSelectExpr *E) {
+  llvm_unreachable("TOOD");
+}
+
 template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformMSDependentExistsStmt(
diff --git a/clang/lib/Serialization/ASTCommon.cpp 
b/clang/lib/Serialization/ASTCommon.cpp
index 69db02f2efc40..d07661a5b2f64 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -459,6 +459,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
   case Decl::HLSLRootSignature:
   case Decl::OpenACCDeclare:
   case Decl::OpenACCRoutine:
+  case Decl::CXXExpansionStmt:
     return false;
 
   // These indirectly derive from Redeclarable<T> but are not actually
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp 
b/clang/lib/Serialization/ASTReaderDecl.cpp
index 5456e73956659..3086d7315a862 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -405,6 +405,7 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, 
void> {
   void VisitFriendDecl(FriendDecl *D);
   void VisitFriendTemplateDecl(FriendTemplateDecl *D);
   void VisitStaticAssertDecl(StaticAssertDecl *D);
+  void VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D);
   void VisitBlockDecl(BlockDecl *BD);
   void VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D);
   void VisitCapturedDecl(CapturedDecl *CD);
@@ -2769,6 +2770,14 @@ void 
ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
   D->RParenLoc = readSourceLocation();
 }
 
+void ASTDeclReader::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) {
+  VisitDecl(D);
+  D->Expansion = cast<CXXExpansionStmtPattern>(Record.readStmt());
+  D->Instantiations =
+      cast_or_null<CXXExpansionStmtInstantiation>(Record.readStmt());
+  D->TParams = Record.readTemplateParameterList();
+}
+
 void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) {
   VisitDecl(D);
 }
@@ -4083,6 +4092,9 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
   case DECL_STATIC_ASSERT:
     D = StaticAssertDecl::CreateDeserialized(Context, ID);
     break;
+  case DECL_EXPANSION_STMT:
+    D = CXXExpansionStmtDecl::CreateDeserialized(Context, ID);
+    break;
   case DECL_OBJC_METHOD:
     D = ObjCMethodDecl::CreateDeserialized(Context, ID);
     break;
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index eef97a8588f0b..c74113c4ab0da 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1730,6 +1730,77 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt 
*S) {
   S->setBody(Record.readSubStmt());
 }
 
+void ASTStmtReader::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
+  VisitStmt(S);
+  S->LParenLoc = readSourceLocation();
+  S->ColonLoc = readSourceLocation();
+  S->RParenLoc = readSourceLocation();
+  S->ParentDecl = cast<CXXExpansionStmtDecl>(Record.readDeclRef());
+  S->setInit(Record.readSubStmt());
+  S->setExpansionVarStmt(Record.readSubStmt());
+  S->setBody(Record.readSubStmt());
+}
+
+void ASTStmtReader::VisitCXXExpansionStmtInstantiation(
+    CXXExpansionStmtInstantiation *S) {
+  VisitStmt(S);
+  Record.skipInts(2);
+  S->BeginLoc = readSourceLocation();
+  S->EndLoc = readSourceLocation();
+  for (unsigned I = 0; I < S->getNumSubStmts(); ++I)
+    S->getAllSubStmts()[I] = Record.readSubStmt();
+  S->setShouldApplyLifetimeExtensionToSharedStmts(Record.readBool());
+}
+
+void ASTStmtReader::VisitCXXEnumeratingExpansionStmtPattern(
+    CXXEnumeratingExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+}
+
+void ASTStmtReader::VisitCXXIteratingExpansionStmtPattern(
+    CXXIteratingExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+  S->setRangeVarStmt(cast<DeclStmt>(Record.readSubStmt()));
+  S->setBeginVarStmt(cast<DeclStmt>(Record.readSubStmt()));
+  S->setEndVarStmt(cast<DeclStmt>(Record.readSubStmt()));
+}
+
+void ASTStmtReader::VisitCXXDestructuringExpansionStmtPattern(
+    CXXDestructuringExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+  S->setDecompositionDeclStmt(Record.readSubStmt());
+}
+
+void ASTStmtReader::VisitCXXDependentExpansionStmtPattern(
+    CXXDependentExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+  S->setExpansionInitializer(Record.readSubExpr());
+}
+
+void ASTStmtReader::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) 
{
+  VisitExpr(E);
+  assert(Record.peekInt() == E->getNumExprs() && "NumExprFields is wrong ?");
+  Record.skipInts(1);
+  E->LBraceLoc = readSourceLocation();
+  E->RBraceLoc = readSourceLocation();
+  for (unsigned I = 0; I < E->getNumExprs(); ++I)
+    E->getExprs()[I] = Record.readSubExpr();
+}
+
+void ASTStmtReader::VisitCXXExpansionInitListSelectExpr(
+    CXXExpansionInitListSelectExpr *E) {
+  VisitExpr(E);
+  E->setRangeExpr(cast<CXXExpansionInitListExpr>(Record.readSubExpr()));
+  E->setIndexExpr(Record.readSubExpr());
+}
+
+void ASTStmtReader::VisitCXXDestructuringExpansionSelectExpr(
+    CXXDestructuringExpansionSelectExpr *E) {
+  VisitExpr(E);
+  E->setDecompositionDecl(cast<DecompositionDecl>(Record.readDeclRef()));
+  E->setIndexExpr(Record.readSubExpr());
+}
+
 void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
   VisitStmt(S);
   S->KeywordLoc = readSourceLocation();
@@ -3566,6 +3637,28 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
              /*numHandlers=*/Record[ASTStmtReader::NumStmtFields]);
       break;
 
+    case STMT_CXX_ENUMERATING_EXPANSION:
+      S = new (Context) CXXEnumeratingExpansionStmtPattern(Empty);
+      break;
+
+    case STMT_CXX_ITERATING_EXPANSION:
+      S = new (Context) CXXIteratingExpansionStmtPattern(Empty);
+      break;
+
+    case STMT_CXX_DESTRUCTURING_EXPANSION:
+      S = new (Context) CXXDestructuringExpansionStmtPattern(Empty);
+      break;
+
+    case STMT_CXX_DEPENDENT_EXPANSION:
+      S = new (Context) CXXDependentExpansionStmtPattern(Empty);
+      break;
+
+    case STMT_CXX_EXPANSION_INSTANTIATION:
+      S = CXXExpansionStmtInstantiation::CreateEmpty(
+          Context, Empty, Record[ASTStmtReader::NumStmtFields],
+          Record[ASTStmtReader::NumStmtFields + 1]);
+      break;
+
     case STMT_CXX_FOR_RANGE:
       S = new (Context) CXXForRangeStmt(Empty);
       break;
@@ -4443,6 +4536,20 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       S = new (Context) ConceptSpecializationExpr(Empty);
       break;
     }
+
+    case EXPR_CXX_EXPANSION_INIT_LIST:
+      S = CXXExpansionInitListExpr::CreateEmpty(
+          Context, Empty, Record[ASTStmtReader::NumExprFields]);
+      break;
+
+    case EXPR_CXX_EXPANSION_INIT_LIST_SELECT:
+      S = new (Context) CXXExpansionInitListSelectExpr(Empty);
+      break;
+
+    case EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT:
+      S = new (Context) CXXDestructuringExpansionSelectExpr(Empty);
+      break;
+
     case STMT_OPENACC_COMPUTE_CONSTRUCT: {
       unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
       S = OpenACCComputeConstruct::CreateEmpty(Context, NumClauses);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp 
b/clang/lib/Serialization/ASTWriterDecl.cpp
index c9f8797ab973f..23d11341d131a 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -144,6 +144,7 @@ namespace clang {
     void VisitFriendDecl(FriendDecl *D);
     void VisitFriendTemplateDecl(FriendTemplateDecl *D);
     void VisitStaticAssertDecl(StaticAssertDecl *D);
+    void VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D);
     void VisitBlockDecl(BlockDecl *D);
     void VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D);
     void VisitCapturedDecl(CapturedDecl *D);
@@ -2188,6 +2189,14 @@ void 
ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
   Code = serialization::DECL_STATIC_ASSERT;
 }
 
+void ASTDeclWriter::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) {
+  VisitDecl(D);
+  Record.AddStmt(D->getExpansionPattern());
+  Record.AddStmt(D->getInstantiations());
+  Record.AddTemplateParameterList(D->getTemplateParameters());
+  Code = serialization::DECL_EXPANSION_STMT;
+}
+
 /// Emit the DeclContext part of a declaration context decl.
 void ASTDeclWriter::VisitDeclContext(DeclContext *DC) {
   static_assert(DeclContext::NumDeclContextBits == 13,
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp 
b/clang/lib/Serialization/ASTWriterStmt.cpp
index acf345392aa1a..d795b23525888 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1704,6 +1704,85 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt 
*S) {
   Code = serialization::STMT_CXX_FOR_RANGE;
 }
 
+void ASTStmtWriter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
+  VisitStmt(S);
+  Record.AddSourceLocation(S->getLParenLoc());
+  Record.AddSourceLocation(S->getColonLoc());
+  Record.AddSourceLocation(S->getRParenLoc());
+  Record.AddDeclRef(S->getDecl());
+  Record.AddStmt(S->getInit());
+  Record.AddStmt(S->getExpansionVarStmt());
+  Record.AddStmt(S->getBody());
+}
+
+void ASTStmtWriter::VisitCXXExpansionStmtInstantiation(
+    CXXExpansionStmtInstantiation *S) {
+  VisitStmt(S);
+  Record.push_back(S->getInstantiations().size());
+  Record.push_back(S->getSharedStmts().size());
+  Record.AddSourceLocation(S->getBeginLoc());
+  Record.AddSourceLocation(S->getEndLoc());
+  for (Stmt *St : S->getAllSubStmts())
+    Record.AddStmt(St);
+  Record.push_back(S->shouldApplyLifetimeExtensionToSharedStmts());
+  Code = serialization::STMT_CXX_EXPANSION_INSTANTIATION;
+}
+
+void ASTStmtWriter::VisitCXXEnumeratingExpansionStmtPattern(
+    CXXEnumeratingExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+  Code = serialization::STMT_CXX_ENUMERATING_EXPANSION;
+}
+
+void ASTStmtWriter::VisitCXXIteratingExpansionStmtPattern(
+    CXXIteratingExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+  Record.AddStmt(S->getRangeVarStmt());
+  Record.AddStmt(S->getBeginVarStmt());
+  Record.AddStmt(S->getEndVarStmt());
+  Code = serialization::STMT_CXX_ITERATING_EXPANSION;
+}
+
+void ASTStmtWriter::VisitCXXDestructuringExpansionStmtPattern(
+    CXXDestructuringExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+  Record.AddStmt(S->getDecompositionDeclStmt());
+  Code = serialization::STMT_CXX_DESTRUCTURING_EXPANSION;
+}
+
+void ASTStmtWriter::VisitCXXDependentExpansionStmtPattern(
+    CXXDependentExpansionStmtPattern *S) {
+  VisitCXXExpansionStmtPattern(S);
+  Record.AddStmt(S->getExpansionInitializer());
+  Code = serialization::STMT_CXX_DEPENDENT_EXPANSION;
+}
+
+void ASTStmtWriter::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) 
{
+  VisitExpr(E);
+  Record.push_back(E->getNumExprs());
+  Record.AddSourceLocation(E->getLBraceLoc());
+  Record.AddSourceLocation(E->getRBraceLoc());
+  for (Expr *SubExpr : E->getExprs())
+    Record.AddStmt(SubExpr);
+  Code = serialization::EXPR_CXX_EXPANSION_INIT_LIST;
+}
+
+void ASTStmtWriter::VisitCXXExpansionInitListSelectExpr(
+    CXXExpansionInitListSelectExpr *E) {
+  VisitExpr(E);
+  Record.AddStmt(E->getRangeExpr());
+  Record.AddStmt(E->getIndexExpr());
+  Code = serialization::EXPR_CXX_EXPANSION_INIT_LIST_SELECT;
+}
+
+void ASTStmtWriter::VisitCXXDestructuringExpansionSelectExpr(
+    CXXDestructuringExpansionSelectExpr *E) {
+  VisitExpr(E);
+  Record.AddDeclRef(E->getDecompositionDecl());
+  Record.AddStmt(E->getIndexExpr());
+  Code = serialization::EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT;
+}
+
 void ASTStmtWriter::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
   VisitStmt(S);
   Record.AddSourceLocation(S->getKeywordLoc());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index a759aee47b8ea..38106f154c15e 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1752,6 +1752,14 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::SEHExceptStmtClass:
     case Stmt::SEHLeaveStmtClass:
     case Stmt::SEHFinallyStmtClass:
+    case Stmt::CXXEnumeratingExpansionStmtPatternClass:
+    case Stmt::CXXIteratingExpansionStmtPatternClass:
+    case Stmt::CXXDestructuringExpansionStmtPatternClass:
+    case Stmt::CXXDependentExpansionStmtPatternClass:
+    case Stmt::CXXExpansionStmtInstantiationClass:
+    case Stmt::CXXExpansionInitListExprClass:
+    case Stmt::CXXExpansionInitListSelectExprClass:
+    case Stmt::CXXDestructuringExpansionSelectExprClass:
     case Stmt::OMPCanonicalLoopClass:
     case Stmt::OMPParallelDirectiveClass:
     case Stmt::OMPSimdDirectiveClass:
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index f4d6fa72a1dfe..d4da1cc8ba722 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -7254,6 +7254,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
   case Decl::UnresolvedUsingIfExists:
   case Decl::OpenACCDeclare:
   case Decl::OpenACCRoutine:
+  case Decl::CXXExpansionStmt:
     return C;
 
   // Declaration kinds that don't make any sense here, but are
diff --git a/clang/tools/libclang/CXCursor.cpp 
b/clang/tools/libclang/CXCursor.cpp
index 0a43d73063c1f..f0ae4f0b593a2 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -290,6 +290,11 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl 
*Parent,
 
   case Stmt::CoroutineBodyStmtClass:
   case Stmt::CoreturnStmtClass:
+  case Stmt::CXXEnumeratingExpansionStmtPatternClass:
+  case Stmt::CXXIteratingExpansionStmtPatternClass:
+  case Stmt::CXXDestructuringExpansionStmtPatternClass:
+  case Stmt::CXXDependentExpansionStmtPatternClass:
+  case Stmt::CXXExpansionStmtInstantiationClass:
     K = CXCursor_UnexposedStmt;
     break;
 
@@ -338,6 +343,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl 
*Parent,
   case Stmt::EmbedExprClass:
   case Stmt::HLSLOutArgExprClass:
   case Stmt::OpenACCAsteriskSizeExprClass:
+  case Stmt::CXXExpansionInitListExprClass:
+  case Stmt::CXXExpansionInitListSelectExprClass:
+  case Stmt::CXXDestructuringExpansionSelectExprClass:
     K = CXCursor_UnexposedExpr;
     break;
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to