Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Clang][P1061] Add stuctured binding packs #121417

Merged
merged 26 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3c81c5b
[Clang][P1061] stuctured binding packs
ricejasonf Jul 22, 2021
116aff1
[Clang][P1061] Improve visiting HoldingVars; Improve parsing diagnost…
ricejasonf Jan 2, 2025
66ff7c6
[Clang][P1061] Remove unrelated code changes; Address style issues
ricejasonf Jan 2, 2025
5720bd3
[Clang][P1061] Remove vestigial changes
ricejasonf Jan 3, 2025
ffefb67
[Clang][P1061] Simplify unwrapping ResolvedPacks; other style fixes
ricejasonf Jan 3, 2025
685f947
[Clang][P1061] Add ASTReader implementation
ricejasonf Jan 4, 2025
d957783
[Clang][P1061] Improve AST dump testing
ricejasonf Jan 4, 2025
91ca5b4
[Clang][P1061] Add flat_binding_iterator
ricejasonf Jan 10, 2025
abab5cf
[Clang][P1061] Remove Decomp Visit functions
ricejasonf Jan 10, 2025
80acb71
[Clang][P1061] Use range concat for flat_bindings
ricejasonf Jan 15, 2025
360708d
[Clang][P1061] Unremove llvm_unreachable in EmitDecl
ricejasonf Jan 15, 2025
ea249ac
[Clang][P1061] Move rebuild of resolved packs into TreeTransform
ricejasonf Jan 15, 2025
dda9d89
[Clang][P1061] Fix crash
ricejasonf Jan 16, 2025
0b83b99
[Clang][P1061] Fix crash (part 2)
ricejasonf Jan 16, 2025
d496c54
[Clang][P1061] Add bit-field and pack indexing tests
ricejasonf Jan 16, 2025
d064095
[Clang][P1061] Make BindingDecl have NULL TYPE by default
ricejasonf Jan 16, 2025
97257d7
[Clang][P1061] Revert change to typo correction test
ricejasonf Jan 16, 2025
39ab76e
[Clang][P1061] Add codegen test
ricejasonf Jan 17, 2025
765db8a
[Clang][P1061] Clean up stuff
ricejasonf Jan 17, 2025
8cf8205
[Clang][P1061] Use cast_if_present
ricejasonf Jan 17, 2025
6d49a3d
[Clang][P1061] Improve error message wording
ricejasonf Jan 18, 2025
5c351d7
[Clang][P1061] Fix error messages in tests
ricejasonf Jan 18, 2025
5302830
[Clang][P1061] Remove BindingInitWalker
ricejasonf Jan 21, 2025
e497a0c
[Clang][P1061] Handle explicitly capturing binding packs
zwuis Jan 22, 2025
5751d2f
[Clang][P1016] Address nits; Remove unneeded code
ricejasonf Jan 28, 2025
36f8029
[Clang][P1061] Add proper C++ compatability warnings
ricejasonf Jan 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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 {
Expand Down
21 changes: 14 additions & 7 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -4131,16 +4131,18 @@ 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;

public:
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
Expand All @@ -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).
Expand All @@ -4167,6 +4165,8 @@ class BindingDecl : public ValueDecl {
/// Set the decomposed variable for this BindingDecl.
void setDecomposedDecl(ValueDecl *Decomposed) { Decomp = Decomposed; }

VarDecl *getHoldingVar() const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get the comment to move as well? Or at least an updated one?


static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decl::Binding; }
};
Expand Down Expand Up @@ -4219,6 +4219,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.
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; }
};
Expand Down
50 changes: 50 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -5321,6 +5321,56 @@ 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
cor3ntin marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +5324 to +5326
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be doing the same job as SubstNonTypeTemplateParmPackExpr and FunctionParmPackExpr. Do we need all three? If so, mentioning the relationship between the three in this comment might be nice -- but I do wonder if FunctionParmPackExpr could be generalized to cover the case of a binding declaration too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely think they could be generalized which is what I had in mind with ResolvedUnexpandedPackExpr. This is originally what I had for parmexprs (P1221).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we try to address that?

