Skip to content

Commit d3be2f2

Browse files
committed
[Clang][C++26] Implement Pack Indexing (P2662R3).
https://isocpp.org/files/papers/P2662R3.pdf Because there is a slight chance the syntax might change slightly (see https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2994r0.html), the feature is not exposed in other language modes.
1 parent f8e8530 commit d3be2f2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1435
-17
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ C++2c Feature Support
182182
This is applied to both C++ standard attributes, and other attributes supported by Clang.
183183
This completes the implementation of `P2361R6 Unevaluated Strings <https://wg21.link/P2361R6>`_
184184

185+
- Implemented `P2662R3 Pack Indexing <https://wg21.link/P2662R3>`_.
186+
185187

186188
Resolutions to C++ Defect Reports
187189
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang-c/Index.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1685,7 +1685,12 @@ enum CXCursorKind {
16851685
*/
16861686
CXCursor_CXXParenListInitExpr = 155,
16871687

1688-
CXCursor_LastExpr = CXCursor_CXXParenListInitExpr,
1688+
/**
1689+
* Represents a C++26 pack indexing expression
1690+
*/
1691+
CXCursor_PackIndexingExpr = 156,
1692+
1693+
CXCursor_LastExpr = CXCursor_PackIndexingExpr,
16891694

16901695
/* Statements */
16911696
CXCursor_FirstStmt = 200,

clang/include/clang/AST/ASTContext.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
214214
DependentTypeOfExprTypes;
215215
mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
216216
DependentDecltypeTypes;
217+
218+
mutable llvm::FoldingSet<PackIndexingType> DependentPackIndexingTypes;
219+
217220
mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
218221
mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;
219222
mutable llvm::FoldingSet<SubstTemplateTypeParmType>
@@ -1713,6 +1716,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
17131716
/// C++11 decltype.
17141717
QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
17151718

1719+
QualType getPackIndexingType(QualType Pattern, Expr *IndexExpr,
1720+
bool FullyExpanded = false,
1721+
ArrayRef<QualType> Expansions = {},
1722+
int Index = -1) const;
1723+
17161724
/// Unary type transforms
17171725
QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
17181726
UnaryTransformType::UTTKind UKind) const;

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,12 @@ class ASTNodeTraverser
385385
void VisitDecltypeType(const DecltypeType *T) {
386386
Visit(T->getUnderlyingExpr());
387387
}
388+
389+
void VisitPackIndexingType(const PackIndexingType *T) {
390+
Visit(T->getPattern());
391+
Visit(T->getIndexExpr());
392+
}
393+
388394
void VisitUnaryTransformType(const UnaryTransformType *T) {
389395
Visit(T->getBaseType());
390396
}

clang/include/clang/AST/ExprCXX.h

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4344,6 +4344,112 @@ class SizeOfPackExpr final
43444344
}
43454345
};
43464346

