Skip to content

Commit ad1a65f

Browse files
authored
[Clang][C++26] Implement Pack Indexing (P2662R3). (#72644)
Implements https://isocpp.org/files/papers/P2662R3.pdf The feature is exposed as an extension in older language modes. Mangling is not yet supported and that is something we will have to do before release.
1 parent 1f13203 commit ad1a65f

Some content is hidden

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

76 files changed

+1520
-29
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ C++23 Feature Support
6868
C++2c Feature Support
6969
^^^^^^^^^^^^^^^^^^^^^
7070

71+
- Implemented `P2662R3 Pack Indexing <https://wg21.link/P2662R3>`_.
72+
73+
7174
Resolutions to C++ Defect Reports
7275
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7376

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 FullySubstituted = 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/ComputeDependence.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class ArrayTypeTraitExpr;
6363
class ExpressionTraitExpr;
6464
class CXXNoexceptExpr;
6565
class PackExpansionExpr;
66+
class PackIndexingExpr;
6667
class SubstNonTypeTemplateParmExpr;
6768
class CoroutineSuspendExpr;
6869
class DependentCoawaitExpr;
@@ -150,6 +151,7 @@ ExprDependence computeDependence(ArrayTypeTraitExpr *E);
150151
ExprDependence computeDependence(ExpressionTraitExpr *E);
151152
ExprDependence computeDependence(CXXNoexceptExpr *E, CanThrowResult CT);
152153
ExprDependence computeDependence(PackExpansionExpr *E);
154+
ExprDependence computeDependence(PackIndexingExpr *E);
153155
ExprDependence computeDependence(SubstNonTypeTemplateParmExpr *E);
154156
ExprDependence computeDependence(CoroutineSuspendExpr *E);
155157
ExprDependence computeDependence(DependentCoawaitExpr *E);

clang/include/clang/AST/ExprCXX.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4331,6 +4331,105 @@ class SizeOfPackExpr final
43314331
}
43324332
};
43334333

4334+
class PackIndexingExpr final
4335+
: public Expr,
4336+
private llvm::TrailingObjects<PackIndexingExpr, Expr *> {
4337+
friend class ASTStmtReader;
4338+
friend class ASTStmtWriter;
4339+
friend TrailingObjects;
4340+
4341+
SourceLocation EllipsisLoc;
4342+
4343+
// The location of the closing bracket
4344+
SourceLocation RSquareLoc;
4345+
4346+
// The pack being indexed, followed by the index
4347+
Stmt *SubExprs[2];
4348+
4349+
size_t TransformedExpressions;
4350+
4351+
PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
4352+
SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr,
4353+
ArrayRef<Expr *> SubstitutedExprs = {})
4354+
: Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
4355+
EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
4356+
SubExprs{PackIdExpr, IndexExpr},
4357+
TransformedExpressions(SubstitutedExprs.size()) {
4358+
4359+
auto *Exprs = getTrailingObjects<Expr *>();
4360+
std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(),
4361+
Exprs);
4362+
4363+
setDependence(computeDependence(this));
4364+
if (!isInstantiationDependent())
4365+
setValueKind(getSelectedExpr()->getValueKind());
4366+
}
4367+
4368+
/// Create an empty expression.
4369+
PackIndexingExpr(EmptyShell Empty) : Expr(PackIndexingExprClass, Empty) {}
4370+
4371+
unsigned numTrailingObjects(OverloadToken<Expr *>) const {
4372+
return TransformedExpressions;
4373+
}
4374+
4375+
public:
4376+
static PackIndexingExpr *Create(ASTContext &Context,
4377+
SourceLocation EllipsisLoc,
4378+
SourceLocation RSquareLoc, Expr *PackIdExpr,
4379+
Expr *IndexExpr, std::optional<int64_t> Index,
4380+
ArrayRef<Expr *> SubstitutedExprs = {});
4381+
static PackIndexingExpr *CreateDeserialized(ASTContext &Context,
4382+
unsigned NumTransformedExprs);
4383+
4384+
/// Determine the location of the 'sizeof' keyword.
4385+
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
4386+
4387+
/// Determine the location of the parameter pack.
4388+
SourceLocation getPackLoc() const { return SubExprs[0]->getBeginLoc(); }
4389+
4390+
/// Determine the location of the right parenthesis.
4391+
SourceLocation getRSquareLoc() const { return RSquareLoc; }
4392+
4393+
SourceLocation getBeginLoc() const LLVM_READONLY { return getPackLoc(); }
4394+
SourceLocation getEndLoc() const LLVM_READONLY { return RSquareLoc; }
4395+
4396+
Expr *getPackIdExpression() const { return cast<Expr>(SubExprs[0]); }
4397+
4398+
NamedDecl *getPackDecl() const;
4399+
4400+
Expr *getIndexExpr() const { return cast<Expr>(SubExprs[1]); }
4401+
4402+
std::optional<unsigned> getSelectedIndex() const {
4403+
if (isInstantiationDependent())
4404+
return std::nullopt;
4405+
ConstantExpr *CE = cast<ConstantExpr>(getIndexExpr());
4406+
auto Index = CE->getResultAsAPSInt();
4407+
assert(Index.isNonNegative() && "Invalid index");
4408+
return static_cast<unsigned>(Index.getExtValue());
4409+
}
4410+
4411+
Expr *getSelectedExpr() const {
4412+
std::optional<unsigned> Index = getSelectedIndex();
4413+
assert(Index && "extracting the indexed expression of a dependant pack");
4414+
return getTrailingObjects<Expr *>()[*Index];
4415+
}
4416+
4417+
ArrayRef<Expr *> getExpressions() const {
4418+
return {getTrailingObjects<Expr *>(), TransformedExpressions};
4419+
}
4420+
4421+
static bool classof(const Stmt *T) {
4422+
return T->getStmtClass() == PackIndexingExprClass;
4423+
}
4424+
4425+
// Iterators
4426+
child_range children() { return child_range(SubExprs, SubExprs + 2); }
4427+
4428+
const_child_range children() const {
4429+
return const_child_range(SubExprs, SubExprs + 2);
4430+
}
4431+
};
4432+
43344433
/// Represents a reference to a non-type template parameter
43354434
/// that has been substituted with a template argument.
43364435
class SubstNonTypeTemplateParmExpr : public Expr {

clang/include/clang/AST/RecursiveASTVisitor.h

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

1068+
DEF_TRAVERSE_TYPE(PackIndexingType, {
1069+
TRY_TO(TraverseType(T->getPattern()));
1070+
TRY_TO(TraverseStmt(T->getIndexExpr()));
1071+
})
1072+
10681073
DEF_TRAVERSE_TYPE(UnaryTransformType, {
10691074
TRY_TO(TraverseType(T->getBaseType()));
10701075
TRY_TO(TraverseType(T->getUnderlyingType()));
@@ -1343,6 +1348,11 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
13431348
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
13441349
})
13451350

1351+
DEF_TRAVERSE_TYPELOC(PackIndexingType, {
1352+
TRY_TO(TraverseType(TL.getPattern()));
1353+
TRY_TO(TraverseStmt(TL.getTypePtr()->getIndexExpr()));
1354+
})
1355+
13461356
DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
13471357
TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
13481358
})
@@ -2854,6 +2864,7 @@ DEF_TRAVERSE_STMT(CompoundAssignOperator, {})
28542864
DEF_TRAVERSE_STMT(CXXNoexceptExpr, {})
28552865
DEF_TRAVERSE_STMT(PackExpansionExpr, {})
28562866
DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
2867+
DEF_TRAVERSE_STMT(PackIndexingExpr, {})
28572868
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
28582869
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
28592870
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})

