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