: public Expr,
private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Stmt *> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Stmt *> {
private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Expr *> {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only place you're using this as a Stmt is for children, and the cast that way is 'safe' (and Expr isa Stmt). This change likely saves a bunch of casting elsewhere.

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
1 change: 1 addition & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,13 @@ 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 note_previous_ellipsis : Note<
"previous ellipsis specified here">;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a little strange to talk about ellipses rather than packs here. Maybe "multiple binding packs in [...]" instead?

def ext_cxx_binding_pack : ExtWarn<
cor3ntin marked this conversation as resolved.
Show resolved Hide resolved
"structured binding pack is incompatible with C++ standards before C++2c">,
InGroup<CXX26>;
def err_capture_default_first : Error<
"capture default must be first">;
def ext_decl_attrs_on_lambda : ExtWarn<
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -1795,6 +1795,7 @@ class DecompositionDeclarator {
IdentifierInfo *Name;
SourceLocation NameLoc;
std::optional<ParsedAttributes> Attrs;
SourceLocation EllipsisLoc;
};

private:
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 9 additions & 5 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of a 'Visit' here, I wonder if there is value with some sort of llvm::any_of on the collection instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added a flat_binding_iterator to replace these Visit* functions. I forgot to use it here, but if a custom iterator is what you wanted, please consider it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be a little surprised if there wasn't an existing iterator type that would work. If not though, I'd vastly prefer removing both of the Visit functions and replacing them with iterators.

Copy link
Contributor Author

@ricejasonf ricejasonf Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced the Visit functions with flat_bindings and reverted the places where I was using them. I will look to see if there is some existing iterator that you are referring to if it would be simpler than flat_binding_iterator (which had some things I had to fix.)

if (DeclMustBeEmitted(BindingVD))
BindingResult = true;
});
if (BindingResult)
return true;
}

return false;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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());
zyn0217 marked this conversation as resolved.
Show resolved Hide resolved
}

void ImplicitParamDecl::anchor() {}

ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ bool Decl::isTemplateParameterPack() const {
}

bool Decl::isParameterPack() const {
if (const auto *Var = dyn_cast<VarDecl>(this))
if (const auto *Var = dyn_cast<ValueDecl>(this))
zyn0217 marked this conversation as resolved.
Show resolved Hide resolved
return Var->isParameterPack();

return isTemplateParameterPack();
Expand Down
34 changes: 30 additions & 4 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3395,19 +3395,21 @@ 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_if_present<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 {
Expand All @@ -3423,6 +3425,30 @@ VarDecl *BindingDecl::getHoldingVar() const {
return VD;
}

void DecompositionDecl::VisitHoldingVars(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than both of these functions, I'd prefer we have some sort of iterators that allow standard iteration over these. We have 'filter' iterators already that take a lambda that we could define to allow going through these.

The visitation can be nice, but it has the requirement of going through every element even when we only care about 'the first of'.

llvm::function_ref<void(VarDecl *)> F) const {
VisitBindings([&](BindingDecl *BD) {
if (VarDecl *VD = BD->getHoldingVar())
F(VD);
});
}

void DecompositionDecl::VisitBindings(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is a bit more complicated? But I'd be surprised if there isn't an existing llvm iterator that can do this.

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,
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3653,6 +3653,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case PackIndexingExprClass:
case HLSLOutArgExprClass:
case OpenACCAsteriskSizeExprClass:
case ResolvedUnexpandedPackExprClass:
// These never have a side-effect.
return false;

Expand Down
49 changes: 49 additions & 0 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1965,3 +1965,52 @@ 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) {
// 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);
cor3ntin marked this conversation as resolved.
Show resolved Hide resolved
}

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());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be a std::uninitialized_copy?

Copy link
Contributor Author

@ricejasonf ricejasonf Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it could. The other Create function it is calling here is using std::fill which could probably be std::uninitialized_fill. EDIT: (assuming we even want the fill at all)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC I looked it up at one point and found that std::copy into uninitialized data (or perhaps std::fill as well), but I cannot for the life of me remember what it was. Perhaps it is just 'dtor' related stuff (which makes this not matter for pointers?) but the code I wrote is pointers-only too, so IDK why it became a bit of my personal cargo-cult.

return New;
}

ResolvedUnexpandedPackExpr *ResolvedUnexpandedPackExpr::getFromDecl(Decl *D) {
if (auto *BD = dyn_cast<BindingDecl>(D))
return dyn_cast_if_present<ResolvedUnexpandedPackExpr>(BD->getBinding());
return nullptr;
}
Loading
Loading