clang/include/clang/AST/Type.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4934,6 +4934,73 @@ class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
49344934
Expr *E);
49354935
};
49364936

4937+
class PackIndexingType final
4938+
: public Type,
4939+
public llvm::FoldingSetNode,
4940+
private llvm::TrailingObjects<PackIndexingType, QualType> {
4941+
friend TrailingObjects;
4942+
4943+
const ASTContext &Context;
4944+
QualType Pattern;
4945+
Expr *IndexExpr;
4946+
4947+
unsigned Size;
4948+
4949+
protected:
4950+
friend class ASTContext; // ASTContext creates these.
4951+
PackIndexingType(const ASTContext &Context, QualType Canonical,
4952+
QualType Pattern, Expr *IndexExpr,
4953+
ArrayRef<QualType> Expansions = {});
4954+
4955+
public:
4956+
Expr *getIndexExpr() const { return IndexExpr; }
4957+
QualType getPattern() const { return Pattern; }
4958+
4959+
bool isSugared() const { return hasSelectedType(); }
4960+
4961+
QualType desugar() const {
4962+
if (hasSelectedType())
4963+
return getSelectedType();
4964+
return QualType(this, 0);
4965+
}
4966+
4967+
QualType getSelectedType() const {
4968+
assert(hasSelectedType() && "Type is dependant");
4969+
return *(getExpansionsPtr() + *getSelectedIndex());
4970+
}
4971+
4972+
std::optional<unsigned> getSelectedIndex() const;
4973+
4974+
bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; }
4975+
4976+
ArrayRef<QualType> getExpansions() const {
4977+
return {getExpansionsPtr(), Size};
4978+
}
4979+
4980+
static bool classof(const Type *T) {
4981+
return T->getTypeClass() == PackIndexing;
4982+
}
4983+
4984+
void Profile(llvm::FoldingSetNodeID &ID) {
4985+
if (hasSelectedType())
4986+
getSelectedType().Profile(ID);
4987+
else
4988+
Profile(ID, Context, getPattern(), getIndexExpr());
4989+
}
4990+
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
4991+
QualType Pattern, Expr *E);
4992+
4993+
private:
4994+
const QualType *getExpansionsPtr() const {
4995+
return getTrailingObjects<QualType>();
4996+
}
4997+
4998+
static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr,
4999+
ArrayRef<QualType> Expansions = {});
5000+
5001+
unsigned numTrailingObjects(OverloadToken<QualType>) const { return Size; }
5002+
};
5003+
49375004
/// A unary type transform, which is a type constructed from another.
49385005
class UnaryTransformType : public Type {
49395006
public:

clang/include/clang/AST/TypeLoc.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,34 @@ class DecltypeTypeLoc
20592059
}
20602060
};
20612061