4347+
class PackIndexingExpr final
4348+
: public Expr,
4349+
private llvm::TrailingObjects<PackIndexingExpr, Expr *> {
4350+
friend class ASTStmtReader;
4351+
friend class ASTStmtWriter;
4352+
friend TrailingObjects;
4353+
4354+
SourceLocation EllipsisLoc;
4355+
4356+
// The location of the closing bracket
4357+
SourceLocation RSquareLoc;
4358+
4359+
// The pack being indexed, followed by the index
4360+
Stmt *SubExprs[2];
4361+
4362+
// The evaluated index
4363+
std::optional<int64_t> Index;
4364+
4365+
size_t TransformedExpressions;
4366+
4367+
PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
4368+
SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr,
4369+
std::optional<int64_t> Index = std::nullopt,
4370+
ArrayRef<Expr *> SubstitutedExprs = {})
4371+
: Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
4372+
EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
4373+
SubExprs{PackIdExpr, IndexExpr}, Index(Index),
4374+
TransformedExpressions(SubstitutedExprs.size()) {
4375+
4376+
auto *Exprs = getTrailingObjects<Expr *>();
4377+
std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(),
4378+
Exprs);
4379+
4380+
ExprDependence D = IndexExpr->getDependence();
4381+
if (SubstitutedExprs.empty())
4382+
D |= (PackIdExpr->getDependence() |
4383+
ExprDependence::TypeValueInstantiation) &
4384+
~ExprDependence::UnexpandedPack;
4385+
else if (!IndexExpr->isValueDependent()) {
4386+
assert(Index && *Index < int64_t(SubstitutedExprs.size()) &&
4387+
"pack index out of bound");
4388+
D |= SubstitutedExprs[*Index]->getDependence();
4389+
setValueKind(SubstitutedExprs[*Index]->getValueKind());
4390+
}
4391+
setDependence(D);
4392+
}
4393+
4394+
/// Create an empty expression.
4395+
PackIndexingExpr(EmptyShell Empty) : Expr(PackIndexingExprClass, Empty) {}
4396+
4397+
unsigned numTrailingObjects(OverloadToken<Expr *>) const {
4398+
return TransformedExpressions;
4399+
}
4400+
4401+
public:
4402+
static PackIndexingExpr *Create(ASTContext &Context,
4403+
SourceLocation EllipsisLoc,
4404+
SourceLocation RSquareLoc, Expr *PackIdExpr,
4405+
Expr *IndexExpr,
4406+
std::optional<int64_t> Index = std::nullopt,
4407+
ArrayRef<Expr *> SubstitutedExprs = {});
4408+
static PackIndexingExpr *CreateDeserialized(ASTContext &Context,
4409+
unsigned NumTransformedExprs);
4410+
4411+
/// Determine the location of the 'sizeof' keyword.
4412+
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
4413+
4414+
/// Determine the location of the parameter pack.
4415+
SourceLocation getPackLoc() const { return SubExprs[0]->getBeginLoc(); }
4416+
4417+
/// Determine the location of the right parenthesis.
4418+
SourceLocation getRSquareLoc() const { return RSquareLoc; }
4419+
4420+
SourceLocation getBeginLoc() const LLVM_READONLY { return getPackLoc(); }
4421+
SourceLocation getEndLoc() const LLVM_READONLY { return RSquareLoc; }
4422+
4423+
Expr *getPackIdExpression() const { return cast<Expr>(SubExprs[0]); }
4424+
4425+
NamedDecl *getPackDecl() const;
4426+
4427+
Expr *getIndexExpr() const { return cast<Expr>(SubExprs[1]); }
4428+
4429+
Expr *getSelectedExpr() const {
4430+
assert(Index && !isInstantiationDependent() &&
4431+
"extracting the indexed expression of a dependant pack");
4432+
return getTrailingObjects<Expr *>()[*Index];
4433+
}
4434+
4435+
llvm::ArrayRef<Expr *> getExpressions() const {
4436+
if (TransformedExpressions == 0)
4437+
return {};
4438+
return {getTrailingObjects<Expr *>(), TransformedExpressions};
4439+
}
4440+
4441+
static bool classof(const Stmt *T) {
4442+
return T->getStmtClass() == PackIndexingExprClass;
4443+
}
4444+
4445+
// Iterators
4446+
child_range children() { return child_range(SubExprs, SubExprs + 2); }
4447+
4448+
const_child_range children() const {
4449+
return const_child_range(SubExprs, SubExprs + 2);
4450+
}
4451+
};
4452+
43474453
/// Represents a reference to a non-type template parameter
43484454
/// that has been substituted with a template argument.
43494455
class SubstNonTypeTemplateParmExpr : public Expr {

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,11 @@ DEF_TRAVERSE_TYPE(TypeOfType, { TRY_TO(TraverseType(T->getUnmodifiedType())); })
10631063
DEF_TRAVERSE_TYPE(DecltypeType,
10641064
{ TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
10651065

1066+
DEF_TRAVERSE_TYPE(PackIndexingType, {
1067+
TRY_TO(TraverseType(T->getPattern()));
1068+
TRY_TO(TraverseStmt(T->getIndexExpr()));
1069+
})
1070+
10661071
DEF_TRAVERSE_TYPE(UnaryTransformType, {
10671072
TRY_TO(TraverseType(T->getBaseType()));
10681073
TRY_TO(TraverseType(T->getUnderlyingType()));
@@ -1341,6 +1346,11 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
13411346
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
13421347
})
13431348

1349+
DEF_TRAVERSE_TYPELOC(PackIndexingType, {
1350+
TRY_TO(TraverseType(TL.getPattern()));
1351+
TRY_TO(TraverseStmt(TL.getTypePtr()->getIndexExpr()));
1352+
})
1353+
13441354
DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
13451355
TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
13461356
})
@@ -2857,6 +2867,7 @@ DEF_TRAVERSE_STMT(CompoundAssignOperator, {})
28572867
DEF_TRAVERSE_STMT(CXXNoexceptExpr, {})
28582868
DEF_TRAVERSE_STMT(PackExpansionExpr, {})
28592869
DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
2870+
DEF_TRAVERSE_STMT(PackIndexingExpr, {})
28602871
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
28612872
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
28622873
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})

