[Clang] Preserve partially substituted pack indexing type/expressions (#116782)
Substituting into pack indexing types/expressions can still result in unexpanded types/expressions, such as `PackIndexingType` or `PackIndexingExpr`. To handle these cases correctly, we should defer the pack size checks to the next round of transformation, when the patterns can be fully expanded. To that end, the `FullySubstituted` flag is now necessary for computing the dependencies of `PackIndexingExprs`. Conveniently, this flag can also represent the prior `ExpandsToEmpty` status with an additional emptiness check. Therefore, I converted all stored flags to use `FullySubstituted`. Fixes https://github.com/llvm/llvm-project/issues/116105
This commit is contained in:
@@ -714,6 +714,7 @@ Bug Fixes to C++ Support
|
||||
assumption if they also occur inside of a dependent lambda. (#GH114787)
|
||||
- Clang now uses valid deduced type locations when diagnosing functions with trailing return type
|
||||
missing placeholder return type. (#GH78694)
|
||||
- Fixed a bug where bounds of partially expanded pack indexing expressions were checked too early. (#GH116105)
|
||||
|
||||
Bug Fixes to AST Handling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -4390,17 +4390,17 @@ class PackIndexingExpr final
|
||||
unsigned TransformedExpressions : 31;
|
||||
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned ExpandedToEmptyPack : 1;
|
||||
unsigned FullySubstituted : 1;
|
||||
|
||||
PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
|
||||
SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr,
|
||||
ArrayRef<Expr *> SubstitutedExprs = {},
|
||||
bool ExpandedToEmptyPack = false)
|
||||
bool FullySubstituted = false)
|
||||
: Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
|
||||
EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
|
||||
SubExprs{PackIdExpr, IndexExpr},
|
||||
TransformedExpressions(SubstitutedExprs.size()),
|
||||
ExpandedToEmptyPack(ExpandedToEmptyPack) {
|
||||
FullySubstituted(FullySubstituted) {
|
||||
|
||||
auto *Exprs = getTrailingObjects<Expr *>();
|
||||
std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(),
|
||||
@@ -4424,12 +4424,16 @@ public:
|
||||
SourceLocation RSquareLoc, Expr *PackIdExpr,
|
||||
Expr *IndexExpr, std::optional<int64_t> Index,
|
||||
ArrayRef<Expr *> SubstitutedExprs = {},
|
||||
bool ExpandedToEmptyPack = false);
|
||||
bool FullySubstituted = false);
|
||||
static PackIndexingExpr *CreateDeserialized(ASTContext &Context,
|
||||
unsigned NumTransformedExprs);
|
||||
|
||||
bool isFullySubstituted() const { return FullySubstituted; }
|
||||
|
||||
/// Determine if the expression was expanded to empty.
|
||||
bool expandsToEmptyPack() const { return ExpandedToEmptyPack; }
|
||||
bool expandsToEmptyPack() const {
|
||||
return isFullySubstituted() && TransformedExpressions == 0;
|
||||
}
|
||||
|
||||
/// Determine the location of the 'sizeof' keyword.
|
||||
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
|
||||
|
||||
@@ -5922,12 +5922,12 @@ class PackIndexingType final
|
||||
unsigned Size : 31;
|
||||
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned ExpandsToEmptyPack : 1;
|
||||
unsigned FullySubstituted : 1;
|
||||
|
||||
protected:
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
PackIndexingType(const ASTContext &Context, QualType Canonical,
|
||||
QualType Pattern, Expr *IndexExpr, bool ExpandsToEmptyPack,
|
||||
QualType Pattern, Expr *IndexExpr, bool FullySubstituted,
|
||||
ArrayRef<QualType> Expansions = {});
|
||||
|
||||
public:
|
||||
@@ -5951,7 +5951,9 @@ public:
|
||||
|
||||
bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; }
|
||||
|
||||
bool expandsToEmptyPack() const { return ExpandsToEmptyPack; }
|
||||
bool isFullySubstituted() const { return FullySubstituted; }
|
||||
|
||||
bool expandsToEmptyPack() const { return isFullySubstituted() && Size == 0; }
|
||||
|
||||
ArrayRef<QualType> getExpansions() const {
|
||||
return {getExpansionsPtr(), Size};
|
||||
@@ -5965,10 +5967,10 @@ public:
|
||||
if (hasSelectedType())
|
||||
getSelectedType().Profile(ID);
|
||||
else
|
||||
Profile(ID, Context, getPattern(), getIndexExpr(), expandsToEmptyPack());
|
||||
Profile(ID, Context, getPattern(), getIndexExpr(), isFullySubstituted());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
|
||||
QualType Pattern, Expr *E, bool ExpandsToEmptyPack);
|
||||
QualType Pattern, Expr *E, bool FullySubstituted);
|
||||
|
||||
private:
|
||||
const QualType *getExpansionsPtr() const {
|
||||
|
||||
@@ -473,12 +473,12 @@ let Class = PackIndexingType in {
|
||||
def : Property<"indexExpression", ExprRef> {
|
||||
let Read = [{ node->getIndexExpr() }];
|
||||
}
|
||||
def : Property<"expandsToEmptyPack", Bool> {
|
||||
let Read = [{ node->expandsToEmptyPack() }];
|
||||
def : Property<"isFullySubstituted", Bool> {
|
||||
let Read = [{ node->isFullySubstituted() }];
|
||||
}
|
||||
|
||||
def : Creator<[{
|
||||
return ctx.getPackIndexingType(pattern, indexExpression, expandsToEmptyPack);
|
||||
return ctx.getPackIndexingType(pattern, indexExpression, isFullySubstituted);
|
||||
}]>;
|
||||
}
|
||||
|
||||
|
||||
@@ -14257,7 +14257,7 @@ public:
|
||||
SourceLocation EllipsisLoc, Expr *IndexExpr,
|
||||
SourceLocation RSquareLoc,
|
||||
ArrayRef<Expr *> ExpandedExprs = {},
|
||||
bool EmptyPack = false);
|
||||
bool FullySubstituted = false);
|
||||
|
||||
/// Handle a C++1z fold-expression: ( expr op ... op expr ).
|
||||
ExprResult ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
|
||||
|
||||
@@ -6223,13 +6223,11 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
|
||||
ArrayRef<QualType> Expansions,
|
||||
int Index) const {
|
||||
QualType Canonical;
|
||||
bool ExpandsToEmptyPack = FullySubstituted && Expansions.empty();
|
||||
if (FullySubstituted && Index != -1) {
|
||||
Canonical = getCanonicalType(Expansions[Index]);
|
||||
} else {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
PackIndexingType::Profile(ID, *this, Pattern, IndexExpr,
|
||||
ExpandsToEmptyPack);
|
||||
PackIndexingType::Profile(ID, *this, Pattern, IndexExpr, FullySubstituted);
|
||||
void *InsertPos = nullptr;
|
||||
PackIndexingType *Canon =
|
||||
DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
@@ -6238,7 +6236,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
|
||||
PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
|
||||
TypeAlignment);
|
||||
Canon = new (Mem) PackIndexingType(*this, QualType(), Pattern, IndexExpr,
|
||||
ExpandsToEmptyPack, Expansions);
|
||||
FullySubstituted, Expansions);
|
||||
DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
|
||||
}
|
||||
Canonical = QualType(Canon, 0);
|
||||
@@ -6248,7 +6246,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
|
||||
Allocate(PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
|
||||
TypeAlignment);
|
||||
auto *T = new (Mem) PackIndexingType(*this, Canonical, Pattern, IndexExpr,
|
||||
ExpandsToEmptyPack, Expansions);
|
||||
FullySubstituted, Expansions);
|
||||
Types.push_back(T);
|
||||
return QualType(T, 0);
|
||||
}
|
||||
|
||||
@@ -388,9 +388,8 @@ ExprDependence clang::computeDependence(PackIndexingExpr *E) {
|
||||
ExprDependence::Instantiation;
|
||||
|
||||
ArrayRef<Expr *> Exprs = E->getExpressions();
|
||||
if (Exprs.empty())
|
||||
if (Exprs.empty() || !E->isFullySubstituted())
|
||||
D |= PatternDep | ExprDependence::Instantiation;
|
||||
|
||||
else if (!E->getIndexExpr()->isInstantiationDependent()) {
|
||||
std::optional<unsigned> Index = E->getSelectedIndex();
|
||||
assert(Index && *Index < Exprs.size() && "pack index out of bound");
|
||||
|
||||
@@ -1717,9 +1717,9 @@ NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
|
||||
PackIndexingExpr *PackIndexingExpr::Create(
|
||||
ASTContext &Context, SourceLocation EllipsisLoc, SourceLocation RSquareLoc,
|
||||
Expr *PackIdExpr, Expr *IndexExpr, std::optional<int64_t> Index,
|
||||
ArrayRef<Expr *> SubstitutedExprs, bool ExpandedToEmptyPack) {
|
||||
ArrayRef<Expr *> SubstitutedExprs, bool FullySubstituted) {
|
||||
QualType Type;
|
||||
if (Index && !SubstitutedExprs.empty())
|
||||
if (Index && FullySubstituted && !SubstitutedExprs.empty())
|
||||
Type = SubstitutedExprs[*Index]->getType();
|
||||
else
|
||||
Type = Context.DependentTy;
|
||||
@@ -1728,7 +1728,7 @@ PackIndexingExpr *PackIndexingExpr::Create(
|
||||
Context.Allocate(totalSizeToAlloc<Expr *>(SubstitutedExprs.size()));
|
||||
return new (Storage)
|
||||
PackIndexingExpr(Type, EllipsisLoc, RSquareLoc, PackIdExpr, IndexExpr,
|
||||
SubstitutedExprs, ExpandedToEmptyPack);
|
||||
SubstitutedExprs, FullySubstituted);
|
||||
}
|
||||
|
||||
NamedDecl *PackIndexingExpr::getPackDecl() const {
|
||||
|
||||
@@ -4031,12 +4031,12 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
|
||||
PackIndexingType::PackIndexingType(const ASTContext &Context,
|
||||
QualType Canonical, QualType Pattern,
|
||||
Expr *IndexExpr, bool ExpandsToEmptyPack,
|
||||
Expr *IndexExpr, bool FullySubstituted,
|
||||
ArrayRef<QualType> Expansions)
|
||||
: Type(PackIndexing, Canonical,
|
||||
computeDependence(Pattern, IndexExpr, Expansions)),
|
||||
Context(Context), Pattern(Pattern), IndexExpr(IndexExpr),
|
||||
Size(Expansions.size()), ExpandsToEmptyPack(ExpandsToEmptyPack) {
|
||||
Size(Expansions.size()), FullySubstituted(FullySubstituted) {
|
||||
|
||||
std::uninitialized_copy(Expansions.begin(), Expansions.end(),
|
||||
getTrailingObjects<QualType>());
|
||||
@@ -4081,10 +4081,10 @@ PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr,
|
||||
|
||||
void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
const ASTContext &Context, QualType Pattern,
|
||||
Expr *E, bool ExpandsToEmptyPack) {
|
||||
Expr *E, bool FullySubstituted) {
|
||||
Pattern.Profile(ID);
|
||||
E->Profile(ID, Context, true);
|
||||
ID.AddBoolean(ExpandsToEmptyPack);
|
||||
ID.AddBoolean(FullySubstituted);
|
||||
}
|
||||
|
||||
UnaryTransformType::UnaryTransformType(QualType BaseType,
|
||||
|
||||
@@ -1157,10 +1157,12 @@ ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
|
||||
return Res;
|
||||
}
|
||||
|
||||
ExprResult
|
||||
Sema::BuildPackIndexingExpr(Expr *PackExpression, SourceLocation EllipsisLoc,
|
||||
Expr *IndexExpr, SourceLocation RSquareLoc,
|
||||
ArrayRef<Expr *> ExpandedExprs, bool EmptyPack) {
|
||||
ExprResult Sema::BuildPackIndexingExpr(Expr *PackExpression,
|
||||
SourceLocation EllipsisLoc,
|
||||
Expr *IndexExpr,
|
||||
SourceLocation RSquareLoc,
|
||||
ArrayRef<Expr *> ExpandedExprs,
|
||||
bool FullySubstituted) {
|
||||
|
||||
std::optional<int64_t> Index;
|
||||
if (!IndexExpr->isInstantiationDependent()) {
|
||||
@@ -1174,8 +1176,8 @@ Sema::BuildPackIndexingExpr(Expr *PackExpression, SourceLocation EllipsisLoc,
|
||||
IndexExpr = Res.get();
|
||||
}
|
||||
|
||||
if (Index && (!ExpandedExprs.empty() || EmptyPack)) {
|
||||
if (*Index < 0 || EmptyPack || *Index >= int64_t(ExpandedExprs.size())) {
|
||||
if (Index && FullySubstituted) {
|
||||
if (*Index < 0 || *Index >= int64_t(ExpandedExprs.size())) {
|
||||
Diag(PackExpression->getBeginLoc(), diag::err_pack_index_out_of_bound)
|
||||
<< *Index << PackExpression << ExpandedExprs.size();
|
||||
return ExprError();
|
||||
@@ -1184,7 +1186,7 @@ Sema::BuildPackIndexingExpr(Expr *PackExpression, SourceLocation EllipsisLoc,
|
||||
|
||||
return PackIndexingExpr::Create(getASTContext(), EllipsisLoc, RSquareLoc,
|
||||
PackExpression, IndexExpr, Index,
|
||||
ExpandedExprs, EmptyPack);
|
||||
ExpandedExprs, FullySubstituted);
|
||||
}
|
||||
|
||||
TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(
|
||||
|
||||
@@ -3670,10 +3670,10 @@ public:
|
||||
SourceLocation RSquareLoc,
|
||||
Expr *PackIdExpression, Expr *IndexExpr,
|
||||
ArrayRef<Expr *> ExpandedExprs,
|
||||
bool EmptyPack = false) {
|
||||
bool FullySubstituted = false) {
|
||||
return getSema().BuildPackIndexingExpr(PackIdExpression, EllipsisLoc,
|
||||
IndexExpr, RSquareLoc, ExpandedExprs,
|
||||
EmptyPack);
|
||||
FullySubstituted);
|
||||
}
|
||||
|
||||
/// Build a new expression representing a call to a source location
|
||||
@@ -6769,6 +6769,7 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
|
||||
if (Out.isNull())
|
||||
return QualType();
|
||||
SubtitutedTypes.push_back(Out);
|
||||
FullySubstituted &= !Out->containsUnexpandedParameterPack();
|
||||
}
|
||||
// If we're supposed to retain a pack expansion, do so by temporarily
|
||||
// forgetting the partially-substituted parameter pack.
|
||||
@@ -15581,6 +15582,7 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
|
||||
}
|
||||
|
||||
SmallVector<Expr *, 5> ExpandedExprs;
|
||||
bool FullySubstituted = true;
|
||||
if (!E->expandsToEmptyPack() && E->getExpressions().empty()) {
|
||||
Expr *Pattern = E->getPackIdExpression();
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
@@ -15605,7 +15607,7 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
|
||||
return ExprError();
|
||||
return getDerived().RebuildPackIndexingExpr(
|
||||
E->getEllipsisLoc(), E->getRSquareLoc(), Pack.get(), IndexExpr.get(),
|
||||
{});
|
||||
{}, /*FullySubstituted=*/false);
|
||||
}
|
||||
for (unsigned I = 0; I != *NumExpansions; ++I) {
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
|
||||
@@ -15617,6 +15619,7 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
|
||||
OrigNumExpansions);
|
||||
if (Out.isInvalid())
|
||||
return true;
|
||||
FullySubstituted = false;
|
||||
}
|
||||
ExpandedExprs.push_back(Out.get());
|
||||
}
|
||||
@@ -15633,6 +15636,7 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
|
||||
OrigNumExpansions);
|
||||
if (Out.isInvalid())
|
||||
return true;
|
||||
FullySubstituted = false;
|
||||
ExpandedExprs.push_back(Out.get());
|
||||
}
|
||||
} else if (!E->expandsToEmptyPack()) {
|
||||
@@ -15644,8 +15648,7 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
|
||||
|
||||
return getDerived().RebuildPackIndexingExpr(
|
||||
E->getEllipsisLoc(), E->getRSquareLoc(), E->getPackIdExpression(),
|
||||
IndexExpr.get(), ExpandedExprs,
|
||||
/*EmptyPack=*/ExpandedExprs.size() == 0);
|
||||
IndexExpr.get(), ExpandedExprs, FullySubstituted);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
||||
@@ -2191,7 +2191,7 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
|
||||
void ASTStmtReader::VisitPackIndexingExpr(PackIndexingExpr *E) {
|
||||
VisitExpr(E);
|
||||
E->TransformedExpressions = Record.readInt();
|
||||
E->ExpandedToEmptyPack = Record.readInt();
|
||||
E->FullySubstituted = Record.readInt();
|
||||
E->EllipsisLoc = readSourceLocation();
|
||||
E->RSquareLoc = readSourceLocation();
|
||||
E->SubExprs[0] = Record.readStmt();
|
||||
|
||||
@@ -2191,7 +2191,7 @@ void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
|
||||
void ASTStmtWriter::VisitPackIndexingExpr(PackIndexingExpr *E) {
|
||||
VisitExpr(E);
|
||||
Record.push_back(E->TransformedExpressions);
|
||||
Record.push_back(E->ExpandedToEmptyPack);
|
||||
Record.push_back(E->FullySubstituted);
|
||||
Record.AddSourceLocation(E->getEllipsisLoc());
|
||||
Record.AddSourceLocation(E->getRSquareLoc());
|
||||
Record.AddStmt(E->getPackIdExpression());
|
||||
|
||||
@@ -271,3 +271,37 @@ void f() {
|
||||
}
|
||||
|
||||
} // namespace GH105903
|
||||
|
||||
namespace GH116105 {
|
||||
|
||||
template <unsigned long Np, class... Ts> using pack_type = Ts...[Np];
|
||||
|
||||
template <unsigned long Np, auto... Ts> using pack_expr = decltype(Ts...[Np]);
|
||||
|
||||
template <class...> struct types;
|
||||
|
||||
template <class, long... Is> struct indices;
|
||||
|
||||
template <class> struct repack;
|
||||
|
||||
template <long... Idx> struct repack<indices<long, Idx...>> {
|
||||
template <class... Ts>
|
||||
using pack_type_alias = types<pack_type<Idx, Ts...>...>;
|
||||
|
||||
template <class... Ts>
|
||||
using pack_expr_alias = types<pack_expr<Idx, Ts{}...>...>;
|
||||
};
|
||||
|
||||
template <class... Args> struct mdispatch_ {
|
||||
using Idx = __make_integer_seq<indices, long, sizeof...(Args)>;
|
||||
|
||||
static_assert(__is_same(
|
||||
typename repack<Idx>::template pack_type_alias<Args...>, types<Args...>));
|
||||
|
||||
static_assert(__is_same(
|
||||
typename repack<Idx>::template pack_expr_alias<Args...>, types<Args...>));
|
||||
};
|
||||
|
||||
mdispatch_<int, int> d;
|
||||
|
||||
} // namespace GH116105
|
||||
|
||||
Reference in New Issue
Block a user