2062+
struct PackIndexingTypeLocInfo {
2063+
SourceLocation EllipsisLoc;
2064+
};
2065+
2066+
class PackIndexingTypeLoc
2067+
: public ConcreteTypeLoc<UnqualTypeLoc, PackIndexingTypeLoc,
2068+
PackIndexingType, PackIndexingTypeLocInfo> {
2069+
2070+
public:
2071+
Expr *getIndexExpr() const { return getTypePtr()->getIndexExpr(); }
2072+
QualType getPattern() const { return getTypePtr()->getPattern(); }
2073+
2074+
SourceLocation getEllipsisLoc() const { return getLocalData()->EllipsisLoc; }
2075+
void setEllipsisLoc(SourceLocation Loc) { getLocalData()->EllipsisLoc = Loc; }
2076+
2077+
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
2078+
setEllipsisLoc(Loc);
2079+
}
2080+
2081+
TypeLoc getPatternLoc() const { return getInnerTypeLoc(); }
2082+
2083+
QualType getInnerType() const { return this->getTypePtr()->getPattern(); }
2084+
2085+
SourceRange getLocalSourceRange() const {
2086+
return SourceRange(getEllipsisLoc(), getEllipsisLoc());
2087+
}
2088+
};
2089+
20622090
struct UnaryTransformTypeLocInfo {
20632091
// FIXME: While there's only one unary transform right now, future ones may
20642092
// 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: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5721,9 +5721,18 @@ def err_function_parameter_pack_without_parameter_packs : Error<
57215721
def err_ellipsis_in_declarator_not_parameter : Error<
57225722
"only function and template parameters can be parameter packs">;
57235723

5724-
def err_sizeof_pack_no_pack_name : Error<
5724+
def err_expected_name_of_pack : Error<
57255725
"%0 does not refer to the name of a parameter pack">;
57265726

5727+
def err_pack_index_out_of_bound : Error<
5728+
"invalid index %0 for pack %1 of size %2">;
5729+
5730+
def ext_pack_indexing : ExtWarn<
5731+
"pack indexing is a C++2c extension">, InGroup<CXX26>;
5732+
def warn_cxx23_pack_indexing : Warning<
5733+
"pack indexing is incompatible with C++ standards before C++2c">,
5734+
DefaultIgnore, InGroup<CXXPre26Compat>;
5735+
57275736
def err_fold_expression_packs_both_sides : Error<
57285737
"binary fold expression has unexpanded parameter packs in both operands">;
57295738
def err_fold_expression_empty : Error<

clang/include/clang/Basic/Specifiers.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,22 +79,24 @@ namespace clang {
7979
TST_enum,
8080
TST_union,
8181
TST_struct,
82-
TST_class, // C++ class type
83-
TST_interface, // C++ (Microsoft-specific) __interface type
84-
TST_typename, // Typedef, C++ class-name or enum name, etc.
82+
TST_class, // C++ class type
83+
TST_interface, // C++ (Microsoft-specific) __interface type
84+
TST_typename, // Typedef, C++ class-name or enum name, etc.
8585
TST_typeofType, // C23 (and GNU extension) typeof(type-name)
8686
TST_typeofExpr, // C23 (and GNU extension) typeof(expression)
8787
TST_typeof_unqualType, // C23 typeof_unqual(type-name)
8888
TST_typeof_unqualExpr, // C23 typeof_unqual(expression)
89-
TST_decltype, // C++11 decltype
89+
TST_decltype, // C++11 decltype
9090
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait,
9191
#include "clang/Basic/TransformTypeTraits.def"
9292
TST_auto, // C++11 auto
9393
TST_decltype_auto, // C++1y decltype(auto)
9494
TST_auto_type, // __auto_type extension
9595
TST_unknown_anytype, // __unknown_anytype extension
9696
TST_atomic, // C11 _Atomic
97-
#define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types
97+
TST_typename_pack_indexing,
98+
#define GENERIC_IMAGE_TYPE(ImgType, Id) \
99+
TST_##ImgType##_t, // OpenCL image types
98100
#include "clang/Basic/OpenCLImageTypes.def"
99101
TST_error // erroneous type
100102
};

0 commit comments

Comments
 (0)