clang/include/clang/AST/Type.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4884,6 +4884,72 @@ class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
48844884
Expr *E);
48854885
};
48864886

4887+
class PackIndexingType final
4888+
: public Type,
4889+
public llvm::FoldingSetNode,
4890+
private llvm::TrailingObjects<PackIndexingType, QualType> {
4891+
friend TrailingObjects;
4892+
4893+
const ASTContext &Context;
4894+
QualType Pattern;
4895+
Expr *IndexExpr;
4896+
4897+
unsigned Size;
4898+
int Index = -1;
4899+
4900+
protected:
4901+
friend class ASTContext; // ASTContext creates these.
4902+
PackIndexingType(const ASTContext &Context, QualType Canonical,
4903+
QualType Pattern, Expr *IndexExpr,
4904+
ArrayRef<QualType> Expansions = {}, int Index = -1);
4905+
4906+
public:
4907+
Expr *getIndexExpr() const { return IndexExpr; }
4908+
QualType getPattern() const { return Pattern; }
4909+
4910+
bool isSugared() const { return hasSelectedType(); }
4911+
4912+
QualType desugar() const {
4913+
if (hasSelectedType())
4914+
return getSelectedType();
4915+
return QualType(this, 0);
4916+
}
4917+
4918+
QualType getSelectedType() const {
4919+
assert(hasSelectedType() && "Type is dependant");
4920+
return *(getExpansionsPtr() + Index);
4921+
}
4922+
4923+
bool hasSelectedType() const { return Index != -1 && !isDependentType(); }
4924+
4925+
ArrayRef<QualType> getExpansions() const {
4926+
return {getExpansionsPtr(), Size};
4927+
}
4928+
4929+
static bool classof(const Type *T) {
4930+
return T->getTypeClass() == PackIndexing;
4931+
}
4932+
4933+
void Profile(llvm::FoldingSetNodeID &ID) {
4934+
if (hasSelectedType())
4935+
getSelectedType().Profile(ID);
4936+
else
4937+
Profile(ID, Context, getPattern(), getIndexExpr());
4938+
}
4939+
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
4940+
QualType Pattern, Expr *E);
4941+
4942+
private:
4943+
const QualType *getExpansionsPtr() const {
4944+
return getTrailingObjects<QualType>();
4945+
}
4946+
4947+
static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr,
4948+
ArrayRef<QualType> Expansions = {});
4949+
4950+
unsigned numTrailingObjects(OverloadToken<QualType>) const { return Size; }
4951+
};
4952+
48874953
/// A unary type transform, which is a type constructed from another.
48884954
class UnaryTransformType : public Type {
48894955
public:

clang/include/clang/AST/TypeLoc.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,6 +2055,34 @@ class DecltypeTypeLoc
20552055
}
20562056
};
20572057

2058+
struct PackIndexingTypeLocInfo {
2059+
SourceLocation EllipsisLoc;
2060+
};
2061+
2062+
class PackIndexingTypeLoc
2063+
: public ConcreteTypeLoc<UnqualTypeLoc, PackIndexingTypeLoc,
2064+
PackIndexingType, PackIndexingTypeLocInfo> {
2065+
2066+
public:
2067+
Expr *getIndexExpr() const { return getTypePtr()->getIndexExpr(); }
2068+
QualType getPattern() const { return getTypePtr()->getPattern(); }
2069+
2070+
SourceLocation getEllipsisLoc() const { return getLocalData()->EllipsisLoc; }
2071+
void setEllipsisLoc(SourceLocation Loc) { getLocalData()->EllipsisLoc = Loc; }
2072+
2073+
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
2074+
setEllipsisLoc(Loc);
2075+
}
2076+
2077+
TypeLoc getPatternLoc() const { return getInnerTypeLoc(); }
2078+
2079+
QualType getInnerType() const { return this->getTypePtr()->getPattern(); }
2080+
2081+
SourceRange getLocalSourceRange() const {
2082+
return SourceRange(getEllipsisLoc(), getEllipsisLoc());
2083+
}
2084+
};
2085+
20582086
struct UnaryTransformTypeLocInfo {
20592087
// FIXME: While there's only one unary transform right now, future ones may
20602088
// need different representations

clang/include/clang/AST/TypeProperties.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,20 @@ let Class = DecltypeType in {
433433
}]>;
434434
}
435435

