[clang] [Clang][P1061] Add stuctured binding packs (PR #121417)
Jason Rice via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 15 21:03:09 PST 2025
https://github.com/ricejasonf updated https://github.com/llvm/llvm-project/pull/121417
>From 3c81c5bd989f26331917f1401becc1cfa7f4a454 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Thu, 22 Jul 2021 16:46:33 -0700
Subject: [PATCH 01/13] [Clang][P1061] stuctured binding packs
---
clang/include/clang/AST/Decl.h | 8 +-
clang/include/clang/AST/DeclCXX.h | 22 +-
clang/include/clang/AST/ExprCXX.h | 48 ++++
clang/include/clang/AST/RecursiveASTVisitor.h | 1 +
.../clang/Basic/DiagnosticParseKinds.td | 5 +
.../clang/Basic/DiagnosticSemaKinds.td | 3 +
clang/include/clang/Basic/StmtNodes.td | 1 +
clang/include/clang/Sema/DeclSpec.h | 1 +
clang/include/clang/Sema/Sema.h | 4 +-
.../include/clang/Serialization/ASTBitCodes.h | 1 +
clang/lib/AST/ASTContext.cpp | 14 +-
clang/lib/AST/ASTImporter.cpp | 2 +-
clang/lib/AST/Decl.cpp | 11 +-
clang/lib/AST/DeclBase.cpp | 6 +-
clang/lib/AST/DeclCXX.cpp | 60 ++++-
clang/lib/AST/Expr.cpp | 5 +
clang/lib/AST/ExprCXX.cpp | 48 ++++
clang/lib/AST/ExprClassification.cpp | 7 +
clang/lib/AST/ExprConstant.cpp | 5 +-
clang/lib/AST/ItaniumMangle.cpp | 2 +-
clang/lib/AST/StmtPrinter.cpp | 11 +
clang/lib/AST/StmtProfile.cpp | 4 +
clang/lib/CodeGen/CGDebugInfo.cpp | 4 +-
clang/lib/CodeGen/CGDecl.cpp | 5 +-
clang/lib/CodeGen/CodeGenModule.cpp | 4 +-
clang/lib/Parse/ParseDecl.cpp | 28 ++-
clang/lib/Sema/SemaDecl.cpp | 10 +
clang/lib/Sema/SemaDeclCXX.cpp | 209 ++++++++++++++----
clang/lib/Sema/SemaExceptionSpec.cpp | 7 +-
clang/lib/Sema/SemaLambda.cpp | 1 +
clang/lib/Sema/SemaStmt.cpp | 14 +-
clang/lib/Sema/SemaTemplate.cpp | 7 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 40 +++-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 32 ++-
clang/lib/Sema/SemaTemplateVariadic.cpp | 73 +++++-
clang/lib/Sema/TreeTransform.h | 7 +
clang/lib/Serialization/ASTReaderStmt.cpp | 11 +
clang/lib/Serialization/ASTWriter.cpp | 1 +
clang/lib/Serialization/ASTWriterStmt.cpp | 11 +
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 +
clang/test/Parser/cxx2c-binding-pack.cpp | 7 +
.../cxx2c-binding-pack-nontemplate.cpp | 12 +
clang/test/SemaCXX/cxx2c-binding-pack.cpp | 82 +++++++
clang/test/SemaCXX/typo-correction-crash.cpp | 3 +-
clang/tools/libclang/CXCursor.cpp | 1 +
45 files changed, 728 insertions(+), 111 deletions(-)
create mode 100644 clang/test/Parser/cxx2c-binding-pack.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-binding-pack.cpp
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 67ee0bb412692a..bdf6c81732d0bc 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -698,6 +698,10 @@ class ValueDecl : public NamedDecl {
return const_cast<ValueDecl *>(this)->getPotentiallyDecomposedVarDecl();
}
+ /// Determine whether this value is actually a function parameter pack,
+ /// init-capture pack, or structured binding pack
+ bool isParameterPack() const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; }
@@ -1527,10 +1531,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
NonParmVarDeclBits.IsInitCapture = IC;
}
- /// Determine whether this variable is actually a function parameter pack or
- /// init-capture pack.
- bool isParameterPack() const;
-
/// Whether this local extern variable declaration's previous declaration
/// was declared in the same block scope. Only correct in C++.
bool isPreviousDeclInSameBlockScope() const {
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index c232556edeff70..12002db17fb3ad 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4131,8 +4131,9 @@ class BindingDecl : public ValueDecl {
/// binding).
Expr *Binding = nullptr;
- BindingDecl(DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id)
- : ValueDecl(Decl::Binding, DC, IdLoc, Id, QualType()) {}
+ BindingDecl(DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id,
+ QualType T)
+ : ValueDecl(Decl::Binding, DC, IdLoc, Id, T) {}
void anchor() override;
@@ -4140,7 +4141,8 @@ class BindingDecl : public ValueDecl {
friend class ASTDeclReader;
static BindingDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation IdLoc, IdentifierInfo *Id);
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ QualType T);
static BindingDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// Get the expression to which this declaration is bound. This may be null
@@ -4152,10 +4154,6 @@ class BindingDecl : public ValueDecl {
/// decomposition of.
ValueDecl *getDecomposedDecl() const { return Decomp; }
- /// Get the variable (if any) that holds the value of evaluating the binding.
- /// Only present for user-defined bindings for tuple-like types.
- VarDecl *getHoldingVar() const;
-
/// Set the binding for this BindingDecl, along with its declared type (which
/// should be a possibly-cv-qualified form of the type of the binding, or a
/// reference to such a type).
@@ -4167,6 +4165,9 @@ class BindingDecl : public ValueDecl {
/// Set the decomposed variable for this BindingDecl.
void setDecomposedDecl(ValueDecl *Decomposed) { Decomp = Decomposed; }
+ VarDecl *getHoldingVar() const;
+ static VarDecl *getHoldingVar(Expr *E);
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decl::Binding; }
};
@@ -4219,6 +4220,13 @@ class DecompositionDecl final
void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
+ /// Visit the variables (if any) that hold the values of evaluating the
+ /// binding. Only present for user-defined bindings for tuple-like types.
+ void VisitHoldingVars(llvm::function_ref<void(VarDecl *)> F) const;
+
+ // Visit the concrete bindings. (workaround)
+ void VisitBindings(llvm::function_ref<void(BindingDecl *)> F) const;
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decomposition; }
};
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 4cec89c979f775..6162c712c90dc3 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -5321,6 +5321,54 @@ class BuiltinBitCastExpr final
}
};
+class ResolvedUnexpandedPackExpr final
+ : public Expr,
+ private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Stmt *> {
+ friend TrailingObjects;
+
+ SourceLocation BeginLoc;
+ unsigned NumExprs;
+
+ ResolvedUnexpandedPackExpr(SourceLocation BL, QualType QT, unsigned NumExprs);
+
+public:
+ static ResolvedUnexpandedPackExpr *CreateDeserialized(ASTContext &C,
+ unsigned NumExprs);
+ static ResolvedUnexpandedPackExpr *
+ Create(ASTContext &C, SourceLocation BeginLoc, QualType T, unsigned NumExprs);
+ static ResolvedUnexpandedPackExpr *Create(ASTContext &C,
+ SourceLocation BeginLoc, QualType T,
+ llvm::ArrayRef<Expr *> Exprs);
+
+ unsigned getNumExprs() const { return NumExprs; }
+
+ Expr **getExprs() {
+ return reinterpret_cast<Expr **>(getTrailingObjects<Stmt *>());
+ }
+ Expr *const *getExprs() const {
+ return reinterpret_cast<Expr *const *>(getTrailingObjects<Stmt *>());
+ }
+
+ Expr *getExpansion(unsigned Idx) { return getExprs()[Idx]; }
+ Expr *getExpansion(unsigned Idx) const { return getExprs()[Idx]; }
+
+ // Iterators
+ child_range children() {
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() + getNumExprs());
+ }
+
+ SourceLocation getBeginLoc() const LLVM_READONLY { return BeginLoc; }
+ SourceLocation getEndLoc() const LLVM_READONLY { return BeginLoc; }
+
+ // Returns the resolved pack of a decl or nullptr
+ static ResolvedUnexpandedPackExpr *getFromDecl(Decl *);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ResolvedUnexpandedPackExprClass;
+ }
+};
+
} // namespace clang
#endif // LLVM_CLANG_AST_EXPRCXX_H
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index f5b32ed51698e0..9f8a8f2a8348f2 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2936,6 +2936,7 @@ DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
DEF_TRAVERSE_STMT(CXXFoldExpr, {})
DEF_TRAVERSE_STMT(AtomicExpr, {})
DEF_TRAVERSE_STMT(CXXParenListInitExpr, {})
+DEF_TRAVERSE_STMT(ResolvedUnexpandedPackExpr, {})
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {
if (S->getLifetimeExtendedTemporaryDecl()) {
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 86fcae209c40db..5ee6f9ff28c4c8 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1099,6 +1099,11 @@ def err_lambda_capture_misplaced_ellipsis : Error<
"the name of the capture">;
def err_lambda_capture_multiple_ellipses : Error<
"multiple ellipses in pack capture">;
+def err_binding_multiple_ellipses : Error<
+ "multiple ellipses in structured binding declaration">;
+def warn_cxx2c_binding_pack : Warning<
+ "structured binding pack is incompatible with C++ standards before C++2c">,
+ DefaultIgnore, InGroup<CXXPre26Compat>;
def err_capture_default_first : Error<
"capture default must be first">;
def ext_decl_attrs_on_lambda : ExtWarn<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 330ae045616aba..22012fb2663534 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5906,6 +5906,9 @@ def warn_cxx23_pack_indexing : Warning<
"pack indexing is incompatible with C++ standards before C++2c">,
DefaultIgnore, InGroup<CXXPre26Compat>;
+def err_pack_outside_template : Error<
+ "pack declaration outside of template">;
+
def err_fold_expression_packs_both_sides : Error<
"binary fold expression has unexpanded parameter packs in both operands">;
def err_fold_expression_empty : Error<
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 31280df93e4c6e..a5ac8eba371f2f 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -162,6 +162,7 @@ def MaterializeTemporaryExpr : StmtNode<Expr>;
def LambdaExpr : StmtNode<Expr>;
def CXXFoldExpr : StmtNode<Expr>;
def CXXParenListInitExpr: StmtNode<Expr>;
+def ResolvedUnexpandedPackExpr : StmtNode<Expr>;
// C++ Coroutines expressions
def CoroutineSuspendExpr : StmtNode<Expr, 1>;
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 06243f2624876f..5f5df3a45d41dc 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -1795,6 +1795,7 @@ class DecompositionDeclarator {
IdentifierInfo *Name;
SourceLocation NameLoc;
std::optional<ParsedAttributes> Attrs;
+ SourceLocation EllipsisLoc;
};
private:
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5ee7ea48cc983c..24e13278cb2a89 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -230,7 +230,8 @@ void threadSafetyCleanup(BeforeSet *Cache);
// FIXME: No way to easily map from TemplateTypeParmTypes to
// TemplateTypeParmDecls, so we have this horrible PointerUnion.
-typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>,
+typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *,
+ ResolvedUnexpandedPackExpr *>,
SourceLocation>
UnexpandedParameterPack;
@@ -6012,6 +6013,7 @@ class Sema final : public SemaBase {
RecordDecl *ClassDecl,
const IdentifierInfo *Name);
+ unsigned GetDecompositionElementCount(QualType DecompType);
void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
/// Stack containing information needed when in C++2a an 'auto' is encountered
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index dfd82afad40070..bab63be73e58e8 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1890,6 +1890,7 @@ enum StmtCode {
EXPR_PACK_EXPANSION, // PackExpansionExpr
EXPR_PACK_INDEXING, // PackIndexingExpr
EXPR_SIZEOF_PACK, // SizeOfPackExpr
+ EXPR_RESOLVED_UNEXPANDED_PACK, // ResolvedUnexpandedPackExpr
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr
EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 8b4ae58e8427a9..6216d896a88ac3 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12726,11 +12726,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
// Likewise, variables with tuple-like bindings are required if their
// bindings have side-effects.
- if (const auto *DD = dyn_cast<DecompositionDecl>(VD))
- for (const auto *BD : DD->bindings())
- if (const auto *BindingVD = BD->getHoldingVar())
- if (DeclMustBeEmitted(BindingVD))
- return true;
+ if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
+ bool BindingResult = false;
+ DD->VisitHoldingVars([&](VarDecl *BindingVD) {
+ if (DeclMustBeEmitted(BindingVD))
+ BindingResult = true;
+ });
+ if (BindingResult)
+ return true;
+ }
return false;
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 26d33b0d94795f..33b4fe0b8fecc9 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -2552,7 +2552,7 @@ ExpectedDecl ASTNodeImporter::VisitBindingDecl(BindingDecl *D) {
BindingDecl *ToD;
if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo()))
+ Name.getAsIdentifierInfo(), D->getType()))
return ToD;
Error Err = Error::success();
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 741e908cf9bc56..76c208bef6031c 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2659,10 +2659,6 @@ bool VarDecl::checkForConstantInitialization(
return Eval->HasConstantInitialization;
}
-bool VarDecl::isParameterPack() const {
- return isa<PackExpansionType>(getType());
-}
-
template<typename DeclT>
static DeclT *getDefinitionOrSelf(DeclT *D) {
assert(D);
@@ -5397,6 +5393,13 @@ bool ValueDecl::isInitCapture() const {
return false;
}
+bool ValueDecl::isParameterPack() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(this))
+ return NTTP->isParameterPack();
+
+ return isa_and_nonnull<PackExpansionType>(getType().getTypePtrOrNull());
+}
+
void ImplicitParamDecl::anchor() {}
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index fb701f76231bcd..6a5662f9d074e4 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -237,10 +237,12 @@ bool Decl::isTemplateParameterPack() const {
}
bool Decl::isParameterPack() const {
- if (const auto *Var = dyn_cast<VarDecl>(this))
+ if (isTemplateParameterPack())
+ return true;
+ if (const auto *Var = dyn_cast<ValueDecl>(this))
return Var->isParameterPack();
- return isTemplateParameterPack();
+ return false;
}
FunctionDecl *Decl::getAsFunction() {
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index af73c658d6a0c5..371bf5dcf02206 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3395,26 +3395,37 @@ VarDecl *ValueDecl::getPotentiallyDecomposedVarDecl() {
if (auto *Var = llvm::dyn_cast<VarDecl>(this))
return Var;
if (auto *BD = llvm::dyn_cast<BindingDecl>(this))
- return llvm::dyn_cast<VarDecl>(BD->getDecomposedDecl());
+ return llvm::dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
return nullptr;
}
void BindingDecl::anchor() {}
BindingDecl *BindingDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation IdLoc, IdentifierInfo *Id) {
- return new (C, DC) BindingDecl(DC, IdLoc, Id);
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ QualType T) {
+ return new (C, DC) BindingDecl(DC, IdLoc, Id, T);
}
BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
- return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr);
+ return new (C, ID)
+ BindingDecl(nullptr, SourceLocation(), nullptr, QualType());
}
VarDecl *BindingDecl::getHoldingVar() const {
Expr *B = getBinding();
if (!B)
return nullptr;
- auto *DRE = dyn_cast<DeclRefExpr>(B->IgnoreImplicit());
+ return getHoldingVar(B);
+}
+
+VarDecl *BindingDecl::getHoldingVar(Expr *E) {
+ auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreImplicit());
+ if (!DRE)
+ return nullptr;
+ if (auto *BD = dyn_cast<BindingDecl>(DRE->getDecl())) {
+ DRE = dyn_cast<DeclRefExpr>(BD->getBinding());
+ }
if (!DRE)
return nullptr;
@@ -3423,6 +3434,45 @@ VarDecl *BindingDecl::getHoldingVar() const {
return VD;
}
+void DecompositionDecl::VisitHoldingVars(
+ llvm::function_ref<void(VarDecl *)> F) const {
+ for (BindingDecl *B : bindings()) {
+ Expr *BE = B->getBinding();
+ // All BindingDecls will contain holding vars or none will
+ if (!BE)
+ return;
+
+ llvm::ArrayRef<Expr *> Exprs;
+ if (auto *RP = dyn_cast<ResolvedUnexpandedPackExpr>(BE))
+ Exprs = llvm::ArrayRef(RP->getExprs(), RP->getNumExprs());
+ else
+ Exprs = BE;
+
+ for (Expr *E : Exprs) {
+ VarDecl *VD = BindingDecl::getHoldingVar(E);
+ if (!VD)
+ return;
+ F(VD);
+ }
+ }
+}
+
+void DecompositionDecl::VisitBindings(
+ llvm::function_ref<void(BindingDecl *)> F) const {
+ for (BindingDecl *B : bindings()) {
+ llvm::ArrayRef<Expr *> Exprs;
+ if (B->isParameterPack()) {
+ auto *RP = cast<ResolvedUnexpandedPackExpr>(B->getBinding());
+ Exprs = llvm::ArrayRef(RP->getExprs(), RP->getNumExprs());
+ for (Expr *E : Exprs) {
+ auto *DRE = cast<DeclRefExpr>(E);
+ F(cast<BindingDecl>(DRE->getDecl()));
+ }
+ } else
+ F(B);
+ }
+}
+
void DecompositionDecl::anchor() {}
DecompositionDecl *DecompositionDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 8c8ccdb61dc01c..39f02ebf85b2ce 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3656,6 +3656,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
// These never have a side-effect.
return false;
+ // ResolvedUnexpandedPackExpr is currently only used for
+ // structed bindings which have no side effects
+ case ResolvedUnexpandedPackExprClass:
+ return false;
+
case ConstantExprClass:
// FIXME: Move this into the "return false;" block above.
return cast<ConstantExpr>(this)->getSubExpr()->HasSideEffects(
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index fc09d24fc30cb4..190af789d306ed 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1965,3 +1965,51 @@ CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee,
SubExprs[SubExpr::RHS] = RHS;
setDependence(computeDependence(this));
}
+
+ResolvedUnexpandedPackExpr::ResolvedUnexpandedPackExpr(SourceLocation BL,
+ QualType QT,
+ unsigned NumExprs)
+ : Expr(ResolvedUnexpandedPackExprClass, QT, VK_PRValue, OK_Ordinary),
+ BeginLoc(BL), NumExprs(NumExprs) {
+ setDependence(ExprDependence::TypeValueInstantiation |
+ ExprDependence::UnexpandedPack);
+}
+
+ResolvedUnexpandedPackExpr *
+ResolvedUnexpandedPackExpr::CreateDeserialized(ASTContext &Ctx,
+ unsigned NumExprs) {
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumExprs),
+ alignof(ResolvedUnexpandedPackExpr));
+ return new (Mem)
+ ResolvedUnexpandedPackExpr(SourceLocation(), QualType(), NumExprs);
+}
+
+ResolvedUnexpandedPackExpr *
+ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL,
+ QualType T, unsigned NumExprs) {
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumExprs),
+ alignof(ResolvedUnexpandedPackExpr));
+ ResolvedUnexpandedPackExpr *New =
+ new (Mem) ResolvedUnexpandedPackExpr(BL, T, NumExprs);
+
+ auto Exprs = llvm::MutableArrayRef(New->getExprs(), New->getNumExprs());
+ std::fill(Exprs.begin(), Exprs.end(), nullptr);
+
+ return New;
+}
+
+ResolvedUnexpandedPackExpr *
+ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL,
+ QualType T, ArrayRef<Expr *> Exprs) {
+ auto *New = Create(Ctx, BL, T, Exprs.size());
+ std::copy(Exprs.begin(), Exprs.end(), New->getExprs());
+ return New;
+}
+
+ResolvedUnexpandedPackExpr *ResolvedUnexpandedPackExpr::getFromDecl(Decl *D) {
+ // TODO P1858: Extend to VarDecls for P1858
+ if (auto *BD = dyn_cast<BindingDecl>(D)) {
+ return dyn_cast_or_null<ResolvedUnexpandedPackExpr>(BD->getBinding());
+ }
+ return nullptr;
+}
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index 3f37d06cc8f3a0..29a869bd76ca37 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -451,6 +451,13 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::PackExpansionExprClass:
return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
+ case Expr::ResolvedUnexpandedPackExprClass: {
+ if (cast<ResolvedUnexpandedPackExpr>(E)->getNumExprs() > 0)
+ return ClassifyInternal(
+ Ctx, cast<ResolvedUnexpandedPackExpr>(E)->getExpansion(0));
+ return Cl::CL_PRValue;
+ }
+
case Expr::MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(E)->isBoundToLvalueReference()
? Cl::CL_LValue
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index dd75dca647540a..b7ff7aa1d61ecc 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5155,9 +5155,7 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
OK &= EvaluateVarDecl(Info, VD);
if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(D))
- for (auto *BD : DD->bindings())
- if (auto *VD = BD->getHoldingVar())
- OK &= EvaluateDecl(Info, VD);
+ DD->VisitHoldingVars([&](VarDecl *HD) { OK &= EvaluateDecl(Info, HD); });
return OK;
}
@@ -17122,6 +17120,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::SYCLUniqueStableNameExprClass:
case Expr::CXXParenListInitExprClass:
case Expr::HLSLOutArgExprClass:
+ case Expr::ResolvedUnexpandedPackExprClass:
return ICEDiag(IK_NotICE, E->getBeginLoc());
case Expr::InitListExprClass: {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 47aa9b40dab845..ffa9703536b7f5 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4926,7 +4926,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
case Expr::SourceLocExprClass:
case Expr::EmbedExprClass:
case Expr::BuiltinBitCastExprClass:
- {
+ case Expr::ResolvedUnexpandedPackExprClass: {
NotPrimaryExpr();
if (!NullOut) {
// As bad as this diagnostic is, it's better than crashing.
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index c5d19f70fc6ea0..50bf880a4d37ea 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -44,9 +44,11 @@
#include "clang/Basic/TypeTraits.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -2556,6 +2558,15 @@ void StmtPrinter::VisitPackIndexingExpr(PackIndexingExpr *E) {
OS << "]";
}
+void StmtPrinter::VisitResolvedUnexpandedPackExpr(
+ ResolvedUnexpandedPackExpr *E) {
+ OS << "<<resolved pack(";
+ llvm::interleave(
+ E->getExprs(), E->getExprs() + E->getNumExprs(),
+ [this](auto *X) { PrintExpr(X); }, [this] { OS << ", "; });
+ OS << ")>>";
+}
+
void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *Node) {
OS << *Node->getParameterPack();
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 27313f9ae12752..1424f03ebf78bc 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2276,6 +2276,10 @@ void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) {
ID.AddInteger(0);
}
}
+void StmtProfiler::VisitResolvedUnexpandedPackExpr(
+ const ResolvedUnexpandedPackExpr *S) {
+ VisitExpr(S);
+}
void StmtProfiler::VisitPackIndexingExpr(const PackIndexingExpr *E) {
VisitExpr(E);
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index f29ddece5dbc95..db424dabc0575f 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -5067,10 +5067,10 @@ CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage,
assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
if (auto *DD = dyn_cast<DecompositionDecl>(VD)) {
- for (auto *B : DD->bindings()) {
+ DD->VisitBindings([&](BindingDecl *B) {
EmitDeclare(B, Storage, std::nullopt, Builder,
VD->getType()->isReferenceType());
- }
+ });
// Don't emit an llvm.dbg.declare for the composite storage as it doesn't
// correspond to a user variable.
return nullptr;
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 47b21bc9f63f04..06b4f39e1e3d81 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -104,7 +104,6 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Binding:
case Decl::UnresolvedUsingIfExists:
case Decl::HLSLBuffer:
- llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Record: // struct/union/class X;
case Decl::CXXRecord: // struct/union/class X; [C++]
if (CGDebugInfo *DI = getDebugInfo())
@@ -163,9 +162,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
"Should not see file-scope variables inside a function!");
EmitVarDecl(VD);
if (auto *DD = dyn_cast<DecompositionDecl>(&VD))
- for (auto *B : DD->bindings())
- if (auto *HD = B->getHoldingVar())
- EmitVarDecl(*HD);
+ DD->VisitHoldingVars([&](VarDecl *HD) { EmitVarDecl(*HD); });
return;
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index c49f7631488285..bfd459dabafe10 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6987,9 +6987,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::VarTemplateSpecialization:
EmitGlobal(cast<VarDecl>(D));
if (auto *DD = dyn_cast<DecompositionDecl>(D))
- for (auto *B : DD->bindings())
- if (auto *HD = B->getHoldingVar())
- EmitGlobal(HD);
+ DD->VisitHoldingVars([&](VarDecl *HD) { EmitGlobal(HD); });
break;
// Indirect fields from global anonymous structs and unions can be
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 937a94b02458c6..c298825fb88280 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7308,15 +7308,16 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
// If this doesn't look like a structured binding, maybe it's a misplaced
// array declarator.
- if (!(Tok.is(tok::identifier) &&
+ if (!(Tok.isOneOf(tok::identifier, tok::ellipsis) &&
NextToken().isOneOf(tok::comma, tok::r_square, tok::kw_alignas,
- tok::l_square)) &&
+ tok::identifier, tok::l_square)) &&
!(Tok.is(tok::r_square) &&
NextToken().isOneOf(tok::equal, tok::l_brace))) {
PA.Revert();
return ParseMisplacedBracketDeclarator(D);
}
+ bool HasEllipsis = false;
SmallVector<DecompositionDeclarator::Binding, 32> Bindings;
while (Tok.isNot(tok::r_square)) {
if (!Bindings.empty()) {
@@ -7331,11 +7332,12 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
Diag(Tok, diag::err_expected_comma_or_rsquare);
}
- SkipUntil(tok::r_square, tok::comma, tok::identifier,
- StopAtSemi | StopBeforeMatch);
+ // I don't know why this skipping was here
+ // SkipUntil(tok::r_square, tok::comma, tok::identifier,
+ // StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::comma))
ConsumeToken();
- else if (Tok.isNot(tok::identifier))
+ else if (Tok.is(tok::r_square))
break;
}
}
@@ -7343,6 +7345,20 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
if (isCXX11AttributeSpecifier())
DiagnoseAndSkipCXX11Attributes();
+ SourceLocation EllipsisLoc = {};
+
+ if (Tok.is(tok::ellipsis)) {
+ if (!getLangOpts().CPlusPlus26)
+ Diag(Tok, diag::warn_cxx2c_binding_pack);
+ if (HasEllipsis) {
+ Diag(Tok, diag::err_binding_multiple_ellipses);
+ break;
+ }
+ HasEllipsis = true;
+ EllipsisLoc = Tok.getLocation();
+ ConsumeToken();
+ }
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected) << tok::identifier;
break;
@@ -7360,7 +7376,7 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
MaybeParseCXX11Attributes(Attrs);
}
- Bindings.push_back({II, Loc, std::move(Attrs)});
+ Bindings.push_back({II, Loc, std::move(Attrs), EllipsisLoc});
}
if (Tok.isNot(tok::r_square))
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4001c4d263f1d2..ddb677dc1e70f2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9780,6 +9780,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R = TInfo->getType();
assert(R->isFunctionType());
+ bool NeedsExpansion = false;
+
if (R.getCanonicalType()->castAs<FunctionType>()->getCmseNSCallAttr())
Diag(D.getIdentifierLoc(), diag::err_function_decl_cmse_ns_call);
@@ -10964,6 +10966,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration)
ExternalDeclarations.push_back(NewFD);
+ if (NeedsExpansion) {
+ CodeSynthesisContext SynthCtx{};
+ pushCodeSynthesisContext(SynthCtx);
+ NewFD = dyn_cast_or_null<FunctionDecl>(
+ SubstDecl(NewFD, DC, MultiLevelTemplateArgumentList{}));
+ popCodeSynthesisContext();
+ }
+
return NewFD;
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index c5a72cf812ebc9..adabca19107f2b 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -888,7 +888,15 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
Previous.clear();
}
- auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, VarName);
+ QualType QT = Context.DependentTy;
+ if (B.EllipsisLoc.isValid()) {
+ if (!cast<Decl>(DC)->isTemplated())
+ Diag(B.EllipsisLoc, diag::err_pack_outside_template);
+ QT = Context.getPackExpansionType(QT, std::nullopt,
+ /*ExpectsPackInType=*/false);
+ }
+
+ auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name, QT);
ProcessDeclAttributeList(S, BD, *B.Attrs);
@@ -951,28 +959,130 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
return New;
}
+namespace {
+// CheckBindingsCount
+// - Checks the arity of the structured bindings
+// - Creates the resolved pack expr if there is
+// one
+bool CheckBindingsCount(Sema &S, DecompositionDecl *DD, QualType DecompType,
+ ArrayRef<BindingDecl *> Bindings,
+ unsigned MemberCount) {
+ auto BindingWithPackItr =
+ std::find_if(Bindings.begin(), Bindings.end(),
+ [](BindingDecl *D) -> bool { return D->isParameterPack(); });
+ bool HasPack = BindingWithPackItr != Bindings.end();
+ bool IsValid;
+ if (!HasPack) {
+ IsValid = Bindings.size() == MemberCount;
+ } else {
+ // there may not be more members than non-pack bindings
+ IsValid = MemberCount >= Bindings.size() - 1;
+ }
+
+ if (IsValid && HasPack) {
+ TemplateTypeParmDecl *DummyTemplateParam = TemplateTypeParmDecl::Create(
+ S.Context, S.Context.getTranslationUnitDecl(),
+ /*KeyLoc*/ SourceLocation(), /*NameLoc*/ SourceLocation(),
+ /*TemplateDepth*/ 0, /*AutoParameterPosition*/ 0,
+ /*Identifier*/ nullptr, false, /*IsParameterPack*/ true);
+
+ // create the pack expr and assign it to the binding
+ unsigned PackSize = MemberCount - Bindings.size() + 1;
+ QualType PackType = S.Context.getPackExpansionType(
+ QualType(DummyTemplateParam->getTypeForDecl(), 0), PackSize);
+ (*BindingWithPackItr)
+ ->setBinding(PackType,
+ ResolvedUnexpandedPackExpr::Create(
+ S.Context, DD->getBeginLoc(), DecompType, PackSize));
+ }
+
+ if (IsValid)
+ return false;
+
+ S.Diag(DD->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
+ << DecompType << (unsigned)Bindings.size() << MemberCount << MemberCount
+ << (MemberCount < Bindings.size());
+ return true;
+}
+
+// BindingInitWalker
+// - This implements a forward iterating flattened view
+// of structured bindings that may have a nested pack.
+// It allows the user to set the init expr for either the
+// BindingDecl or its ResolvedUnexpandedPackExpr
+struct BindingInitWalker {
+ using BindingItrTy = typename ArrayRef<BindingDecl *>::iterator;
+ using PackExprItrTy = typename MutableArrayRef<Expr *>::iterator;
+ Sema &SemaRef;
+ ArrayRef<BindingDecl *> Bindings;
+ ResolvedUnexpandedPackExpr *PackExpr = nullptr;
+ MutableArrayRef<Expr *> PackExprNodes;
+ BindingItrTy BindingItr;
+ PackExprItrTy PackExprItr;
+
+ BindingInitWalker(Sema &S, ArrayRef<BindingDecl *> Bs)
+ : SemaRef(S), Bindings(Bs), BindingItr(Bindings.begin()) {}
+
+ BindingDecl *get() { return *BindingItr; }
+
+ void commitAndAdvance(QualType T, Expr *E) {
+ BindingDecl *B = *BindingItr;
+ bool IsPackExpr =
+ isa_and_nonnull<ResolvedUnexpandedPackExpr>(B->getBinding());
+ if (IsPackExpr && !PackExpr) {
+ PackExpr = cast<ResolvedUnexpandedPackExpr>(B->getBinding());
+ PackExprNodes =
+ llvm::MutableArrayRef(PackExpr->getExprs(), PackExpr->getNumExprs());
+ PackExprItr = PackExprNodes.begin();
+ }
+
+ if (IsPackExpr) {
+ // Build a nested BindingDecl with a DeclRefExpr
+ auto *NestedBD =
+ BindingDecl::Create(SemaRef.Context, B->getDeclContext(),
+ B->getLocation(), B->getIdentifier(), T);
+
+ NestedBD->setBinding(T, E);
+ NestedBD->setDecomposedDecl(nullptr);
+ auto *DE = SemaRef.BuildDeclRefExpr(NestedBD, T.getNonReferenceType(),
+ VK_LValue, B->getLocation());
+ *PackExprItr = DE;
+ if (++PackExprItr != PackExprNodes.end())
+ return;
+ // If we hit the end of the pack exprs then
+ // continue to advance BindingItr
+ } else {
+ (*BindingItr)->setBinding(T, E);
+ }
+
+ ++BindingItr;
+ }
+};
+} // namespace
+
static bool checkSimpleDecomposition(
Sema &S, ArrayRef<BindingDecl *> Bindings, ValueDecl *Src,
- QualType DecompType, const llvm::APSInt &NumElems, QualType ElemType,
+ QualType DecompType, const llvm::APSInt &NumElemsAPS, QualType ElemType,
llvm::function_ref<ExprResult(SourceLocation, Expr *, unsigned)> GetInit) {
- if ((int64_t)Bindings.size() != NumElems) {
- S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
- << DecompType << (unsigned)Bindings.size()
- << (unsigned)NumElems.getLimitedValue(UINT_MAX)
- << toString(NumElems, 10) << (NumElems < Bindings.size());
+ unsigned NumElems = (unsigned)NumElemsAPS.getLimitedValue(UINT_MAX);
+
+ if (CheckBindingsCount(S, cast<DecompositionDecl>(Src), DecompType, Bindings,
+ NumElems)) {
+
return true;
}
- unsigned I = 0;
- for (auto *B : Bindings) {
+ auto Walker = BindingInitWalker(S, Bindings);
+ for (unsigned I = 0; I < NumElems; I++) {
+ BindingDecl *B = Walker.get();
SourceLocation Loc = B->getLocation();
ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
if (E.isInvalid())
return true;
- E = GetInit(Loc, E.get(), I++);
+ E = GetInit(Loc, E.get(), I);
if (E.isInvalid())
return true;
- B->setBinding(ElemType, E.get());
+ Walker.commitAndAdvance(ElemType, E.get());
}
return false;
@@ -1210,11 +1320,9 @@ static bool checkTupleLikeDecomposition(Sema &S,
ArrayRef<BindingDecl *> Bindings,
VarDecl *Src, QualType DecompType,
const llvm::APSInt &TupleSize) {
- if ((int64_t)Bindings.size() != TupleSize) {
- S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
- << DecompType << (unsigned)Bindings.size()
- << (unsigned)TupleSize.getLimitedValue(UINT_MAX)
- << toString(TupleSize, 10) << (TupleSize < Bindings.size());
+ unsigned NumElems = (unsigned)TupleSize.getLimitedValue(UINT_MAX);
+ if (CheckBindingsCount(S, cast<DecompositionDecl>(Src), DecompType, Bindings,
+ NumElems)) {
return true;
}
@@ -1249,8 +1357,9 @@ static bool checkTupleLikeDecomposition(Sema &S,
}
}
- unsigned I = 0;
- for (auto *B : Bindings) {
+ auto Walker = BindingInitWalker(S, Bindings);
+ for (unsigned I = 0; I < NumElems; I++) {
+ BindingDecl *B = Walker.get();
InitializingBinding InitContext(S, B);
SourceLocation Loc = B->getLocation();
@@ -1336,8 +1445,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
if (E.isInvalid())
return true;
- B->setBinding(T, E.get());
- I++;
+ Walker.commitAndAdvance(T, E.get());
}
return false;
@@ -1433,20 +1541,18 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
QualType BaseType = S.Context.getQualifiedType(S.Context.getRecordType(RD),
DecompType.getQualifiers());
- auto DiagnoseBadNumberOfBindings = [&]() -> bool {
- unsigned NumFields = llvm::count_if(
- RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitField(); });
- assert(Bindings.size() != NumFields);
- S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
- << DecompType << (unsigned)Bindings.size() << NumFields << NumFields
- << (NumFields < Bindings.size());
+ unsigned NumFields = llvm::count_if(
+ RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitField(); });
+ if (CheckBindingsCount(S, cast<DecompositionDecl>(Src), DecompType, Bindings,
+ NumFields)) {
return true;
- };
+ }
+
+ auto Walker = BindingInitWalker(S, Bindings);
// all of E's non-static data members shall be [...] well-formed
// when named as e.name in the context of the structured binding,
// E shall not have an anonymous union member, ...
- unsigned I = 0;
for (auto *FD : RD->fields()) {
if (FD->isUnnamedBitField())
continue;
@@ -1471,9 +1577,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
}
// We have a real field to bind.
- if (I >= Bindings.size())
- return DiagnoseBadNumberOfBindings();
- auto *B = Bindings[I++];
+ BindingDecl *B = Walker.get();
SourceLocation Loc = B->getLocation();
// The field must be accessible in the context of the structured binding.
@@ -1508,23 +1612,52 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
Qualifiers Q = DecompType.getQualifiers();
if (FD->isMutable())
Q.removeConst();
- B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get());
+ Walker.commitAndAdvance(S.BuildQualifiedType(FD->getType(), Loc, Q),
+ E.get());
}
- if (I != Bindings.size())
- return DiagnoseBadNumberOfBindings();
-
return false;
}
+unsigned Sema::GetDecompositionElementCount(QualType DecompType) {
+ assert(!DecompType->isDependentType() && "expecting non-dependent type");
+ SourceLocation Loc = SourceLocation(); // FIXME
+ DecompType = DecompType.getNonReferenceType();
+ if (auto *CAT = Context.getAsConstantArrayType(DecompType))
+ return CAT->getSize().getLimitedValue(UINT_MAX);
+ if (auto *VT = DecompType->getAs<VectorType>())
+ return VT->getNumElements();
+ if (auto *CT = DecompType->getAs<ComplexType>())
+ return 2;
+ llvm::APSInt TupleSize(32);
+ if (IsTupleLike TL = isTupleLike(*this, Loc, DecompType, TupleSize);
+ TL == IsTupleLike::TupleLike)
+ return (unsigned)TupleSize.getLimitedValue(UINT_MAX);
+
+ if (CXXRecordDecl *RD = DecompType->getAsCXXRecordDecl();
+ RD && !RD->isUnion()) {
+ CXXCastPath BasePath;
+ DeclAccessPair BasePair =
+ findDecomposableBaseClass(*this, Loc, RD, BasePath);
+ RD = cast_or_null<CXXRecordDecl>(BasePair.getDecl());
+ if (RD)
+ return llvm::count_if(
+ RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitField(); });
+ }
+
+ llvm_unreachable("unknown type for decomposition");
+}
+
void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) {
QualType DecompType = DD->getType();
// If the type of the decomposition is dependent, then so is the type of
// each binding.
if (DecompType->isDependentType()) {
- for (auto *B : DD->bindings())
- B->setType(Context.DependentTy);
+ for (auto *B : DD->bindings()) {
+ if (B->getType().isNull())
+ B->setType(Context.DependentTy);
+ }
return;
}
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index ac3666394d0e86..079ba597ed0cf1 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1068,9 +1068,9 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
// If this is a decomposition declaration, bindings might throw.
if (auto *DD = dyn_cast<DecompositionDecl>(VD))
- for (auto *B : DD->bindings())
- if (auto *HD = B->getHoldingVar())
- CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD));
+ DD->VisitHoldingVars([&](VarDecl *HD) {
+ CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD));
+ });
return CT;
}
@@ -1278,6 +1278,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::ConvertVectorExprClass:
case Expr::VAArgExprClass:
case Expr::CXXParenListInitExprClass:
+ case Expr::ResolvedUnexpandedPackExprClass:
return canSubStmtsThrow(*this, S);
case Expr::CompoundLiteralExprClass:
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index a67c0b2b367d1a..e008a26ff7f062 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1526,6 +1526,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// - a member of a templated entity,
// - an enumerator for an enumeration that is a templated entity, or
// - the closure type of a lambda-expression ([expr.prim.lambda.closure])
+ // - an entity defined with an implicit template region
// appearing in the declaration of a templated entity. [Note 6: A local
// class, a local or block variable, or a friend function defined in a
// templated entity is a templated entity. — end note]
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index d9149f7ee40bbf..2d7ba56657a0c2 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -755,7 +755,7 @@ bool Sema::checkMustTailAttr(const Stmt *St, const Attr &MTA) {
return true;
};
- const auto *CallerDecl = dyn_cast<FunctionDecl>(CurContext);
+ const auto *CallerDecl = getCurFunctionDecl();
// Find caller function signature.
if (!CallerDecl) {
@@ -1010,8 +1010,7 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc,
bool Immediate = ExprEvalContexts.back().Context ==
ExpressionEvaluationContext::ImmediateFunctionContext;
if (CurContext->isFunctionOrMethod()) {
- const auto *FD =
- dyn_cast<FunctionDecl>(Decl::castFromDeclContext(CurContext));
+ const auto *FD = getCurFunctionDecl();
if (FD && FD->isImmediateFunction())
Immediate = true;
}
@@ -2670,8 +2669,11 @@ StmtResult Sema::BuildCXXForRangeStmt(
// them in properly when we instantiate the loop.
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
- for (auto *Binding : DD->bindings())
- Binding->setType(Context.DependentTy);
+ for (auto *Binding : DD->bindings()) {
+ if (!Binding->isParameterPack()) {
+ Binding->setType(Context.DependentTy);
+ }
+ }
LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType()));
}
} else if (!BeginDeclStmt.get()) {
@@ -3916,7 +3918,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
// deduction.
if (getLangOpts().CPlusPlus14) {
if (AutoType *AT = FnRetType->getContainedAutoType()) {
- FunctionDecl *FD = cast<FunctionDecl>(CurContext);
+ FunctionDecl *FD = getCurFunctionDecl();
// If we've already decided this function is invalid, e.g. because
// we saw a `return` whose expression had an error, don't keep
// trying to deduce its return type.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 5e7a3c8484c88f..ef19d0d52213b2 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -928,9 +928,10 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn,
TemplateArgumentListInfo &TemplateArgs) {
- for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I)
- TemplateArgs.addArgument(translateTemplateArgument(*this,
- TemplateArgsIn[I]));
+ for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I) {
+ TemplateArgs.addArgument(
+ translateTemplateArgument(*this, TemplateArgsIn[I]));
+ }
}
static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S,
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index fb0f38df62a744..ca11a1b7c910fa 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -805,7 +805,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SemaRef, CodeSynthesisContext::BuildingDeductionGuides,
PointOfInstantiation, InstantiationRange, Entity) {}
-
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
@@ -1569,6 +1568,10 @@ namespace {
/// pack.
ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
+ // Transform a ResolvedUnexpandedPackExpr
+ ExprResult
+ TransformResolvedUnexpandedPackExpr(ResolvedUnexpandedPackExpr *E);
+
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL) {
// Call the base version; it will forward to our overridden version below.
@@ -1851,7 +1854,8 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) {
if (T.isNull())
return true;
- if (T->isInstantiationDependentType() || T->isVariablyModifiedType())
+ if (T->isInstantiationDependentType() || T->isVariablyModifiedType() ||
+ T->containsUnexpandedParameterPack())
return false;
getSema().MarkDeclarationsReferencedInType(Loc, T);
@@ -2484,6 +2488,14 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
if (PD->isParameterPack())
return TransformFunctionParmPackRefExpr(E, PD);
+ if (BindingDecl *BD = dyn_cast<BindingDecl>(D); BD && BD->isParameterPack()) {
+ BD = cast<BindingDecl>(TransformDecl(BD->getLocation(), BD));
+ if (auto *RP =
+ dyn_cast_or_null<ResolvedUnexpandedPackExpr>(BD->getBinding())) {
+ return TransformResolvedUnexpandedPackExpr(RP);
+ }
+ }
+
return inherited::TransformDeclRefExpr(E);
}
@@ -2648,6 +2660,30 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return Result;
}
+ExprResult TemplateInstantiator::TransformResolvedUnexpandedPackExpr(
+ ResolvedUnexpandedPackExpr *E) {
+ if (getSema().ArgumentPackSubstitutionIndex != -1) {
+ assert(static_cast<unsigned>(getSema().ArgumentPackSubstitutionIndex) <
+ E->getNumExprs() &&
+ "ArgumentPackSubstitutionIndex is out of range");
+ return TransformExpr(
+ E->getExpansion(getSema().ArgumentPackSubstitutionIndex));
+ }
+
+ if (!AlwaysRebuild())
+ return E;
+
+ SmallVector<Expr *, 12> NewExprs;
+ if (TransformExprs(E->getExprs(), E->getNumExprs(),
+ /*IsCall=*/false, NewExprs))
+ return ExprError();
+
+ // NOTE: The type is just a superficial PackExpansionType
+ // that needs no substitution.
+ return ResolvedUnexpandedPackExpr::Create(SemaRef.Context, E->getBeginLoc(),
+ E->getType(), NewExprs);
+}
+
QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL,
bool SuppressObjCLifetime) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e058afe81da589..68d090c3a558ad 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1166,17 +1166,24 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) {
auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getIdentifier());
+ D->getIdentifier(), D->getType());
NewBD->setReferenced(D->isReferenced());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD);
+
return NewBD;
}
Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) {
// Transform the bindings first.
+ // The transformed DD will have all of the concrete BindingDecls.
SmallVector<BindingDecl*, 16> NewBindings;
- for (auto *OldBD : D->bindings())
+ ResolvedUnexpandedPackExpr *OldResolvedPack = nullptr;
+ for (auto *OldBD : D->bindings()) {
+ Expr *BindingExpr = OldBD->getBinding();
+ if (auto *RP = dyn_cast_or_null<ResolvedUnexpandedPackExpr>(BindingExpr))
+ OldResolvedPack = RP;
NewBindings.push_back(cast<BindingDecl>(VisitBindingDecl(OldBD)));
+ }
ArrayRef<BindingDecl*> NewBindingArray = NewBindings;
auto *NewDD = cast_or_null<DecompositionDecl>(
@@ -1186,6 +1193,27 @@ Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) {
for (auto *NewBD : NewBindings)
NewBD->setInvalidDecl();
+ if (OldResolvedPack) {
+ // Mark the holding vars (if any) in the pack as instantiated since
+ // they are created implicitly.
+ auto Bindings = NewDD->bindings();
+ auto BPack = std::find_if(
+ Bindings.begin(), Bindings.end(),
+ [](BindingDecl *D) -> bool { return D->isParameterPack(); });
+ auto *NewResolvedPack =
+ cast<ResolvedUnexpandedPackExpr>((*BPack)->getBinding());
+ Expr **OldExprs = OldResolvedPack->getExprs();
+ Expr **NewExprs = NewResolvedPack->getExprs();
+ for (unsigned I = 0; I < OldResolvedPack->getNumExprs(); I++) {
+ DeclRefExpr *OldDRE = cast<DeclRefExpr>(OldExprs[I]);
+ BindingDecl *OldNestedBD = cast<BindingDecl>(OldDRE->getDecl());
+ DeclRefExpr *NewDRE = cast<DeclRefExpr>(NewExprs[I]);
+ BindingDecl *NewNestedBD = cast<BindingDecl>(NewDRE->getDecl());
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldNestedBD,
+ NewNestedBD);
+ }
+ }
+
return NewDD;
}
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index c8452db6bc9014..c4e6e090705104 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -19,6 +19,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/SaveAndRestore.h"
#include <optional>
@@ -50,16 +51,28 @@ class CollectUnexpandedParameterPacksVisitor
auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr;
if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
return;
- } else if (getDepthAndIndex(ND).first >= DepthLimit)
+ } else if (ND->isTemplateParameterPack() &&
+ getDepthAndIndex(ND).first >= DepthLimit) {
return;
+ } else if (auto *BD = dyn_cast<BindingDecl>(ND)) {
+ Expr *E = BD->getBinding();
+ if (auto *RP = dyn_cast_or_null<ResolvedUnexpandedPackExpr>(E)) {
+ addUnexpanded(RP);
+ return;
+ }
+ }
Unexpanded.push_back({ND, Loc});
}
+
void addUnexpanded(const TemplateTypeParmType *T,
SourceLocation Loc = SourceLocation()) {
if (T->getDepth() < DepthLimit)
Unexpanded.push_back({T, Loc});
}
+ void addUnexpanded(ResolvedUnexpandedPackExpr *E) {
+ Unexpanded.push_back({E, E->getBeginLoc()});
+ }
public:
explicit CollectUnexpandedParameterPacksVisitor(
@@ -103,6 +116,12 @@ class CollectUnexpandedParameterPacksVisitor
return true;
}
+ bool
+ VisitResolvedUnexpandedPackExpr(ResolvedUnexpandedPackExpr *E) override {
+ addUnexpanded(E);
+ return true;
+ }
+
/// Record occurrences of template template parameter packs.
bool TraverseTemplateName(TemplateName Template) override {
if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
@@ -210,6 +229,10 @@ class CollectUnexpandedParameterPacksVisitor
bool TraversePackIndexingTypeLoc(PackIndexingTypeLoc TL) override {
return DynamicRecursiveASTVisitor::TraverseStmt(TL.getIndexExpr());
}
+ bool
+ TraverseResolvedUnexpandedPackExpr(ResolvedUnexpandedPackExpr *E) override {
+ return true;
+ }
///@}
@@ -422,8 +445,8 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
if (const TemplateTypeParmType *TTP
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
Name = TTP->getIdentifier();
- else
- Name = cast<NamedDecl *>(Unexpanded[I].first)->getIdentifier();
+ else if (NamedDecl *ND = Unexpanded[I].first.dyn_cast<NamedDecl *>())
+ Name = ND->getIdentifier();
if (Name && NamesKnown.insert(Name).second)
Names.push_back(Name);
@@ -757,23 +780,42 @@ bool Sema::CheckParameterPacksForExpansion(
bool HaveFirstPack = false;
std::optional<unsigned> NumPartialExpansions;
SourceLocation PartiallySubstitutedPackLoc;
+ typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
for (UnexpandedParameterPack ParmPack : Unexpanded) {
// Compute the depth and index for this parameter pack.
unsigned Depth = 0, Index = 0;
IdentifierInfo *Name;
bool IsVarDeclPack = false;
+ ResolvedUnexpandedPackExpr *ResolvedPack = nullptr;
if (const TemplateTypeParmType *TTP =
ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
Name = TTP->getIdentifier();
+ } else if (auto *RP =
+ ParmPack.first.dyn_cast<ResolvedUnexpandedPackExpr *>()) {
+ ResolvedPack = RP;
} else {
NamedDecl *ND = cast<NamedDecl *>(ParmPack.first);
if (isa<VarDecl>(ND))
IsVarDeclPack = true;
- else
+ else if (isa<BindingDecl>(ND)) {
+ // find the instantiated BindingDecl and check it for a resolved pack
+ llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
+ CurrentInstantiationScope->findInstantiationOf(ND);
+ if (Decl *B = Instantiation->dyn_cast<Decl *>()) {
+ Expr *BindingExpr = cast<BindingDecl>(B)->getBinding();
+ if (auto *RP = dyn_cast<ResolvedUnexpandedPackExpr>(BindingExpr)) {
+ ResolvedPack = RP;
+ }
+ }
+ if (!ResolvedPack) {
+ ShouldExpand = false;
+ continue;
+ }
+ } else
std::tie(Depth, Index) = getDepthAndIndex(ND);
Name = ND->getIdentifier();
@@ -797,6 +839,8 @@ bool Sema::CheckParameterPacksForExpansion(
ShouldExpand = false;
continue;
}
+ } else if (ResolvedPack) {
+ NewPackSize = ResolvedPack->getNumExprs();
} else {
// If we don't have a template argument at this depth/index, then we
// cannot expand the pack expansion. Make a note of this, but we still
@@ -833,7 +877,7 @@ bool Sema::CheckParameterPacksForExpansion(
// Template argument deduction can extend the sequence of template
// arguments corresponding to a template parameter pack, even when the
// sequence contains explicitly specified template arguments.
- if (!IsVarDeclPack && CurrentInstantiationScope) {
+ if (!IsVarDeclPack && !ResolvedPack && CurrentInstantiationScope) {
if (NamedDecl *PartialPack =
CurrentInstantiationScope->getPartiallySubstitutedPack()) {
unsigned PartialDepth, PartialIndex;
@@ -939,6 +983,12 @@ std::optional<unsigned> Sema::getNumArgumentsInExpansionFromUnexpanded(
Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
+ } else if (auto *PE = Unexpanded[I]
+ .first.dyn_cast<ResolvedUnexpandedPackExpr *>()) {
+ unsigned Size = PE->getNumExprs();
+ assert((!Result || *Result == Size) && "inconsistent pack sizes");
+ Result = Size;
+ continue;
} else {
NamedDecl *ND = cast<NamedDecl *>(Unexpanded[I].first);
if (isa<VarDecl>(ND)) {
@@ -1167,8 +1217,13 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
+ std::optional<unsigned> Length;
+ if (auto *RP = ResolvedUnexpandedPackExpr::getFromDecl(ParameterPack)) {
+ Length = RP->getNumExprs();
+ }
+
return SizeOfPackExpr::Create(Context, OpLoc, ParameterPack, NameLoc,
- RParenLoc);
+ RParenLoc, Length);
}
static bool isParameterPack(Expr *PackExpression) {
@@ -1439,8 +1494,10 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
}
}
- return BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,
- std::nullopt);
+ ExprResult Result = BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc,
+ RHS, RParenLoc, std::nullopt);
+
+ return Result;
}
ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5d43d98ce49e46..7af74c6d469a55 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15991,6 +15991,13 @@ TreeTransform<Derived>::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
return E;
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformResolvedUnexpandedPackExpr(
+ ResolvedUnexpandedPackExpr *E) {
+ // Default behavior is to do nothing with this transformation.
+ return E;
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 9e8cf19a6f0f72..f1ed2d81676bf2 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2201,6 +2201,11 @@ void ASTStmtReader::VisitPackIndexingExpr(PackIndexingExpr *E) {
Exprs[I] = Record.readExpr();
}
+void ASTStmtReader::VisitResolvedUnexpandedPackExpr(
+ ResolvedUnexpandedPackExpr *E) {
+ VisitExpr(E);
+}
+
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
@@ -4270,6 +4275,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
/*TransformedExprs=*/Record[ASTStmtReader::NumExprFields]);
break;
+ case EXPR_RESOLVED_UNEXPANDED_PACK:
+ S = ResolvedUnexpandedPackExpr::CreateDeserialized(
+ Context,
+ /*NumExprs=*/Record[ASTStmtReader::NumExprFields]);
+ break;
+
case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM:
S = new (Context) SubstNonTypeTemplateParmExpr(Empty);
break;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 4a6027943072c0..2b531659f1920f 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -874,6 +874,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_PACK_EXPANSION);
RECORD(EXPR_SIZEOF_PACK);
RECORD(EXPR_PACK_INDEXING);
+ RECORD(EXPR_RESOLVED_UNEXPANDED_PACK);
RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM);
RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK);
RECORD(EXPR_FUNCTION_PARM_PACK);
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 1d42b43c3e2ca0..26967160d40b4e 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2202,6 +2202,17 @@ void ASTStmtWriter::VisitPackIndexingExpr(PackIndexingExpr *E) {
Code = serialization::EXPR_PACK_INDEXING;
}
+void ASTStmtWriter::VisitResolvedUnexpandedPackExpr(
+ ResolvedUnexpandedPackExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumExprs());
+ Record.AddSourceLocation(E->getBeginLoc());
+ auto SubExprs = llvm::ArrayRef(E->getExprs(), E->getNumExprs());
+ for (Expr *Sub : SubExprs)
+ Record.AddStmt(Sub);
+ Code = serialization::EXPR_RESOLVED_UNEXPANDED_PACK;
+}
+
void ASTStmtWriter::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index db385e891e762f..312c7870948cd9 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1743,6 +1743,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::DependentCoawaitExprClass:
case Stmt::CoreturnStmtClass:
case Stmt::CoyieldExprClass:
+ case Stmt::ResolvedUnexpandedPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHLeaveStmtClass:
diff --git a/clang/test/Parser/cxx2c-binding-pack.cpp b/clang/test/Parser/cxx2c-binding-pack.cpp
new file mode 100644
index 00000000000000..ab8bdd54935f91
--- /dev/null
+++ b/clang/test/Parser/cxx2c-binding-pack.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++2c -verify -fsyntax-only %s
+
+template <unsigned N>
+void decompose_array() {
+ int arr[4] = {1, 2, 3, 5};
+ auto [x, ...rest, ...more_rest] = arr; // expected-error{{multiple ellipses in structured binding declaration}}
+}
diff --git a/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp b/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
new file mode 100644
index 00000000000000..9c02083cf88f7e
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++2c %s -verify
+
+void decompose_array() {
+ int arr[4] = {1, 2, 3, 6};
+ auto [x, ...rest, y] = arr; // expected-error{{pack declaration outside of template}}
+}
+
+template <unsigned N>
+void decompose_array_2() {
+ int arr[4] = {1, 2, 3, N};
+ auto [x, ...rest, ...y] = arr; // expected-error{{multiple ellipses in structured binding declaration}}
+}
diff --git a/clang/test/SemaCXX/cxx2c-binding-pack.cpp b/clang/test/SemaCXX/cxx2c-binding-pack.cpp
new file mode 100644
index 00000000000000..ee9466e3b12c70
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-binding-pack.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++2b %s -verify
+// expected-no-diagnostics
+
+template <typename T>
+struct type_ { };
+
+template <typename ...T>
+auto sum(T... t) { return (t + ...); }
+
+struct my_struct {
+ int a;
+ int b;
+ int c;
+ int d;
+};
+
+struct fake_tuple {
+ int arr[4] = {1, 2, 3, 6};
+
+ template <unsigned i>
+ int get() {
+ return arr[i];
+ }
+};
+
+namespace std {
+ template <typename T>
+ struct tuple_size;
+ template <unsigned i, typename T>
+ struct tuple_element;
+
+ template <>
+ struct tuple_size<fake_tuple> {
+ static constexpr unsigned value = 4;
+ };
+
+ template <unsigned i>
+ struct tuple_element<i, fake_tuple> {
+ using type = int;
+ };
+}
+
+
+template <typename T>
+void decompose_tuple() {
+ auto tup = T{{1, 2, 3, 6}};
+ auto&& [x, ...rest, y] = tup;
+
+ ((void)type_<int>(type_<decltype(rest)>{}), ...);
+
+ T arrtup[2] = {T{{1, 2, 3, 6}},
+ T{{7, 9, 10, 11}}};
+ int sum = 0;
+ for (auto [...xs] : arrtup) {
+ sum += (xs + ...);
+ }
+}
+
+template <typename T>
+void decompose_struct() {
+ T obj{1, 2, 3, 6};
+ auto [x, ...rest, y] = obj;
+}
+
+template <typename T>
+void decompose_array() {
+ // previously unable to use non-dependent array here
+ // Fixes https://bugs.llvm.org/show_bug.cgi?id=45964
+ int arr[4] = {1, 2, 3, 6};
+ auto [x, ...rest, y] = arr;
+
+ static_assert(sizeof...(rest) == 2);
+ int size = sizeof...(rest);
+ T arr2[sizeof...(rest)] = {rest...};
+ auto [...pack] = arr2;
+}
+
+int main() {
+ decompose_array<int>();
+ decompose_tuple<fake_tuple>();
+ decompose_struct<my_struct>();
+}
diff --git a/clang/test/SemaCXX/typo-correction-crash.cpp b/clang/test/SemaCXX/typo-correction-crash.cpp
index 2a77c9df505e8f..9ba2d92fa8bd79 100644
--- a/clang/test/SemaCXX/typo-correction-crash.cpp
+++ b/clang/test/SemaCXX/typo-correction-crash.cpp
@@ -32,7 +32,8 @@ FooRecord::NestedNamespace::type x; // expected-error {{no member named 'NestedN
void cast_expr(int g) { +int(n)(g); } // expected-error {{undeclared identifier 'n'}}
-void bind() { for (const auto& [test,_] : _test_) { }; } // expected-error {{undeclared identifier '_test_'}}
+void bind() { for (const auto& [test,_] : _test_) { }; } // expected-error {{undeclared identifier '_test_'}} \
+ // expected-note {{'test' declared here}}
namespace NoCrash {
class S {
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index f56e77b42f9d73..694d86a2ce9aec 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -338,6 +338,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::EmbedExprClass:
case Stmt::HLSLOutArgExprClass:
case Stmt::OpenACCAsteriskSizeExprClass:
+ case Stmt::ResolvedUnexpandedPackExprClass:
K = CXCursor_UnexposedExpr;
break;
>From 116aff1e444b6bfb0d61bcf8ece24303808db0fe Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Thu, 2 Jan 2025 14:13:49 -0800
Subject: [PATCH 02/13] [Clang][P1061] Improve visiting HoldingVars; Improve
parsing diagnostics of binding packs
---
clang/include/clang/AST/DeclCXX.h | 3 +-
clang/include/clang/AST/ExprCXX.h | 2 ++
.../clang/Basic/DiagnosticParseKinds.td | 6 ++--
clang/lib/AST/DeclBase.cpp | 4 +--
clang/lib/AST/DeclCXX.cpp | 35 ++++---------------
clang/lib/AST/Expr.cpp | 6 +---
clang/lib/AST/ExprCXX.cpp | 9 ++---
clang/lib/AST/ExprClassification.cpp | 2 +-
clang/lib/Parse/ParseDecl.cpp | 25 ++++++++-----
clang/lib/Sema/SemaDecl.cpp | 9 -----
clang/lib/Sema/SemaTemplateInstantiate.cpp | 2 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 +--
clang/lib/Sema/SemaTemplateVariadic.cpp | 2 +-
clang/test/Parser/cxx2c-binding-pack.cpp | 6 +++-
.../cxx2c-binding-pack-nontemplate.cpp | 12 +++----
clang/test/SemaCXX/cxx2c-binding-pack.cpp | 4 +--
16 files changed, 51 insertions(+), 80 deletions(-)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 12002db17fb3ad..6ac913e8b85b92 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4166,7 +4166,6 @@ class BindingDecl : public ValueDecl {
void setDecomposedDecl(ValueDecl *Decomposed) { Decomp = Decomposed; }
VarDecl *getHoldingVar() const;
- static VarDecl *getHoldingVar(Expr *E);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decl::Binding; }
@@ -4224,7 +4223,7 @@ class DecompositionDecl final
/// binding. Only present for user-defined bindings for tuple-like types.
void VisitHoldingVars(llvm::function_ref<void(VarDecl *)> F) const;
- // Visit the concrete bindings. (workaround)
+ // Visit the concrete bindings.
void VisitBindings(llvm::function_ref<void(BindingDecl *)> F) const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 6162c712c90dc3..371da5caf41a5c 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -5321,6 +5321,8 @@ class BuiltinBitCastExpr final
}
};
+// Represents an unexpanded pack where the list of expressions are
+// known. These are used when structured bindings introduce a pack.
class ResolvedUnexpandedPackExpr final
: public Expr,
private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Stmt *> {
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 5ee6f9ff28c4c8..3ed90a261f7e4a 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1101,9 +1101,11 @@ def err_lambda_capture_multiple_ellipses : Error<
"multiple ellipses in pack capture">;
def err_binding_multiple_ellipses : Error<
"multiple ellipses in structured binding declaration">;
-def warn_cxx2c_binding_pack : Warning<
+def note_previous_ellipsis : Note<
+ "previous ellipsis specified here">;
+def ext_cxx_binding_pack : ExtWarn<
"structured binding pack is incompatible with C++ standards before C++2c">,
- DefaultIgnore, InGroup<CXXPre26Compat>;
+ InGroup<CXX26>;
def err_capture_default_first : Error<
"capture default must be first">;
def ext_decl_attrs_on_lambda : ExtWarn<
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 6a5662f9d074e4..29bb3c0b6816b3 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -237,12 +237,10 @@ bool Decl::isTemplateParameterPack() const {
}
bool Decl::isParameterPack() const {
- if (isTemplateParameterPack())
- return true;
if (const auto *Var = dyn_cast<ValueDecl>(this))
return Var->isParameterPack();
- return false;
+ return isTemplateParameterPack();
}
FunctionDecl *Decl::getAsFunction() {
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 371bf5dcf02206..4c9a069f15ce32 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3395,7 +3395,7 @@ VarDecl *ValueDecl::getPotentiallyDecomposedVarDecl() {
if (auto *Var = llvm::dyn_cast<VarDecl>(this))
return Var;
if (auto *BD = llvm::dyn_cast<BindingDecl>(this))
- return llvm::dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
+ return llvm::dyn_cast_if_present<VarDecl>(BD->getDecomposedDecl());
return nullptr;
}
@@ -3416,16 +3416,7 @@ VarDecl *BindingDecl::getHoldingVar() const {
Expr *B = getBinding();
if (!B)
return nullptr;
- return getHoldingVar(B);
-}
-
-VarDecl *BindingDecl::getHoldingVar(Expr *E) {
- auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreImplicit());
- if (!DRE)
- return nullptr;
- if (auto *BD = dyn_cast<BindingDecl>(DRE->getDecl())) {
- DRE = dyn_cast<DeclRefExpr>(BD->getBinding());
- }
+ auto *DRE = dyn_cast<DeclRefExpr>(B->IgnoreImplicit());
if (!DRE)
return nullptr;
@@ -3434,27 +3425,13 @@ VarDecl *BindingDecl::getHoldingVar(Expr *E) {
return VD;
}
+
void DecompositionDecl::VisitHoldingVars(
llvm::function_ref<void(VarDecl *)> F) const {
- for (BindingDecl *B : bindings()) {
- Expr *BE = B->getBinding();
- // All BindingDecls will contain holding vars or none will
- if (!BE)
- return;
-
- llvm::ArrayRef<Expr *> Exprs;
- if (auto *RP = dyn_cast<ResolvedUnexpandedPackExpr>(BE))
- Exprs = llvm::ArrayRef(RP->getExprs(), RP->getNumExprs());
- else
- Exprs = BE;
-
- for (Expr *E : Exprs) {
- VarDecl *VD = BindingDecl::getHoldingVar(E);
- if (!VD)
- return;
+ VisitBindings([&](BindingDecl* BD) {
+ if (VarDecl* VD = BD->getHoldingVar())
F(VD);
- }
- }
+ });
}
void DecompositionDecl::VisitBindings(
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 39f02ebf85b2ce..26a227814388ff 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3653,12 +3653,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case PackIndexingExprClass:
case HLSLOutArgExprClass:
case OpenACCAsteriskSizeExprClass:
- // These never have a side-effect.
- return false;
-
- // ResolvedUnexpandedPackExpr is currently only used for
- // structed bindings which have no side effects
case ResolvedUnexpandedPackExprClass:
+ // These never have a side-effect.
return false;
case ConstantExprClass:
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 190af789d306ed..7c710b703f38c1 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1971,6 +1971,9 @@ ResolvedUnexpandedPackExpr::ResolvedUnexpandedPackExpr(SourceLocation BL,
unsigned NumExprs)
: Expr(ResolvedUnexpandedPackExprClass, QT, VK_PRValue, OK_Ordinary),
BeginLoc(BL), NumExprs(NumExprs) {
+ // C++ [temp.dep.expr]p3
+ // An id-expression is type-dependent if it is
+ // - associated by name lookup with a pack
setDependence(ExprDependence::TypeValueInstantiation |
ExprDependence::UnexpandedPack);
}
@@ -2007,9 +2010,7 @@ ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL,
}
ResolvedUnexpandedPackExpr *ResolvedUnexpandedPackExpr::getFromDecl(Decl *D) {
- // TODO P1858: Extend to VarDecls for P1858
- if (auto *BD = dyn_cast<BindingDecl>(D)) {
- return dyn_cast_or_null<ResolvedUnexpandedPackExpr>(BD->getBinding());
- }
+ if (auto *BD = dyn_cast<BindingDecl>(D))
+ return dyn_cast_if_present<ResolvedUnexpandedPackExpr>(BD->getBinding());
return nullptr;
}
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index 29a869bd76ca37..5225c3ca773ad4 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -455,7 +455,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
if (cast<ResolvedUnexpandedPackExpr>(E)->getNumExprs() > 0)
return ClassifyInternal(
Ctx, cast<ResolvedUnexpandedPackExpr>(E)->getExpansion(0));
- return Cl::CL_PRValue;
+ return Cl::CL_LValue;
}
case Expr::MaterializeTemporaryExprClass:
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index c298825fb88280..3e480415996996 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7310,14 +7310,14 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
// array declarator.
if (!(Tok.isOneOf(tok::identifier, tok::ellipsis) &&
NextToken().isOneOf(tok::comma, tok::r_square, tok::kw_alignas,
- tok::identifier, tok::l_square)) &&
+ tok::identifier, tok::l_square, tok::ellipsis)) &&
!(Tok.is(tok::r_square) &&
NextToken().isOneOf(tok::equal, tok::l_brace))) {
PA.Revert();
return ParseMisplacedBracketDeclarator(D);
}
- bool HasEllipsis = false;
+ SourceLocation PrevEllipsisLoc;
SmallVector<DecompositionDeclarator::Binding, 32> Bindings;
while (Tok.isNot(tok::r_square)) {
if (!Bindings.empty()) {
@@ -7332,9 +7332,8 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
Diag(Tok, diag::err_expected_comma_or_rsquare);
}
- // I don't know why this skipping was here
- // SkipUntil(tok::r_square, tok::comma, tok::identifier,
- // StopAtSemi | StopBeforeMatch);
+ SkipUntil({tok::r_square, tok::comma, tok::identifier, tok::ellipsis},
+ StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::comma))
ConsumeToken();
else if (Tok.is(tok::r_square))
@@ -7345,17 +7344,18 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
if (isCXX11AttributeSpecifier())
DiagnoseAndSkipCXX11Attributes();
- SourceLocation EllipsisLoc = {};
+ SourceLocation EllipsisLoc;
if (Tok.is(tok::ellipsis)) {
if (!getLangOpts().CPlusPlus26)
- Diag(Tok, diag::warn_cxx2c_binding_pack);
- if (HasEllipsis) {
+ Diag(Tok, diag::ext_cxx_binding_pack);
+ if (PrevEllipsisLoc.isValid()) {
Diag(Tok, diag::err_binding_multiple_ellipses);
+ Diag(PrevEllipsisLoc, diag::note_previous_ellipsis);
break;
}
- HasEllipsis = true;
EllipsisLoc = Tok.getLocation();
+ PrevEllipsisLoc = EllipsisLoc;
ConsumeToken();
}
@@ -7368,6 +7368,13 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
SourceLocation Loc = Tok.getLocation();
ConsumeToken();
+ if (Tok.is(tok::ellipsis) && !PrevEllipsisLoc.isValid()) {
+ DiagnoseMisplacedEllipsis(Tok.getLocation(), Loc,
+ EllipsisLoc.isValid(), true);
+ EllipsisLoc = Tok.getLocation();
+ ConsumeToken();
+ }
+
ParsedAttributes Attrs(AttrFactory);
if (isCXX11AttributeSpecifier()) {
Diag(Tok, getLangOpts().CPlusPlus26
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index ddb677dc1e70f2..4ba78818f19836 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9780,7 +9780,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R = TInfo->getType();
assert(R->isFunctionType());
- bool NeedsExpansion = false;
if (R.getCanonicalType()->castAs<FunctionType>()->getCmseNSCallAttr())
Diag(D.getIdentifierLoc(), diag::err_function_decl_cmse_ns_call);
@@ -10966,14 +10965,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration)
ExternalDeclarations.push_back(NewFD);
- if (NeedsExpansion) {
- CodeSynthesisContext SynthCtx{};
- pushCodeSynthesisContext(SynthCtx);
- NewFD = dyn_cast_or_null<FunctionDecl>(
- SubstDecl(NewFD, DC, MultiLevelTemplateArgumentList{}));
- popCodeSynthesisContext();
- }
-
return NewFD;
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index ca11a1b7c910fa..f94c22185d399b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2491,7 +2491,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
if (BindingDecl *BD = dyn_cast<BindingDecl>(D); BD && BD->isParameterPack()) {
BD = cast<BindingDecl>(TransformDecl(BD->getLocation(), BD));
if (auto *RP =
- dyn_cast_or_null<ResolvedUnexpandedPackExpr>(BD->getBinding())) {
+ dyn_cast_if_present<ResolvedUnexpandedPackExpr>(BD->getBinding())) {
return TransformResolvedUnexpandedPackExpr(RP);
}
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 68d090c3a558ad..4ae29854a58725 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1180,13 +1180,13 @@ Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) {
ResolvedUnexpandedPackExpr *OldResolvedPack = nullptr;
for (auto *OldBD : D->bindings()) {
Expr *BindingExpr = OldBD->getBinding();
- if (auto *RP = dyn_cast_or_null<ResolvedUnexpandedPackExpr>(BindingExpr))
+ if (auto *RP = dyn_cast_if_present<ResolvedUnexpandedPackExpr>(BindingExpr))
OldResolvedPack = RP;
NewBindings.push_back(cast<BindingDecl>(VisitBindingDecl(OldBD)));
}
ArrayRef<BindingDecl*> NewBindingArray = NewBindings;
- auto *NewDD = cast_or_null<DecompositionDecl>(
+ auto *NewDD = cast_if_present<DecompositionDecl>(
VisitVarDecl(D, /*InstantiatingVarTemplate=*/false, &NewBindingArray));
if (!NewDD || NewDD->isInvalidDecl())
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index c4e6e090705104..94cdc99217d306 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -56,7 +56,7 @@ class CollectUnexpandedParameterPacksVisitor
return;
} else if (auto *BD = dyn_cast<BindingDecl>(ND)) {
Expr *E = BD->getBinding();
- if (auto *RP = dyn_cast_or_null<ResolvedUnexpandedPackExpr>(E)) {
+ if (auto *RP = dyn_cast_if_present<ResolvedUnexpandedPackExpr>(E)) {
addUnexpanded(RP);
return;
}
diff --git a/clang/test/Parser/cxx2c-binding-pack.cpp b/clang/test/Parser/cxx2c-binding-pack.cpp
index ab8bdd54935f91..400630b6b7d7df 100644
--- a/clang/test/Parser/cxx2c-binding-pack.cpp
+++ b/clang/test/Parser/cxx2c-binding-pack.cpp
@@ -3,5 +3,9 @@
template <unsigned N>
void decompose_array() {
int arr[4] = {1, 2, 3, 5};
- auto [x, ...rest, ...more_rest] = arr; // expected-error{{multiple ellipses in structured binding declaration}}
+ auto [x, ... // #1
+ rest, ...more_rest] = arr; // expected-error{{multiple ellipses in structured binding declaration}}
+ // expected-note@#1{{previous ellipsis specified here}}
+ //
+ auto [y...] = arr; // expected-error{{'...' must immediately precede declared identifier}}
}
diff --git a/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp b/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
index 9c02083cf88f7e..3ce405937861b9 100644
--- a/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
+++ b/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
@@ -1,12 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++2c %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++26 %s -verify=nontemplate
+// RUN: %clang_cc1 -fsyntax-only %s -verify=nontemplate,compat
void decompose_array() {
int arr[4] = {1, 2, 3, 6};
- auto [x, ...rest, y] = arr; // expected-error{{pack declaration outside of template}}
-}
-
-template <unsigned N>
-void decompose_array_2() {
- int arr[4] = {1, 2, 3, N};
- auto [x, ...rest, ...y] = arr; // expected-error{{multiple ellipses in structured binding declaration}}
+ auto [x, ...rest, y] = arr; // nontemplate-error{{pack declaration outside of template}} \
+ // compat-warning{{structured binding pack is incompatible with C++ standards before C++2c}}
}
diff --git a/clang/test/SemaCXX/cxx2c-binding-pack.cpp b/clang/test/SemaCXX/cxx2c-binding-pack.cpp
index ee9466e3b12c70..7e06d63543841a 100644
--- a/clang/test/SemaCXX/cxx2c-binding-pack.cpp
+++ b/clang/test/SemaCXX/cxx2c-binding-pack.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++2b %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++26 %s -verify
// expected-no-diagnostics
template <typename T>
@@ -64,8 +64,6 @@ void decompose_struct() {
template <typename T>
void decompose_array() {
- // previously unable to use non-dependent array here
- // Fixes https://bugs.llvm.org/show_bug.cgi?id=45964
int arr[4] = {1, 2, 3, 6};
auto [x, ...rest, y] = arr;
>From 66ff7c679f1e48cd80e02bf23be51bcb84e65b98 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Thu, 2 Jan 2025 15:22:42 -0800
Subject: [PATCH 03/13] [Clang][P1061] Remove unrelated code changes; Address
style issues
---
clang/lib/AST/DeclCXX.cpp | 5 ++--
clang/lib/Parse/ParseDecl.cpp | 4 +--
clang/lib/Sema/SemaDeclCXX.cpp | 39 ++++---------------------
clang/lib/Sema/SemaLambda.cpp | 1 -
clang/lib/Sema/SemaStmt.cpp | 7 +++--
clang/lib/Sema/SemaTemplate.cpp | 3 +-
clang/lib/Sema/SemaTemplateVariadic.cpp | 14 ++++-----
7 files changed, 19 insertions(+), 54 deletions(-)
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 4c9a069f15ce32..d5a986bfd588cd 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3425,11 +3425,10 @@ VarDecl *BindingDecl::getHoldingVar() const {
return VD;
}
-
void DecompositionDecl::VisitHoldingVars(
llvm::function_ref<void(VarDecl *)> F) const {
- VisitBindings([&](BindingDecl* BD) {
- if (VarDecl* VD = BD->getHoldingVar())
+ VisitBindings([&](BindingDecl *BD) {
+ if (VarDecl *VD = BD->getHoldingVar())
F(VD);
});
}
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 3e480415996996..234da2ed13bd11 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7369,8 +7369,8 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
ConsumeToken();
if (Tok.is(tok::ellipsis) && !PrevEllipsisLoc.isValid()) {
- DiagnoseMisplacedEllipsis(Tok.getLocation(), Loc,
- EllipsisLoc.isValid(), true);
+ DiagnoseMisplacedEllipsis(Tok.getLocation(), Loc, EllipsisLoc.isValid(),
+ true);
EllipsisLoc = Tok.getLocation();
ConsumeToken();
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index adabca19107f2b..2f657bdd2eada1 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -959,14 +959,15 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
return New;
}
-namespace {
// CheckBindingsCount
// - Checks the arity of the structured bindings
// - Creates the resolved pack expr if there is
// one
-bool CheckBindingsCount(Sema &S, DecompositionDecl *DD, QualType DecompType,
- ArrayRef<BindingDecl *> Bindings,
- unsigned MemberCount) {
+
+static bool CheckBindingsCount(Sema &S, DecompositionDecl *DD,
+ QualType DecompType,
+ ArrayRef<BindingDecl *> Bindings,
+ unsigned MemberCount) {
auto BindingWithPackItr =
std::find_if(Bindings.begin(), Bindings.end(),
[](BindingDecl *D) -> bool { return D->isParameterPack(); });
@@ -1058,7 +1059,6 @@ struct BindingInitWalker {
++BindingItr;
}
};
-} // namespace
static bool checkSimpleDecomposition(
Sema &S, ArrayRef<BindingDecl *> Bindings, ValueDecl *Src,
@@ -1619,35 +1619,6 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
return false;
}
-unsigned Sema::GetDecompositionElementCount(QualType DecompType) {
- assert(!DecompType->isDependentType() && "expecting non-dependent type");
- SourceLocation Loc = SourceLocation(); // FIXME
- DecompType = DecompType.getNonReferenceType();
- if (auto *CAT = Context.getAsConstantArrayType(DecompType))
- return CAT->getSize().getLimitedValue(UINT_MAX);
- if (auto *VT = DecompType->getAs<VectorType>())
- return VT->getNumElements();
- if (auto *CT = DecompType->getAs<ComplexType>())
- return 2;
- llvm::APSInt TupleSize(32);
- if (IsTupleLike TL = isTupleLike(*this, Loc, DecompType, TupleSize);
- TL == IsTupleLike::TupleLike)
- return (unsigned)TupleSize.getLimitedValue(UINT_MAX);
-
- if (CXXRecordDecl *RD = DecompType->getAsCXXRecordDecl();
- RD && !RD->isUnion()) {
- CXXCastPath BasePath;
- DeclAccessPair BasePair =
- findDecomposableBaseClass(*this, Loc, RD, BasePath);
- RD = cast_or_null<CXXRecordDecl>(BasePair.getDecl());
- if (RD)
- return llvm::count_if(
- RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitField(); });
- }
-
- llvm_unreachable("unknown type for decomposition");
-}
-
void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) {
QualType DecompType = DD->getType();
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index e008a26ff7f062..a67c0b2b367d1a 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1526,7 +1526,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// - a member of a templated entity,
// - an enumerator for an enumeration that is a templated entity, or
// - the closure type of a lambda-expression ([expr.prim.lambda.closure])
- // - an entity defined with an implicit template region
// appearing in the declaration of a templated entity. [Note 6: A local
// class, a local or block variable, or a friend function defined in a
// templated entity is a templated entity. — end note]
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 2d7ba56657a0c2..250035e2e5df1e 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -755,7 +755,7 @@ bool Sema::checkMustTailAttr(const Stmt *St, const Attr &MTA) {
return true;
};
- const auto *CallerDecl = getCurFunctionDecl();
+ const auto *CallerDecl = dyn_cast<FunctionDecl>(CurContext);
// Find caller function signature.
if (!CallerDecl) {
@@ -1010,7 +1010,8 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc,
bool Immediate = ExprEvalContexts.back().Context ==
ExpressionEvaluationContext::ImmediateFunctionContext;
if (CurContext->isFunctionOrMethod()) {
- const auto *FD = getCurFunctionDecl();
+ const auto *FD =
+ dyn_cast<FunctionDecl>(Decl::castFromDeclContext(CurContext));
if (FD && FD->isImmediateFunction())
Immediate = true;
}
@@ -3918,7 +3919,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
// deduction.
if (getLangOpts().CPlusPlus14) {
if (AutoType *AT = FnRetType->getContainedAutoType()) {
- FunctionDecl *FD = getCurFunctionDecl();
+ FunctionDecl *FD = cast<FunctionDecl>(CurContext);
// If we've already decided this function is invalid, e.g. because
// we saw a `return` whose expression had an error, don't keep
// trying to deduce its return type.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ef19d0d52213b2..f4dbb296ac7ded 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -928,10 +928,9 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn,
TemplateArgumentListInfo &TemplateArgs) {
- for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I) {
+ for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I)
TemplateArgs.addArgument(
translateTemplateArgument(*this, TemplateArgsIn[I]));
- }
}
static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S,
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 94cdc99217d306..945ff8900ce9dc 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -19,7 +19,6 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
-#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/SaveAndRestore.h"
#include <optional>
@@ -70,6 +69,7 @@ class CollectUnexpandedParameterPacksVisitor
if (T->getDepth() < DepthLimit)
Unexpanded.push_back({T, Loc});
}
+
void addUnexpanded(ResolvedUnexpandedPackExpr *E) {
Unexpanded.push_back({E, E->getBeginLoc()});
}
@@ -807,9 +807,8 @@ bool Sema::CheckParameterPacksForExpansion(
CurrentInstantiationScope->findInstantiationOf(ND);
if (Decl *B = Instantiation->dyn_cast<Decl *>()) {
Expr *BindingExpr = cast<BindingDecl>(B)->getBinding();
- if (auto *RP = dyn_cast<ResolvedUnexpandedPackExpr>(BindingExpr)) {
+ if (auto *RP = dyn_cast<ResolvedUnexpandedPackExpr>(BindingExpr))
ResolvedPack = RP;
- }
}
if (!ResolvedPack) {
ShouldExpand = false;
@@ -1218,9 +1217,8 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
std::optional<unsigned> Length;
- if (auto *RP = ResolvedUnexpandedPackExpr::getFromDecl(ParameterPack)) {
+ if (auto *RP = ResolvedUnexpandedPackExpr::getFromDecl(ParameterPack))
Length = RP->getNumExprs();
- }
return SizeOfPackExpr::Create(Context, OpLoc, ParameterPack, NameLoc,
RParenLoc, Length);
@@ -1494,10 +1492,8 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
}
}
- ExprResult Result = BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc,
- RHS, RParenLoc, std::nullopt);
-
- return Result;
+ return BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,
+ std::nullopt);
}
ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,
>From 5720bd3a86f9ed240f110ace4d8b040dad509324 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Fri, 3 Jan 2025 11:13:38 -0800
Subject: [PATCH 04/13] [Clang][P1061] Remove vestigial changes
---
clang/lib/Sema/SemaDecl.cpp | 1 -
clang/lib/Sema/SemaTemplateInstantiate.cpp | 1 +
clang/lib/Sema/SemaTemplateVariadic.cpp | 9 ++-------
3 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4ba78818f19836..4001c4d263f1d2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9780,7 +9780,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R = TInfo->getType();
assert(R->isFunctionType());
-
if (R.getCanonicalType()->castAs<FunctionType>()->getCmseNSCallAttr())
Diag(D.getIdentifierLoc(), diag::err_function_decl_cmse_ns_call);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index f94c22185d399b..84fd945813fa25 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -805,6 +805,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SemaRef, CodeSynthesisContext::BuildingDeductionGuides,
PointOfInstantiation, InstantiationRange, Entity) {}
+
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 945ff8900ce9dc..6936577160f30c 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -50,15 +50,14 @@ class CollectUnexpandedParameterPacksVisitor
auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr;
if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
return;
- } else if (ND->isTemplateParameterPack() &&
- getDepthAndIndex(ND).first >= DepthLimit) {
- return;
} else if (auto *BD = dyn_cast<BindingDecl>(ND)) {
Expr *E = BD->getBinding();
if (auto *RP = dyn_cast_if_present<ResolvedUnexpandedPackExpr>(E)) {
addUnexpanded(RP);
return;
}
+ } else if (getDepthAndIndex(ND).first >= DepthLimit) {
+ return;
}
Unexpanded.push_back({ND, Loc});
@@ -229,10 +228,6 @@ class CollectUnexpandedParameterPacksVisitor
bool TraversePackIndexingTypeLoc(PackIndexingTypeLoc TL) override {
return DynamicRecursiveASTVisitor::TraverseStmt(TL.getIndexExpr());
}
- bool
- TraverseResolvedUnexpandedPackExpr(ResolvedUnexpandedPackExpr *E) override {
- return true;
- }
///@}
>From ffefb6774e13540eb658cc4351d2cb32ff24db0c Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Fri, 3 Jan 2025 14:39:10 -0800
Subject: [PATCH 05/13] [Clang][P1061] Simplify unwrapping ResolvedPacks; other
style fixes
---
clang/lib/Sema/SemaTemplate.cpp | 6 +++---
clang/lib/Sema/SemaTemplateVariadic.cpp | 10 ++++------
2 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f4dbb296ac7ded..5e7a3c8484c88f 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -928,9 +928,9 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn,
TemplateArgumentListInfo &TemplateArgs) {
- for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I)
- TemplateArgs.addArgument(
- translateTemplateArgument(*this, TemplateArgsIn[I]));
+ for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I)
+ TemplateArgs.addArgument(translateTemplateArgument(*this,
+ TemplateArgsIn[I]));
}
static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S,
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 6936577160f30c..656e94ab774df2 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -797,14 +797,12 @@ bool Sema::CheckParameterPacksForExpansion(
if (isa<VarDecl>(ND))
IsVarDeclPack = true;
else if (isa<BindingDecl>(ND)) {
- // find the instantiated BindingDecl and check it for a resolved pack
+ // Find the instantiated BindingDecl and check it for a resolved pack.
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
CurrentInstantiationScope->findInstantiationOf(ND);
- if (Decl *B = Instantiation->dyn_cast<Decl *>()) {
- Expr *BindingExpr = cast<BindingDecl>(B)->getBinding();
- if (auto *RP = dyn_cast<ResolvedUnexpandedPackExpr>(BindingExpr))
- ResolvedPack = RP;
- }
+ Decl *B = cast<Decl *>(*Instantiation);
+ Expr *BindingExpr = cast<BindingDecl>(B)->getBinding();
+ ResolvedPack = dyn_cast<ResolvedUnexpandedPackExpr>(BindingExpr);
if (!ResolvedPack) {
ShouldExpand = false;
continue;
>From 685f947f64bcc1d0da4094c74a9ec868c9eb43e0 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Fri, 3 Jan 2025 20:22:58 -0800
Subject: [PATCH 06/13] [Clang][P1061] Add ASTReader implementation
---
clang/include/clang/AST/ExprCXX.h | 2 +
clang/lib/Serialization/ASTReaderStmt.cpp | 5 ++
clang/test/AST/ast-dump-binding-pack.cpp | 58 +++++++++++++++++++++++
3 files changed, 65 insertions(+)
create mode 100644 clang/test/AST/ast-dump-binding-pack.cpp
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 371da5caf41a5c..980f12bbf7e009 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -5326,6 +5326,8 @@ class BuiltinBitCastExpr final
class ResolvedUnexpandedPackExpr final
: public Expr,
private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Stmt *> {
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
friend TrailingObjects;
SourceLocation BeginLoc;
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index f1ed2d81676bf2..9cf663cc41dded 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2204,6 +2204,11 @@ void ASTStmtReader::VisitPackIndexingExpr(PackIndexingExpr *E) {
void ASTStmtReader::VisitResolvedUnexpandedPackExpr(
ResolvedUnexpandedPackExpr *E) {
VisitExpr(E);
+ E->NumExprs = Record.readInt();
+ E->BeginLoc = readSourceLocation();
+ auto **Exprs = E->getExprs();
+ for (unsigned I = 0; I < E->NumExprs; ++I)
+ Exprs[I] = Record.readExpr();
}
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
diff --git a/clang/test/AST/ast-dump-binding-pack.cpp b/clang/test/AST/ast-dump-binding-pack.cpp
new file mode 100644
index 00000000000000..fc1eeab895628f
--- /dev/null
+++ b/clang/test/AST/ast-dump-binding-pack.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -ast-dump -std=c++26 %s | FileCheck %s
+
+// Test this with PCH.
+// RUN: %clang_cc1 %s -std=c++26 -emit-pch -o %t %s
+// RUN: %clang_cc1 %s -std=c++26 -include-pch %t -ast-dump-all | FileCheck %s
+
+#ifndef PCH_HELPER
+#define PCH_HELPER
+
+template <unsigned N>
+void foo() {
+ int arr[4] = {1, 2, 3, 4};
+ auto [x, ...rest, y] = arr;
+ int arr_2 = {rest...};
+};
+
+// CHECK-LABEL: FunctionTemplateDecl {{.*}} foo
+// CHECK-NEXT: NonTypeTemplateParmDecl
+// CHECK-NEXT: FunctionDecl {{.*}} foo
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl
+// CHECK-NEXT: InitListExpr
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: DecompositionDecl {{.*}} 'int[4]'
+// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int[4]'
+// CHECK-NEXT: OpaqueValueExpr
+// CHECK-NEXT: DeclRefExpr
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT: ArraySubscriptExpr
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT: OpaqueValueExpr
+// CHECK-NEXT: DeclRefExpr {{.*}} lvalue Var {{.*}} 'arr' 'int[4]'
+// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long'
+// CHECK-NEXT: BindingDecl {{.*}} x 'int'
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int[4]' lvalue Decomposition {{.*}} 'int[4]'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: BindingDecl {{.*}} rest 'type-parameter-0-0...'
+// CHECK-NEXT: ResolvedUnexpandedPackExpr {{.*}} 'int[4]'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue Binding {{.*}} 'rest' 'int'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue Binding {{.*}} 'rest' 'int'
+// CHECK-NEXT: BindingDecl {{.*}} y 'int'
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int[4]' lvalue Decomposition {{.*}} 'int[4]'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} arr_2 'int'
+// CHECK-NEXT: InitListExpr {{.*}} 'void'
+// CHECK-NEXT: PackExpansionExpr {{.*}} '<dependent type>' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'type-parameter-0-0' lvalue Binding {{.*}} 'rest'
+#endif
>From d957783750fee77440ea24b775b3dcf2da25534b Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Sat, 4 Jan 2025 11:38:10 -0800
Subject: [PATCH 07/13] [Clang][P1061] Improve AST dump testing
---
clang/test/AST/ast-dump-binding-pack.cpp | 92 ++++++++++++++----------
1 file changed, 54 insertions(+), 38 deletions(-)
diff --git a/clang/test/AST/ast-dump-binding-pack.cpp b/clang/test/AST/ast-dump-binding-pack.cpp
index fc1eeab895628f..81c75a1268730f 100644
--- a/clang/test/AST/ast-dump-binding-pack.cpp
+++ b/clang/test/AST/ast-dump-binding-pack.cpp
@@ -10,49 +10,65 @@
template <unsigned N>
void foo() {
int arr[4] = {1, 2, 3, 4};
- auto [x, ...rest, y] = arr;
- int arr_2 = {rest...};
+ auto [binding_1, ...binding_rest, binding_4] = arr;
+ int arr_2[] = {binding_rest...};
};
// CHECK-LABEL: FunctionTemplateDecl {{.*}} foo
-// CHECK-NEXT: NonTypeTemplateParmDecl
-// CHECK-NEXT: FunctionDecl {{.*}} foo
-// CHECK-NEXT: CompoundStmt
-// CHECK-NEXT: DeclStmt
-// CHECK-NEXT: VarDecl
-// CHECK-NEXT: InitListExpr
-// CHECK-NEXT: IntegerLiteral
-// CHECK-NEXT: IntegerLiteral
-// CHECK-NEXT: IntegerLiteral
-// CHECK-NEXT: IntegerLiteral
-// CHECK-NEXT: DeclStmt
-// CHECK-NEXT: DecompositionDecl {{.*}} 'int[4]'
-// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int[4]'
-// CHECK-NEXT: OpaqueValueExpr
-// CHECK-NEXT: DeclRefExpr
-// CHECK-NEXT: ImplicitCastExpr
-// CHECK-NEXT: ArraySubscriptExpr
-// CHECK-NEXT: ImplicitCastExpr
-// CHECK-NEXT: OpaqueValueExpr
-// CHECK-NEXT: DeclRefExpr {{.*}} lvalue Var {{.*}} 'arr' 'int[4]'
-// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long'
-// CHECK-NEXT: BindingDecl {{.*}} x 'int'
-// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-LABEL: BindingDecl {{.*}} binding_1
+// CHECK-NEXT: ArraySubscriptExpr {{.*}}
// CHECK-NEXT: ImplicitCastExpr
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int[4]' lvalue Decomposition {{.*}} 'int[4]'
+// CHECK-NEXT: DeclRefExpr {{.*}}
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
-// CHECK-NEXT: BindingDecl {{.*}} rest 'type-parameter-0-0...'
-// CHECK-NEXT: ResolvedUnexpandedPackExpr {{.*}} 'int[4]'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue Binding {{.*}} 'rest' 'int'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue Binding {{.*}} 'rest' 'int'
-// CHECK-NEXT: BindingDecl {{.*}} y 'int'
-// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int[4]' lvalue Decomposition {{.*}} 'int[4]'
+// CHECK-NOT: BindingDecl
+// CHECK-LABEL: BindingDecl {{.*}} binding_rest
+// CHECK-NEXT: ResolvedUnexpandedPackExpr
+// CHECK-NEXT: DeclRefExpr {{.*}} lvalue Binding {{.*}} 'binding_rest'
+// CHECK-NEXT: DeclRefExpr {{.*}} lvalue Binding {{.*}} 'binding_rest'
+// CHECK-NOT: BindingDecl
+// CHECK-LABEL: BindingDecl {{.*}} binding_4
+// CHECK-NEXT: ArraySubscriptExpr
+// CHECK-NEXT: ImplicitCastExpr {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} lvalue Decomposition {{.*}}
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
-// CHECK-NEXT: DeclStmt
-// CHECK-NEXT: VarDecl {{.*}} arr_2 'int'
-// CHECK-NEXT: InitListExpr {{.*}} 'void'
+// CHECK-NOT: BindingDecl
+// CHECK-LABEL: VarDecl {{.*}} arr_2
+// CHECK-NEXT: InitListExpr
// CHECK-NEXT: PackExpansionExpr {{.*}} '<dependent type>' lvalue
-// CHECK-NEXT: DeclRefExpr {{.*}} 'type-parameter-0-0' lvalue Binding {{.*}} 'rest'
+// CHECK-NEXT: DeclRefExpr {{.*}} lvalue Binding {{.*}} 'binding_rest'
+
+struct tag_t { };
+template <unsigned N>
+void bar() {
+ auto [...empty_binding_pack] = tag_t{};
+ static_assert(sizeof...(empty_binding_pack) == 0);
+};
+
+// CHECK-LABEL: FunctionTemplateDecl {{.*}} bar
+// CHECK-NOT: BindingDecl
+// CHECK-LABEL: BindingDecl {{.*}} empty_binding_pack
+// CHECK-NEXT: ResolvedUnexpandedPackExpr
+// CHECK-NOT: DeclRefExpr {{.*}} 'empty_binding_pack'
+// CHECK-NOT: BindingDecl
+// CHECK: DeclStmt
+
+struct int_pair { int x; int y; };
+template <typename T>
+void baz() {
+ auto [binding_1, binding_2, ...empty_binding_pack] = T{};
+ static_assert(sizeof...(empty_binding_pack) == 0);
+};
+
+void(*f)() = baz<int_pair>;
+
+// CHECK-LABEL: FunctionDecl {{.*}} baz {{.*}} implicit_instantiation
+// CHECK-NEXT: TemplateArgument type 'int_pair'
+// CHECK: BindingDecl {{.*}} binding_1
+// CHECK: BindingDecl {{.*}} binding_2
+// CHECK-NOT: BindingDecl
+// CHECK-LABEL: BindingDecl {{.*}} empty_binding_pack
+// CHECK-NEXT: ResolvedUnexpandedPackExpr
+// CHECK-NOT: DeclRefExpr {{.*}} 'empty_binding_pack'
+// CHECK-NOT: BindingDecl
+// CHECK: DeclStmt
#endif
>From 91ca5b4566f49f532ab7d0f6da1ab4a13c014df8 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Thu, 9 Jan 2025 19:50:04 -0800
Subject: [PATCH 08/13] [Clang][P1061] Add flat_binding_iterator
---
clang/include/clang/AST/DeclCXX.h | 85 ++++++++++++++++++-
clang/include/clang/AST/ExprCXX.h | 15 ++--
clang/lib/AST/DeclCXX.cpp | 27 +++++-
clang/lib/AST/ExprCXX.cpp | 8 +-
clang/lib/AST/StmtPrinter.cpp | 2 +-
clang/lib/Sema/SemaDeclCXX.cpp | 3 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 2 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 +-
clang/lib/Serialization/ASTReaderStmt.cpp | 2 +-
clang/lib/Serialization/ASTWriterStmt.cpp | 3 +-
10 files changed, 126 insertions(+), 25 deletions(-)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 6ac913e8b85b92..021fddcc836ef1 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4165,6 +4165,8 @@ class BindingDecl : public ValueDecl {
/// Set the decomposed variable for this BindingDecl.
void setDecomposedDecl(ValueDecl *Decomposed) { Decomp = Decomposed; }
+ /// Get the variable (if any) that holds the value of evaluating the binding.
+ /// Only present for user-defined bindings for tuple-like types.
VarDecl *getHoldingVar() const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -4213,10 +4215,19 @@ class DecompositionDecl final
static DecompositionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned NumBindings);
- ArrayRef<BindingDecl *> bindings() const {
- return llvm::ArrayRef(getTrailingObjects<BindingDecl *>(), NumBindings);
+ // Provide the range of bindings which may have a nested pack.
+ llvm::ArrayRef<BindingDecl *> bindings() const {
+ return {getTrailingObjects<BindingDecl *>(), NumBindings};
}
+ // Provide a flattened range to visit each binding directly.
+ class flat_binding_iterator;
+ using flat_binding_range = llvm::iterator_range<flat_binding_iterator>;
+
+ flat_binding_range flat_bindings() const;
+ flat_binding_iterator flat_bindings_begin() const;
+ flat_binding_iterator flat_bindings_end() const;
+
void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
/// Visit the variables (if any) that hold the values of evaluating the
@@ -4230,6 +4241,76 @@ class DecompositionDecl final
static bool classofKind(Kind K) { return K == Decomposition; }
};
+/// Iterate bindings that may be contain a nested pack of bindings.
+class DecompositionDecl::flat_binding_iterator {
+ friend class DecompositionDecl;
+
+ using ItrTy = llvm::ArrayRef<BindingDecl *>::const_iterator;
+ using PackItrTy = llvm::ArrayRef<Expr *>::const_iterator;
+
+ llvm::ArrayRef<BindingDecl *> Bindings;
+ llvm::ArrayRef<Expr *> PackExprs;
+ ItrTy Itr = nullptr;
+ PackItrTy PackItr = nullptr;
+
+ explicit flat_binding_iterator(llvm::ArrayRef<BindingDecl *> Bindings,
+ ItrTy Itr, llvm::ArrayRef<Expr *> PackExprs,
+ PackItrTy PackItr)
+ : Bindings(Bindings), PackExprs(PackExprs), Itr(Itr), PackItr(PackItr) {
+ // If Itr is not a parameter pack then PackItr should not be set.
+ assert(((!(*Itr)->isParameterPack() && PackItr == nullptr) ||
+ PackItr != PackExprs.end()) &&
+ "pack must have initial iterator within the range");
+ }
+
+public:
+ flat_binding_iterator() = default;
+
+ using value_type = BindingDecl *;
+ using reference = BindingDecl *;
+ using pointer = BindingDecl *;
+ using iterator_category = std::forward_iterator_tag;
+
+ reference operator*() const {
+ if (!(*Itr)->isParameterPack())
+ return *Itr;
+
+ auto *DRE = cast<DeclRefExpr>(*PackItr);
+ return cast<BindingDecl>(DRE->getDecl());
+ }
+
+ flat_binding_iterator &operator++() {
+ if ((*Itr)->isParameterPack()) {
+ ++PackItr;
+ if (PackItr != PackExprs.end())
+ return *this;
+ else
+ PackItr = nullptr;
+ }
+ ++Itr;
+ return *this;
+ }
+
+ flat_binding_iterator operator++(int) {
+ flat_binding_iterator Temp = *this;
+ ++*this;
+ return Temp;
+ }
+
+ bool operator==(const flat_binding_iterator &Other) const {
+ return Itr == Other.Itr && PackItr == Other.PackItr;
+ }
+
+ bool operator!=(const flat_binding_iterator &Other) const {
+ return Itr != Other.Itr || PackItr != Other.PackItr;
+ }
+};
+
+inline DecompositionDecl::flat_binding_range
+DecompositionDecl::flat_bindings() const {
+ return flat_binding_range(flat_bindings_begin(), flat_bindings_end());
+}
+
/// An instance of this class represents the declaration of a property
/// member. This is a Microsoft extension to C++, first introduced in
/// Visual Studio .NET 2003 as a parallel to similar features in C#
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 980f12bbf7e009..09d10087add718 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -5325,7 +5325,7 @@ class BuiltinBitCastExpr final
// known. These are used when structured bindings introduce a pack.
class ResolvedUnexpandedPackExpr final
: public Expr,
- private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Stmt *> {
+ private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Expr *> {
friend class ASTStmtReader;
friend class ASTStmtWriter;
friend TrailingObjects;
@@ -5346,11 +5346,12 @@ class ResolvedUnexpandedPackExpr final
unsigned getNumExprs() const { return NumExprs; }
- Expr **getExprs() {
- return reinterpret_cast<Expr **>(getTrailingObjects<Stmt *>());
+ llvm::MutableArrayRef<Expr *> getExprs() {
+ return {getTrailingObjects<Expr *>(), NumExprs};
}
- Expr *const *getExprs() const {
- return reinterpret_cast<Expr *const *>(getTrailingObjects<Stmt *>());
+
+ llvm::ArrayRef<Expr *> getExprs() const {
+ return {getTrailingObjects<Expr *>(), NumExprs};
}
Expr *getExpansion(unsigned Idx) { return getExprs()[Idx]; }
@@ -5358,8 +5359,8 @@ class ResolvedUnexpandedPackExpr final
// Iterators
child_range children() {
- return child_range(getTrailingObjects<Stmt *>(),
- getTrailingObjects<Stmt *>() + getNumExprs());
+ return child_range((Stmt **)getTrailingObjects<Expr *>(),
+ (Stmt **)getTrailingObjects<Expr *>() + getNumExprs());
}
SourceLocation getBeginLoc() const LLVM_READONLY { return BeginLoc; }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index d5a986bfd588cd..083bb77f31af19 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3436,11 +3436,9 @@ void DecompositionDecl::VisitHoldingVars(
void DecompositionDecl::VisitBindings(
llvm::function_ref<void(BindingDecl *)> F) const {
for (BindingDecl *B : bindings()) {
- llvm::ArrayRef<Expr *> Exprs;
if (B->isParameterPack()) {
auto *RP = cast<ResolvedUnexpandedPackExpr>(B->getBinding());
- Exprs = llvm::ArrayRef(RP->getExprs(), RP->getNumExprs());
- for (Expr *E : Exprs) {
+ for (Expr *E : RP->getExprs()) {
auto *DRE = cast<DeclRefExpr>(E);
F(cast<BindingDecl>(DRE->getDecl()));
}
@@ -3449,6 +3447,29 @@ void DecompositionDecl::VisitBindings(
}
}
+DecompositionDecl::flat_binding_iterator
+DecompositionDecl::flat_bindings_begin() const {
+ auto Bindings = bindings();
+ BindingDecl *First = *Bindings.begin();
+ llvm::ArrayRef<Expr *> PackExprs;
+
+ if (First->isParameterPack()) {
+ auto *RP = cast<ResolvedUnexpandedPackExpr>(First->getBinding());
+ PackExprs = RP->getExprs();
+ }
+
+ return flat_binding_iterator(Bindings, Bindings.begin(), PackExprs,
+ PackExprs.begin());
+}
+
+DecompositionDecl::flat_binding_iterator
+DecompositionDecl::flat_bindings_end() const {
+ auto Bindings = bindings();
+ llvm::ArrayRef<Expr *> PackExprs;
+
+ return flat_binding_iterator(Bindings, Bindings.end(), PackExprs, nullptr);
+}
+
void DecompositionDecl::anchor() {}
DecompositionDecl *DecompositionDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 7c710b703f38c1..107ec3dcd9ac65 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1981,7 +1981,7 @@ ResolvedUnexpandedPackExpr::ResolvedUnexpandedPackExpr(SourceLocation BL,
ResolvedUnexpandedPackExpr *
ResolvedUnexpandedPackExpr::CreateDeserialized(ASTContext &Ctx,
unsigned NumExprs) {
- void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumExprs),
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<Expr *>(NumExprs),
alignof(ResolvedUnexpandedPackExpr));
return new (Mem)
ResolvedUnexpandedPackExpr(SourceLocation(), QualType(), NumExprs);
@@ -1990,12 +1990,12 @@ ResolvedUnexpandedPackExpr::CreateDeserialized(ASTContext &Ctx,
ResolvedUnexpandedPackExpr *
ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL,
QualType T, unsigned NumExprs) {
- void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumExprs),
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<Expr *>(NumExprs),
alignof(ResolvedUnexpandedPackExpr));
ResolvedUnexpandedPackExpr *New =
new (Mem) ResolvedUnexpandedPackExpr(BL, T, NumExprs);
- auto Exprs = llvm::MutableArrayRef(New->getExprs(), New->getNumExprs());
+ auto Exprs = New->getExprs();
std::fill(Exprs.begin(), Exprs.end(), nullptr);
return New;
@@ -2005,7 +2005,7 @@ ResolvedUnexpandedPackExpr *
ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL,
QualType T, ArrayRef<Expr *> Exprs) {
auto *New = Create(Ctx, BL, T, Exprs.size());
- std::copy(Exprs.begin(), Exprs.end(), New->getExprs());
+ std::copy(Exprs.begin(), Exprs.end(), New->getExprs().begin());
return New;
}
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 50bf880a4d37ea..64955553108f78 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2562,7 +2562,7 @@ void StmtPrinter::VisitResolvedUnexpandedPackExpr(
ResolvedUnexpandedPackExpr *E) {
OS << "<<resolved pack(";
llvm::interleave(
- E->getExprs(), E->getExprs() + E->getNumExprs(),
+ E->getExprs().begin(), E->getExprs().end(),
[this](auto *X) { PrintExpr(X); }, [this] { OS << ", "; });
OS << ")>>";
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 2f657bdd2eada1..cf78ea197f77c7 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1032,8 +1032,7 @@ struct BindingInitWalker {
isa_and_nonnull<ResolvedUnexpandedPackExpr>(B->getBinding());
if (IsPackExpr && !PackExpr) {
PackExpr = cast<ResolvedUnexpandedPackExpr>(B->getBinding());
- PackExprNodes =
- llvm::MutableArrayRef(PackExpr->getExprs(), PackExpr->getNumExprs());
+ PackExprNodes = PackExpr->getExprs();
PackExprItr = PackExprNodes.begin();
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 84fd945813fa25..dea44fb3910f78 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2675,7 +2675,7 @@ ExprResult TemplateInstantiator::TransformResolvedUnexpandedPackExpr(
return E;
SmallVector<Expr *, 12> NewExprs;
- if (TransformExprs(E->getExprs(), E->getNumExprs(),
+ if (TransformExprs(E->getExprs().begin(), E->getNumExprs(),
/*IsCall=*/false, NewExprs))
return ExprError();
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4ae29854a58725..5593b2c7a87bf5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1202,8 +1202,8 @@ Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) {
[](BindingDecl *D) -> bool { return D->isParameterPack(); });
auto *NewResolvedPack =
cast<ResolvedUnexpandedPackExpr>((*BPack)->getBinding());
- Expr **OldExprs = OldResolvedPack->getExprs();
- Expr **NewExprs = NewResolvedPack->getExprs();
+ auto OldExprs = OldResolvedPack->getExprs();
+ auto NewExprs = NewResolvedPack->getExprs();
for (unsigned I = 0; I < OldResolvedPack->getNumExprs(); I++) {
DeclRefExpr *OldDRE = cast<DeclRefExpr>(OldExprs[I]);
BindingDecl *OldNestedBD = cast<BindingDecl>(OldDRE->getDecl());
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 9cf663cc41dded..cb26228a37fcde 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2206,7 +2206,7 @@ void ASTStmtReader::VisitResolvedUnexpandedPackExpr(
VisitExpr(E);
E->NumExprs = Record.readInt();
E->BeginLoc = readSourceLocation();
- auto **Exprs = E->getExprs();
+ auto **Exprs = E->getTrailingObjects<Expr *>();
for (unsigned I = 0; I < E->NumExprs; ++I)
Exprs[I] = Record.readExpr();
}
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 26967160d40b4e..60470ea2f367a6 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2207,8 +2207,7 @@ void ASTStmtWriter::VisitResolvedUnexpandedPackExpr(
VisitExpr(E);
Record.push_back(E->getNumExprs());
Record.AddSourceLocation(E->getBeginLoc());
- auto SubExprs = llvm::ArrayRef(E->getExprs(), E->getNumExprs());
- for (Expr *Sub : SubExprs)
+ for (Expr *Sub : E->getExprs())
Record.AddStmt(Sub);
Code = serialization::EXPR_RESOLVED_UNEXPANDED_PACK;
}
>From abab5cf53e86ee3d9d6afe53ac36967d516f1eb6 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Fri, 10 Jan 2025 10:22:05 -0800
Subject: [PATCH 09/13] [Clang][P1061] Remove Decomp Visit functions
---
clang/include/clang/AST/DeclCXX.h | 24 ++++++------------------
clang/lib/AST/ASTContext.cpp | 11 ++++-------
clang/lib/AST/DeclCXX.cpp | 27 ++++-----------------------
clang/lib/AST/ExprConstant.cpp | 4 +++-
clang/lib/CodeGen/CGDebugInfo.cpp | 3 +--
clang/lib/CodeGen/CGDecl.cpp | 5 ++++-
clang/lib/CodeGen/CodeGenModule.cpp | 5 ++++-
clang/lib/Sema/SemaExceptionSpec.cpp | 6 +++---
8 files changed, 29 insertions(+), 56 deletions(-)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 021fddcc836ef1..be564b4118dc11 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4230,13 +4230,6 @@ class DecompositionDecl final
void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
- /// Visit the variables (if any) that hold the values of evaluating the
- /// binding. Only present for user-defined bindings for tuple-like types.
- void VisitHoldingVars(llvm::function_ref<void(VarDecl *)> F) const;
-
- // Visit the concrete bindings.
- void VisitBindings(llvm::function_ref<void(BindingDecl *)> F) const;
-
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decomposition; }
};
@@ -4245,8 +4238,8 @@ class DecompositionDecl final
class DecompositionDecl::flat_binding_iterator {
friend class DecompositionDecl;
- using ItrTy = llvm::ArrayRef<BindingDecl *>::const_iterator;
- using PackItrTy = llvm::ArrayRef<Expr *>::const_iterator;
+ using ItrTy = llvm::ArrayRef<BindingDecl *>::iterator;
+ using PackItrTy = llvm::ArrayRef<Expr *>::iterator;
llvm::ArrayRef<BindingDecl *> Bindings;
llvm::ArrayRef<Expr *> PackExprs;
@@ -4256,22 +4249,17 @@ class DecompositionDecl::flat_binding_iterator {
explicit flat_binding_iterator(llvm::ArrayRef<BindingDecl *> Bindings,
ItrTy Itr, llvm::ArrayRef<Expr *> PackExprs,
PackItrTy PackItr)
- : Bindings(Bindings), PackExprs(PackExprs), Itr(Itr), PackItr(PackItr) {
- // If Itr is not a parameter pack then PackItr should not be set.
- assert(((!(*Itr)->isParameterPack() && PackItr == nullptr) ||
- PackItr != PackExprs.end()) &&
- "pack must have initial iterator within the range");
- }
+ : Bindings(Bindings), PackExprs(PackExprs), Itr(Itr), PackItr(PackItr) {}
public:
flat_binding_iterator() = default;
using value_type = BindingDecl *;
- using reference = BindingDecl *;
- using pointer = BindingDecl *;
+ using reference = BindingDecl *&;
+ using pointer = BindingDecl **;
using iterator_category = std::forward_iterator_tag;
- reference operator*() const {
+ BindingDecl *operator*() {
if (!(*Itr)->isParameterPack())
return *Itr;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 6216d896a88ac3..c340d6aeebc600 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12727,13 +12727,10 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
// Likewise, variables with tuple-like bindings are required if their
// bindings have side-effects.
if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
- bool BindingResult = false;
- DD->VisitHoldingVars([&](VarDecl *BindingVD) {
- if (DeclMustBeEmitted(BindingVD))
- BindingResult = true;
- });
- if (BindingResult)
- return true;
+ for (const auto *BD : DD->flat_bindings())
+ if (const auto *BindingVD = BD->getHoldingVar())
+ if (DeclMustBeEmitted(BindingVD))
+ return true;
}
return false;
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 083bb77f31af19..6d9213b5d8037f 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3425,35 +3425,16 @@ VarDecl *BindingDecl::getHoldingVar() const {
return VD;
}
-void DecompositionDecl::VisitHoldingVars(
- llvm::function_ref<void(VarDecl *)> F) const {
- VisitBindings([&](BindingDecl *BD) {
- if (VarDecl *VD = BD->getHoldingVar())
- F(VD);
- });
-}
-
-void DecompositionDecl::VisitBindings(
- llvm::function_ref<void(BindingDecl *)> F) const {
- for (BindingDecl *B : bindings()) {
- if (B->isParameterPack()) {
- auto *RP = cast<ResolvedUnexpandedPackExpr>(B->getBinding());
- for (Expr *E : RP->getExprs()) {
- auto *DRE = cast<DeclRefExpr>(E);
- F(cast<BindingDecl>(DRE->getDecl()));
- }
- } else
- F(B);
- }
-}
-
DecompositionDecl::flat_binding_iterator
DecompositionDecl::flat_bindings_begin() const {
+ if (NumBindings == 0)
+ return flat_bindings_end();
+
auto Bindings = bindings();
BindingDecl *First = *Bindings.begin();
llvm::ArrayRef<Expr *> PackExprs;
- if (First->isParameterPack()) {
+ if (NumBindings > 0 && First->isParameterPack()) {
auto *RP = cast<ResolvedUnexpandedPackExpr>(First->getBinding());
PackExprs = RP->getExprs();
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b7ff7aa1d61ecc..c767ea93065840 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5155,7 +5155,9 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
OK &= EvaluateVarDecl(Info, VD);
if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(D))
- DD->VisitHoldingVars([&](VarDecl *HD) { OK &= EvaluateDecl(Info, HD); });
+ for (auto *BD : DD->flat_bindings())
+ if (auto *VD = BD->getHoldingVar())
+ OK &= EvaluateDecl(Info, VD);
return OK;
}
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index db424dabc0575f..df23ce6d48cd71 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -5067,10 +5067,9 @@ CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage,
assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
if (auto *DD = dyn_cast<DecompositionDecl>(VD)) {
- DD->VisitBindings([&](BindingDecl *B) {
+ for (BindingDecl *B : DD->flat_bindings())
EmitDeclare(B, Storage, std::nullopt, Builder,
VD->getType()->isReferenceType());
- });
// Don't emit an llvm.dbg.declare for the composite storage as it doesn't
// correspond to a user variable.
return nullptr;
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 06b4f39e1e3d81..34c33ef586ba37 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -162,7 +162,10 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
"Should not see file-scope variables inside a function!");
EmitVarDecl(VD);
if (auto *DD = dyn_cast<DecompositionDecl>(&VD))
- DD->VisitHoldingVars([&](VarDecl *HD) { EmitVarDecl(*HD); });
+ for (auto *B : DD->flat_bindings())
+ if (auto *HD = B->getHoldingVar())
+ EmitVarDecl(*HD);
+
return;
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index bfd459dabafe10..a5bd54dd41e6b6 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6987,7 +6987,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::VarTemplateSpecialization:
EmitGlobal(cast<VarDecl>(D));
if (auto *DD = dyn_cast<DecompositionDecl>(D))
- DD->VisitHoldingVars([&](VarDecl *HD) { EmitGlobal(HD); });
+ for (auto *B : DD->flat_bindings())
+ if (auto *HD = B->getHoldingVar())
+ EmitGlobal(HD);
+
break;
// Indirect fields from global anonymous structs and unions can be
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 079ba597ed0cf1..4cd277e3821633 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1068,9 +1068,9 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
// If this is a decomposition declaration, bindings might throw.
if (auto *DD = dyn_cast<DecompositionDecl>(VD))
- DD->VisitHoldingVars([&](VarDecl *HD) {
- CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD));
- });
+ for (auto *B : DD->flat_bindings())
+ if (auto *HD = B->getHoldingVar())
+ CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD));
return CT;
}
>From 80acb717f7617b1983cfde72d62461c2533fc6e8 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Tue, 14 Jan 2025 17:01:10 -0800
Subject: [PATCH 10/13] [Clang][P1061] Use range concat for flat_bindings
---
clang/include/clang/AST/DeclCXX.h | 96 +++++++++----------------------
clang/lib/AST/DeclCXX.cpp | 27 +--------
2 files changed, 29 insertions(+), 94 deletions(-)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index be564b4118dc11..2b3adb04664377 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4150,6 +4150,9 @@ class BindingDecl : public ValueDecl {
/// decomposition declaration, and when the initializer is type-dependent.
Expr *getBinding() const { return Binding; }
+ // Get the array of Exprs when the binding represents a pack.
+ llvm::ArrayRef<Expr *> getBindingPackExprs() const;
+
/// Get the decomposition declaration that this binding represents a
/// decomposition of.
ValueDecl *getDecomposedDecl() const { return Decomp; }
@@ -4220,84 +4223,37 @@ class DecompositionDecl final
return {getTrailingObjects<BindingDecl *>(), NumBindings};
}
- // Provide a flattened range to visit each binding directly.
- class flat_binding_iterator;
- using flat_binding_range = llvm::iterator_range<flat_binding_iterator>;
-
- flat_binding_range flat_bindings() const;
- flat_binding_iterator flat_bindings_begin() const;
- flat_binding_iterator flat_bindings_end() const;
-
- void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
+ // Provide a flattened range to visit each binding.
+ auto flat_bindings() const {
+ llvm::ArrayRef<BindingDecl *> Bindings = bindings();
+ llvm::ArrayRef<Expr *> PackExprs;
- static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classofKind(Kind K) { return K == Decomposition; }
-};
-
-/// Iterate bindings that may be contain a nested pack of bindings.
-class DecompositionDecl::flat_binding_iterator {
- friend class DecompositionDecl;
-
- using ItrTy = llvm::ArrayRef<BindingDecl *>::iterator;
- using PackItrTy = llvm::ArrayRef<Expr *>::iterator;
-
- llvm::ArrayRef<BindingDecl *> Bindings;
- llvm::ArrayRef<Expr *> PackExprs;
- ItrTy Itr = nullptr;
- PackItrTy PackItr = nullptr;
-
- explicit flat_binding_iterator(llvm::ArrayRef<BindingDecl *> Bindings,
- ItrTy Itr, llvm::ArrayRef<Expr *> PackExprs,
- PackItrTy PackItr)
- : Bindings(Bindings), PackExprs(PackExprs), Itr(Itr), PackItr(PackItr) {}
-
-public:
- flat_binding_iterator() = default;
+ // Split the bindings into subranges split by the pack.
+ auto S1 = Bindings.take_until(
+ [](BindingDecl *BD) { return BD->isParameterPack(); });
- using value_type = BindingDecl *;
- using reference = BindingDecl *&;
- using pointer = BindingDecl **;
- using iterator_category = std::forward_iterator_tag;
-
- BindingDecl *operator*() {
- if (!(*Itr)->isParameterPack())
- return *Itr;
-
- auto *DRE = cast<DeclRefExpr>(*PackItr);
- return cast<BindingDecl>(DRE->getDecl());
- }
-
- flat_binding_iterator &operator++() {
- if ((*Itr)->isParameterPack()) {
- ++PackItr;
- if (PackItr != PackExprs.end())
- return *this;
- else
- PackItr = nullptr;
+ Bindings = Bindings.drop_front(S1.size());
+ if (!Bindings.empty()) {
+ PackExprs = Bindings.front()->getBindingPackExprs();
+ Bindings = Bindings.drop_front();
}
- ++Itr;
- return *this;
- }
- flat_binding_iterator operator++(int) {
- flat_binding_iterator Temp = *this;
- ++*this;
- return Temp;
- }
+ auto S2 = llvm::map_range(PackExprs, [](Expr *E) {
+ auto *DRE = cast<DeclRefExpr>(E);
+ return cast<BindingDecl>(DRE->getDecl());
+ });
- bool operator==(const flat_binding_iterator &Other) const {
- return Itr == Other.Itr && PackItr == Other.PackItr;
+ // llvm::concat must take temporaries or it will capture
+ // references.
+ return llvm::concat<BindingDecl *>(std::move(S1), std::move(S2),
+ std::move(Bindings));
}
- bool operator!=(const flat_binding_iterator &Other) const {
- return Itr != Other.Itr || PackItr != Other.PackItr;
- }
-};
+ void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
-inline DecompositionDecl::flat_binding_range
-DecompositionDecl::flat_bindings() const {
- return flat_binding_range(flat_bindings_begin(), flat_bindings_end());
-}
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == Decomposition; }
+};
/// An instance of this class represents the declaration of a property
/// member. This is a Microsoft extension to C++, first introduced in
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 6d9213b5d8037f..7c286a42e338fb 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3425,30 +3425,9 @@ VarDecl *BindingDecl::getHoldingVar() const {
return VD;
}
-DecompositionDecl::flat_binding_iterator
-DecompositionDecl::flat_bindings_begin() const {
- if (NumBindings == 0)
- return flat_bindings_end();
-
- auto Bindings = bindings();
- BindingDecl *First = *Bindings.begin();
- llvm::ArrayRef<Expr *> PackExprs;
-
- if (NumBindings > 0 && First->isParameterPack()) {
- auto *RP = cast<ResolvedUnexpandedPackExpr>(First->getBinding());
- PackExprs = RP->getExprs();
- }
-
- return flat_binding_iterator(Bindings, Bindings.begin(), PackExprs,
- PackExprs.begin());
-}
-
-DecompositionDecl::flat_binding_iterator
-DecompositionDecl::flat_bindings_end() const {
- auto Bindings = bindings();
- llvm::ArrayRef<Expr *> PackExprs;
-
- return flat_binding_iterator(Bindings, Bindings.end(), PackExprs, nullptr);
+llvm::ArrayRef<Expr *> BindingDecl::getBindingPackExprs() const {
+ auto *RP = cast<ResolvedUnexpandedPackExpr>(Binding);
+ return RP->getExprs();
}
void DecompositionDecl::anchor() {}
>From 360708d3d03c337b613cc910a368488a979c66db Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Wed, 15 Jan 2025 12:23:44 -0800
Subject: [PATCH 11/13] [Clang][P1061] Unremove llvm_unreachable in EmitDecl
---
clang/lib/CodeGen/CGDecl.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 34c33ef586ba37..55f6b7c882c914 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -104,6 +104,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Binding:
case Decl::UnresolvedUsingIfExists:
case Decl::HLSLBuffer:
+ llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Record: // struct/union/class X;
case Decl::CXXRecord: // struct/union/class X; [C++]
if (CGDebugInfo *DI = getDebugInfo())
>From ea249ac2527045d7a77902977d5f296c4ca10ab3 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Wed, 15 Jan 2025 15:05:10 -0800
Subject: [PATCH 12/13] [Clang][P1061] Move rebuild of resolved packs into
TreeTransform
---
clang/lib/Sema/SemaTemplateInstantiate.cpp | 17 ++++-------------
clang/lib/Sema/TreeTransform.h | 22 ++++++++++++++++++++--
2 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index dea44fb3910f78..1c001ac5054d14 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2490,7 +2490,9 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
return TransformFunctionParmPackRefExpr(E, PD);
if (BindingDecl *BD = dyn_cast<BindingDecl>(D); BD && BD->isParameterPack()) {
- BD = cast<BindingDecl>(TransformDecl(BD->getLocation(), BD));
+ BD = cast_or_null<BindingDecl>(TransformDecl(BD->getLocation(), BD));
+ if (!BD)
+ return ExprError();
if (auto *RP =
dyn_cast_if_present<ResolvedUnexpandedPackExpr>(BD->getBinding())) {
return TransformResolvedUnexpandedPackExpr(RP);
@@ -2671,18 +2673,7 @@ ExprResult TemplateInstantiator::TransformResolvedUnexpandedPackExpr(
E->getExpansion(getSema().ArgumentPackSubstitutionIndex));
}
- if (!AlwaysRebuild())
- return E;
-
- SmallVector<Expr *, 12> NewExprs;
- if (TransformExprs(E->getExprs().begin(), E->getNumExprs(),
- /*IsCall=*/false, NewExprs))
- return ExprError();
-
- // NOTE: The type is just a superficial PackExpansionType
- // that needs no substitution.
- return ResolvedUnexpandedPackExpr::Create(SemaRef.Context, E->getBeginLoc(),
- E->getType(), NewExprs);
+ return inherited::TransformResolvedUnexpandedPackExpr(E);
}
QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 7af74c6d469a55..8bc4eaf60f8550 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3676,6 +3676,13 @@ class TreeTransform {
FullySubstituted);
}
+ ExprResult RebuildResolvedUnexpandedPackExpr(SourceLocation BeginLoc,
+ QualType T,
+ ArrayRef<Expr *> Exprs) {
+ return ResolvedUnexpandedPackExpr::Create(SemaRef.Context, BeginLoc, T,
+ Exprs);
+ }
+
/// Build a new expression representing a call to a source location
/// builtin.
///
@@ -15994,8 +16001,19 @@ TreeTransform<Derived>::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
template <typename Derived>
ExprResult TreeTransform<Derived>::TransformResolvedUnexpandedPackExpr(
ResolvedUnexpandedPackExpr *E) {
- // Default behavior is to do nothing with this transformation.
- return E;
+ bool ArgumentChanged = false;
+ SmallVector<Expr *, 12> NewExprs;
+ if (TransformExprs(E->getExprs().begin(), E->getNumExprs(),
+ /*IsCall=*/false, NewExprs, &ArgumentChanged))
+ return ExprError();
+
+ if (!AlwaysRebuild() && !ArgumentChanged)
+ return E;
+
+ // NOTE: The type is just a superficial PackExpansionType
+ // that needs no substitution.
+ return RebuildResolvedUnexpandedPackExpr(E->getBeginLoc(), E->getType(),
+ NewExprs);
}
template<typename Derived>
>From dda9d89e7520047508732e6fcd43516ae28c8b71 Mon Sep 17 00:00:00 2001
From: Jason Rice <ricejasonf at gmail.com>
Date: Wed, 15 Jan 2025 21:01:28 -0800
Subject: [PATCH 13/13] [Clang][P1061] Fix crash
---
clang/include/clang/AST/DeclCXX.h | 10 +++++++++-
clang/lib/AST/DeclCXX.cpp | 2 ++
clang/lib/AST/ExprCXX.cpp | 4 ++--
clang/lib/Sema/SemaDeclCXX.cpp | 16 +++++-----------
4 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 2b3adb04664377..e5cd7bbf958243 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4199,8 +4199,16 @@ class DecompositionDecl final
NumBindings(Bindings.size()) {
std::uninitialized_copy(Bindings.begin(), Bindings.end(),
getTrailingObjects<BindingDecl *>());
- for (auto *B : Bindings)
+ for (auto *B : Bindings) {
B->setDecomposedDecl(this);
+ if (B->isParameterPack()) {
+ for (Expr *E : B->getBindingPackExprs()) {
+ auto *DRE = cast<DeclRefExpr>(E);
+ auto *NestedB = cast<BindingDecl>(DRE->getDecl());
+ NestedB->setDecomposedDecl(this);
+ }
+ }
+ }
}
void anchor() override;
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 7c286a42e338fb..6d6cb3a0ef18de 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3426,6 +3426,8 @@ VarDecl *BindingDecl::getHoldingVar() const {
}
llvm::ArrayRef<Expr *> BindingDecl::getBindingPackExprs() const {
+ if (!Binding)
+ return {};
auto *RP = cast<ResolvedUnexpandedPackExpr>(Binding);
return RP->getExprs();
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 107ec3dcd9ac65..a1620376d1a40f 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1996,7 +1996,7 @@ ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL,
new (Mem) ResolvedUnexpandedPackExpr(BL, T, NumExprs);
auto Exprs = New->getExprs();
- std::fill(Exprs.begin(), Exprs.end(), nullptr);
+ std::uninitialized_fill(Exprs.begin(), Exprs.end(), nullptr);
return New;
}
@@ -2005,7 +2005,7 @@ ResolvedUnexpandedPackExpr *
ResolvedUnexpandedPackExpr::Create(ASTContext &Ctx, SourceLocation BL,
QualType T, ArrayRef<Expr *> Exprs) {
auto *New = Create(Ctx, BL, T, Exprs.size());
- std::copy(Exprs.begin(), Exprs.end(), New->getExprs().begin());
+ std::uninitialized_copy(Exprs.begin(), Exprs.end(), New->getExprs().begin());
return New;
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index cf78ea197f77c7..945fddd29e6d51 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -981,20 +981,14 @@ static bool CheckBindingsCount(Sema &S, DecompositionDecl *DD,
}
if (IsValid && HasPack) {
- TemplateTypeParmDecl *DummyTemplateParam = TemplateTypeParmDecl::Create(
- S.Context, S.Context.getTranslationUnitDecl(),
- /*KeyLoc*/ SourceLocation(), /*NameLoc*/ SourceLocation(),
- /*TemplateDepth*/ 0, /*AutoParameterPosition*/ 0,
- /*Identifier*/ nullptr, false, /*IsParameterPack*/ true);
-
// create the pack expr and assign it to the binding
unsigned PackSize = MemberCount - Bindings.size() + 1;
QualType PackType = S.Context.getPackExpansionType(
- QualType(DummyTemplateParam->getTypeForDecl(), 0), PackSize);
- (*BindingWithPackItr)
- ->setBinding(PackType,
- ResolvedUnexpandedPackExpr::Create(
- S.Context, DD->getBeginLoc(), DecompType, PackSize));
+ S.Context.DependentTy, std::nullopt, /*ExpectsPackInType=*/false);
+ BindingDecl *BD = (*BindingWithPackItr);
+ BD->setBinding(PackType,
+ ResolvedUnexpandedPackExpr::Create(
+ S.Context, DD->getBeginLoc(), DecompType, PackSize));
}
if (IsValid)
More information about the cfe-commits
mailing list