[Clang][Sema] Avoid pack expansion for expanded empty PackIndexingExprs (#92385)

We previously doubled the id-expression expansion, even when the pack
was expanded to empty. The previous condition for determining whether we
should expand couldn't distinguish between cases where 'the expansion
was previously postponed' and 'the expansion occurred but resulted in
emptiness.'

In the latter scenario, we crash because we have not been examining the
current lambda's parent local instantiation scope since
[D98068](https://reviews.llvm.org/D98068): Any Decls instantiated in the
parent scope are not visible to the generic lambda, and thus any attempt
of looking for instantiated Decls in the lambda is capped to the current
Lambda's LIS.

Fixes https://github.com/llvm/llvm-project/issues/92230
This commit is contained in:
Younan Zhang
2024-05-21 09:47:05 +08:00
committed by GitHub
parent d1aca0ae2e
commit 8ce2045be0
8 changed files with 37 additions and 20 deletions

View File

@@ -4377,15 +4377,21 @@ class PackIndexingExpr final
// The pack being indexed, followed by the index
Stmt *SubExprs[2];
size_t TransformedExpressions;
// The size of the trailing expressions.
unsigned TransformedExpressions : 31;
LLVM_PREFERRED_TYPE(bool)
unsigned ExpandedToEmptyPack : 1;
PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr,
ArrayRef<Expr *> SubstitutedExprs = {})
ArrayRef<Expr *> SubstitutedExprs = {},
bool ExpandedToEmptyPack = false)
: Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
SubExprs{PackIdExpr, IndexExpr},
TransformedExpressions(SubstitutedExprs.size()) {
TransformedExpressions(SubstitutedExprs.size()),
ExpandedToEmptyPack(ExpandedToEmptyPack) {
auto *Exprs = getTrailingObjects<Expr *>();
std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(),
@@ -4408,10 +4414,14 @@ public:
SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr,
Expr *IndexExpr, std::optional<int64_t> Index,
ArrayRef<Expr *> SubstitutedExprs = {});
ArrayRef<Expr *> SubstitutedExprs = {},
bool ExpandedToEmptyPack = false);
static PackIndexingExpr *CreateDeserialized(ASTContext &Context,
unsigned NumTransformedExprs);
/// Determine if the expression was expanded to empty.
bool expandsToEmptyPack() const { return ExpandedToEmptyPack; }
/// Determine the location of the 'sizeof' keyword.
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
@@ -4445,6 +4455,7 @@ public:
return getTrailingObjects<Expr *>()[*Index];
}
/// Return the trailing expressions, regardless of the expansion.
ArrayRef<Expr *> getExpressions() const {
return {getTrailingObjects<Expr *>(), TransformedExpressions};
}

View File

@@ -1665,12 +1665,10 @@ NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]);
}
PackIndexingExpr *PackIndexingExpr::Create(ASTContext &Context,
SourceLocation EllipsisLoc,
SourceLocation RSquareLoc,
Expr *PackIdExpr, Expr *IndexExpr,
std::optional<int64_t> Index,
ArrayRef<Expr *> SubstitutedExprs) {
PackIndexingExpr *PackIndexingExpr::Create(
ASTContext &Context, SourceLocation EllipsisLoc, SourceLocation RSquareLoc,
Expr *PackIdExpr, Expr *IndexExpr, std::optional<int64_t> Index,
ArrayRef<Expr *> SubstitutedExprs, bool ExpandedToEmptyPack) {
QualType Type;
if (Index && !SubstitutedExprs.empty())
Type = SubstitutedExprs[*Index]->getType();
@@ -1679,8 +1677,9 @@ PackIndexingExpr *PackIndexingExpr::Create(ASTContext &Context,
void *Storage =
Context.Allocate(totalSizeToAlloc<Expr *>(SubstitutedExprs.size()));
return new (Storage) PackIndexingExpr(
Type, EllipsisLoc, RSquareLoc, PackIdExpr, IndexExpr, SubstitutedExprs);
return new (Storage)
PackIndexingExpr(Type, EllipsisLoc, RSquareLoc, PackIdExpr, IndexExpr,
SubstitutedExprs, ExpandedToEmptyPack);
}
NamedDecl *PackIndexingExpr::getPackDecl() const {

View File

@@ -1128,7 +1128,7 @@ Sema::BuildPackIndexingExpr(Expr *PackExpression, SourceLocation EllipsisLoc,
return PackIndexingExpr::Create(getASTContext(), EllipsisLoc, RSquareLoc,
PackExpression, IndexExpr, Index,
ExpandedExprs);
ExpandedExprs, EmptyPack);
}
TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(

View File

@@ -14967,7 +14967,7 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
return ExprError();
SmallVector<Expr *, 5> ExpandedExprs;
if (E->getExpressions().empty()) {
if (!E->expandsToEmptyPack() && E->getExpressions().empty()) {
Expr *Pattern = E->getPackIdExpression();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(E->getPackIdExpression(),
@@ -15021,9 +15021,7 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
return true;
ExpandedExprs.push_back(Out.get());
}
}
else {
} else if (!E->expandsToEmptyPack()) {
if (getDerived().TransformExprs(E->getExpressions().data(),
E->getExpressions().size(), false,
ExpandedExprs))

View File

@@ -2177,6 +2177,7 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
void ASTStmtReader::VisitPackIndexingExpr(PackIndexingExpr *E) {
VisitExpr(E);
E->TransformedExpressions = Record.readInt();
E->ExpandedToEmptyPack = Record.readInt();
E->EllipsisLoc = readSourceLocation();
E->RSquareLoc = readSourceLocation();
E->SubExprs[0] = Record.readStmt();

View File

@@ -2157,11 +2157,11 @@ void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
void ASTStmtWriter::VisitPackIndexingExpr(PackIndexingExpr *E) {
VisitExpr(E);
Record.push_back(E->TransformedExpressions);
Record.push_back(E->ExpandedToEmptyPack);
Record.AddSourceLocation(E->getEllipsisLoc());
Record.AddSourceLocation(E->getRSquareLoc());
Record.AddStmt(E->getPackIdExpression());
Record.AddStmt(E->getIndexExpr());
Record.push_back(E->TransformedExpressions);
for (Expr *Sub : E->getExpressions())
Record.AddStmt(Sub);
Code = serialization::EXPR_PACK_INDEXING;

View File

@@ -10,7 +10,11 @@ using Type = U...[I];
template <int I, auto...V>
constexpr auto Var = V...[I];
template <int I, auto...V>
decltype(V...[I]) foo() { return V...[I]; }
void fn1() {
using A = Type<1, int, long, double>;
constexpr auto V = Var<2, 0, 1, 42>;
foo<2, 0, 1, 42>();
}

View File

@@ -206,13 +206,17 @@ void test(auto...args){
template<int... args>
void test2(){
[&]<int idx>(){
using R = decltype( args...[idx] ) ;
}.template operator()<0>();
using R = decltype( args...[idx] ) ; // #test2-R
}.template operator()<0>(); // #test2-call
}
void f( ) {
test(1);
test2<1>();
test2();
// expected-error@#test2-R {{invalid index 0 for pack args of size 0}}
// expected-note@#test2-call {{requested here}}
// expected-note@-3 {{requested here}}
}