436+
let Class = PackIndexingType in {
437+
def : Property<"pattern", QualType> {
438+
let Read = [{ node->getPattern() }];
439+
}
440+
def : Property<"indexExpression", ExprRef> {
441+
let Read = [{ node->getIndexExpr() }];
442+
}
443+
444+
def : Creator<[{
445+
return ctx.getPackIndexingType(pattern, indexExpression);
446+
}]>;
447+
}
448+
449+
436450
let Class = UnaryTransformType in {
437451
def : Property<"baseType", QualType> {
438452
let Read = [{ node->getBaseType() }];

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5681,9 +5681,12 @@ def err_function_parameter_pack_without_parameter_packs : Error<
56815681
def err_ellipsis_in_declarator_not_parameter : Error<
56825682
"only function and template parameters can be parameter packs">;
56835683

5684-
def err_sizeof_pack_no_pack_name : Error<
5684+
def err_expected_name_of_pack : Error<
56855685
"%0 does not refer to the name of a parameter pack">;
56865686

5687+
def err_pack_index_out_of_bound : Error<
5688+
"%0 is not a valid index for pack %1 of size %2">;
5689+
56875690
def err_fold_expression_packs_both_sides : Error<
56885691
"binary fold expression has unexpanded parameter packs in both operands">;
56895692
def err_fold_expression_empty : Error<

clang/include/clang/Basic/Specifiers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ namespace clang {
9494
TST_auto_type, // __auto_type extension
9595
TST_unknown_anytype, // __unknown_anytype extension
9696
TST_atomic, // C11 _Atomic
97+
TST_indexed_typename_pack,
9798
#define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types
9899
#include "clang/Basic/OpenCLImageTypes.def"
99100
TST_error // erroneous type

clang/include/clang/Basic/StmtNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ def UnresolvedMemberExpr : StmtNode<OverloadExpr>;
154154
def CXXNoexceptExpr : StmtNode<Expr>;
155155
def PackExpansionExpr : StmtNode<Expr>;
156156
def SizeOfPackExpr : StmtNode<Expr>;
157+
def PackIndexingExpr : StmtNode<Expr>;
157158
def SubstNonTypeTemplateParmExpr : StmtNode<Expr>;
158159
def SubstNonTypeTemplateParmPackExpr : StmtNode<Expr>;
159160
def FunctionParmPackExpr : StmtNode<Expr>;

clang/include/clang/Basic/TokenKinds.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,8 @@ ANNOTATION(primary_expr) // annotation for a primary expression, used when
836836
// message send
837837
ANNOTATION(decltype) // annotation for a decltype expression,
838838
// e.g., "decltype(foo.bar())"
839+
ANNOTATION(indexed_pack_type) // annotation for an indexed pack of type,
840+
// e.g., "T...[expr]"
839841

840842
// Annotation for #pragma unused(...)
841843
// For each argument inside the parentheses the pragma handler will produce

clang/include/clang/Basic/TypeNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ def InjectedClassNameType : TypeNode<Type>, AlwaysDependent, LeafType;
103103
def DependentNameType : TypeNode<Type>, AlwaysDependent;
104104
def DependentTemplateSpecializationType : TypeNode<Type>, AlwaysDependent;
105105
def PackExpansionType : TypeNode<Type>, AlwaysDependent;
106+
def PackIndexingType : TypeNode<Type>, NeverCanonicalUnlessDependent;
106107
def ObjCTypeParamType : TypeNode<Type>, NeverCanonical;
107108
def ObjCObjectType : TypeNode<Type>;
108109
def ObjCInterfaceType : TypeNode<ObjCObjectType>, LeafType;

0 commit comments

Comments
 (0)