[clang] [Clang][C++26] Implement Pack Indexing (P2662R3). (PR #72644)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 26 23:10:54 PST 2024
https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/72644
>From 6ea082935520641ea0d45140f3f07bbfe00b2475 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 13 Sep 2022 18:29:34 +0200
Subject: [PATCH 01/12] [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.
---
clang/docs/ReleaseNotes.rst | 3 +
clang/include/clang-c/Index.h | 7 +-
clang/include/clang/AST/ASTContext.h | 8 +
clang/include/clang/AST/ASTNodeTraverser.h | 6 +
clang/include/clang/AST/ExprCXX.h | 106 ++++++++++
clang/include/clang/AST/RecursiveASTVisitor.h | 11 +
clang/include/clang/AST/Type.h | 66 ++++++
clang/include/clang/AST/TypeLoc.h | 28 +++
clang/include/clang/AST/TypeProperties.td | 14 ++
.../clang/Basic/DiagnosticSemaKinds.td | 5 +-
clang/include/clang/Basic/Specifiers.h | 1 +
clang/include/clang/Basic/StmtNodes.td | 1 +
clang/include/clang/Basic/TokenKinds.def | 2 +
clang/include/clang/Basic/TypeNodes.td | 1 +
clang/include/clang/Parse/Parser.h | 9 +
clang/include/clang/Sema/DeclSpec.h | 25 ++-
clang/include/clang/Sema/Sema.h | 25 +++
.../include/clang/Serialization/ASTBitCodes.h | 1 +
.../clang/Serialization/TypeBitCodes.def | 2 +
clang/lib/AST/ASTContext.cpp | 43 ++++
clang/lib/AST/ASTImporter.cpp | 12 ++
clang/lib/AST/ASTStructuralEquivalence.cpp | 10 +
clang/lib/AST/Expr.cpp | 8 +
clang/lib/AST/ExprCXX.cpp | 37 ++++
clang/lib/AST/ExprClassification.cpp | 3 +
clang/lib/AST/ExprConstant.cpp | 7 +
clang/lib/AST/ItaniumMangle.cpp | 9 +
clang/lib/AST/MicrosoftMangle.cpp | 6 +
clang/lib/AST/StmtPrinter.cpp | 4 +
clang/lib/AST/StmtProfile.cpp | 6 +
clang/lib/AST/Type.cpp | 40 ++++
clang/lib/AST/TypePrinter.cpp | 18 ++
clang/lib/CodeGen/CGDebugInfo.cpp | 5 +
clang/lib/CodeGen/CGExpr.cpp | 2 +
clang/lib/CodeGen/CGExprAgg.cpp | 3 +
clang/lib/CodeGen/CGExprComplex.cpp | 4 +
clang/lib/CodeGen/CGExprConstant.cpp | 4 +
clang/lib/CodeGen/CGExprScalar.cpp | 3 +
clang/lib/CodeGen/CodeGenFunction.cpp | 1 +
clang/lib/Parse/ParseCXXInlineMethods.cpp | 14 ++
clang/lib/Parse/ParseDecl.cpp | 5 +
clang/lib/Parse/ParseDeclCXX.cpp | 101 +++++++++
clang/lib/Parse/ParseExpr.cpp | 13 ++
clang/lib/Parse/ParseExprCXX.cpp | 68 +++++-
clang/lib/Parse/ParseTentative.cpp | 13 ++
clang/lib/Parse/Parser.cpp | 3 +-
clang/lib/Sema/DeclSpec.cpp | 21 ++
clang/lib/Sema/SemaCXXScopeSpec.cpp | 23 ++
clang/lib/Sema/SemaDecl.cpp | 1 +
clang/lib/Sema/SemaDeclCXX.cpp | 4 +
clang/lib/Sema/SemaExceptionSpec.cpp | 1 +
clang/lib/Sema/SemaExpr.cpp | 3 +
clang/lib/Sema/SemaExprCXX.cpp | 32 ++-
clang/lib/Sema/SemaTemplate.cpp | 5 +
clang/lib/Sema/SemaTemplateDeduction.cpp | 16 ++
clang/lib/Sema/SemaTemplateVariadic.cpp | 66 +++++-
clang/lib/Sema/SemaType.cpp | 60 ++++++
clang/lib/Sema/TreeTransform.h | 200 ++++++++++++++++++
clang/lib/Serialization/ASTReader.cpp | 4 +
clang/lib/Serialization/ASTReaderStmt.cpp | 22 ++
clang/lib/Serialization/ASTWriter.cpp | 5 +
clang/lib/Serialization/ASTWriterStmt.cpp | 16 ++
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 +
clang/test/PCH/pack_indexing.cpp | 16 ++
clang/test/Parser/cxx2b-pack-indexing.cpp | 65 ++++++
clang/test/SemaCXX/cxx2b-pack-indexing.cpp | 115 ++++++++++
clang/tools/libclang/CIndex.cpp | 8 +
clang/tools/libclang/CXCursor.cpp | 4 +
clang/www/cxx_status.html | 2 +-
69 files changed, 1436 insertions(+), 17 deletions(-)
create mode 100644 clang/test/PCH/pack_indexing.cpp
create mode 100644 clang/test/Parser/cxx2b-pack-indexing.cpp
create mode 100644 clang/test/SemaCXX/cxx2b-pack-indexing.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5330cd9caad8011..cf2d2c94b2fd928 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -68,6 +68,9 @@ C++23 Feature Support
C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^
+- Implemented `P2662R3 Pack Indexing <https://wg21.link/P2662R3>`_.
+
+
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 64ab3378957c702..2c0b89a0d12b21e 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -1685,7 +1685,12 @@ enum CXCursorKind {
*/
CXCursor_CXXParenListInitExpr = 155,
- CXCursor_LastExpr = CXCursor_CXXParenListInitExpr,
+ /**
+ * Represents a C++26 pack indexing expression
+ */
+ CXCursor_PackIndexingExpr = 156,
+
+ CXCursor_LastExpr = CXCursor_PackIndexingExpr,
/* Statements */
CXCursor_FirstStmt = 200,
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 3e46a5da3fc043f..9e1c44eb19b805c 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -214,6 +214,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
DependentTypeOfExprTypes;
mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
DependentDecltypeTypes;
+
+ mutable llvm::FoldingSet<PackIndexingType> DependentPackIndexingTypes;
+
mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmType>
@@ -1713,6 +1716,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// C++11 decltype.
QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
+ QualType getPackIndexingType(QualType Pattern, Expr *IndexExpr,
+ bool FullyExpanded = false,
+ ArrayRef<QualType> Expansions = {},
+ int Index = -1) const;
+
/// Unary type transforms
QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
UnaryTransformType::UTTKind UKind) const;
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index cc8dab97f8b010f..950da2b8d2c4560 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -385,6 +385,12 @@ class ASTNodeTraverser
void VisitDecltypeType(const DecltypeType *T) {
Visit(T->getUnderlyingExpr());
}
+
+ void VisitPackIndexingType(const PackIndexingType *T) {
+ Visit(T->getPattern());
+ Visit(T->getIndexExpr());
+ }
+
void VisitUnaryTransformType(const UnaryTransformType *T) {
Visit(T->getBaseType());
}
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 9a7c632c36c5e8a..af4f2de2f11b87b 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4331,6 +4331,112 @@ class SizeOfPackExpr final
}
};
+class PackIndexingExpr final
+ : public Expr,
+ private llvm::TrailingObjects<PackIndexingExpr, Expr *> {
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+ friend TrailingObjects;
+
+ SourceLocation EllipsisLoc;
+
+ // The location of the closing bracket
+ SourceLocation RSquareLoc;
+
+ // The pack being indexed, followed by the index
+ Stmt *SubExprs[2];
+
+ // The evaluated index
+ std::optional<int64_t> Index;
+
+ size_t TransformedExpressions;
+
+ PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
+ SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr,
+ std::optional<int64_t> Index = std::nullopt,
+ ArrayRef<Expr *> SubstitutedExprs = {})
+ : Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
+ EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
+ SubExprs{PackIdExpr, IndexExpr}, Index(Index),
+ TransformedExpressions(SubstitutedExprs.size()) {
+
+ auto *Exprs = getTrailingObjects<Expr *>();
+ std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(),
+ Exprs);
+
+ ExprDependence D = IndexExpr->getDependence();
+ if (SubstitutedExprs.empty())
+ D |= (PackIdExpr->getDependence() |
+ ExprDependence::TypeValueInstantiation) &
+ ~ExprDependence::UnexpandedPack;
+ else if (!IndexExpr->isValueDependent()) {
+ assert(Index && *Index < int64_t(SubstitutedExprs.size()) &&
+ "pack index out of bound");
+ D |= SubstitutedExprs[*Index]->getDependence();
+ setValueKind(SubstitutedExprs[*Index]->getValueKind());
+ }
+ setDependence(D);
+ }
+
+ /// Create an empty expression.
+ PackIndexingExpr(EmptyShell Empty) : Expr(PackIndexingExprClass, Empty) {}
+
+ unsigned numTrailingObjects(OverloadToken<Expr *>) const {
+ return TransformedExpressions;
+ }
+
+public:
+ static PackIndexingExpr *Create(ASTContext &Context,
+ SourceLocation EllipsisLoc,
+ SourceLocation RSquareLoc, Expr *PackIdExpr,
+ Expr *IndexExpr,
+ std::optional<int64_t> Index = std::nullopt,
+ ArrayRef<Expr *> SubstitutedExprs = {});
+ static PackIndexingExpr *CreateDeserialized(ASTContext &Context,
+ unsigned NumTransformedExprs);
+
+ /// Determine the location of the 'sizeof' keyword.
+ SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+
+ /// Determine the location of the parameter pack.
+ SourceLocation getPackLoc() const { return SubExprs[0]->getBeginLoc(); }
+
+ /// Determine the location of the right parenthesis.
+ SourceLocation getRSquareLoc() const { return RSquareLoc; }
+
+ SourceLocation getBeginLoc() const LLVM_READONLY { return getPackLoc(); }
+ SourceLocation getEndLoc() const LLVM_READONLY { return RSquareLoc; }
+
+ Expr *getPackIdExpression() const { return cast<Expr>(SubExprs[0]); }
+
+ NamedDecl *getPackDecl() const;
+
+ Expr *getIndexExpr() const { return cast<Expr>(SubExprs[1]); }
+
+ Expr *getSelectedExpr() const {
+ assert(Index && !isInstantiationDependent() &&
+ "extracting the indexed expression of a dependant pack");
+ return getTrailingObjects<Expr *>()[*Index];
+ }
+
+ llvm::ArrayRef<Expr *> getExpressions() const {
+ if (TransformedExpressions == 0)
+ return {};
+ return {getTrailingObjects<Expr *>(), TransformedExpressions};
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == PackIndexingExprClass;
+ }
+
+ // Iterators
+ child_range children() { return child_range(SubExprs, SubExprs + 2); }
+
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + 2);
+ }
+};
+
/// Represents a reference to a non-type template parameter
/// that has been substituted with a template argument.
class SubstNonTypeTemplateParmExpr : public Expr {
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 2aee6a947141b6c..16b98b364eaca56 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1065,6 +1065,11 @@ DEF_TRAVERSE_TYPE(TypeOfType, { TRY_TO(TraverseType(T->getUnmodifiedType())); })
DEF_TRAVERSE_TYPE(DecltypeType,
{ TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
+DEF_TRAVERSE_TYPE(PackIndexingType, {
+ TRY_TO(TraverseType(T->getPattern()));
+ TRY_TO(TraverseStmt(T->getIndexExpr()));
+})
+
DEF_TRAVERSE_TYPE(UnaryTransformType, {
TRY_TO(TraverseType(T->getBaseType()));
TRY_TO(TraverseType(T->getUnderlyingType()));
@@ -1343,6 +1348,11 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
})
+DEF_TRAVERSE_TYPELOC(PackIndexingType, {
+ TRY_TO(TraverseType(TL.getPattern()));
+ TRY_TO(TraverseStmt(TL.getTypePtr()->getIndexExpr()));
+})
+
DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
})
@@ -2854,6 +2864,7 @@ DEF_TRAVERSE_STMT(CompoundAssignOperator, {})
DEF_TRAVERSE_STMT(CXXNoexceptExpr, {})
DEF_TRAVERSE_STMT(PackExpansionExpr, {})
DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
+DEF_TRAVERSE_STMT(PackIndexingExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 9336c4c41410d2a..16598ec9860b24f 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -4934,6 +4934,72 @@ class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
Expr *E);
};
+class PackIndexingType final
+ : public Type,
+ public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<PackIndexingType, QualType> {
+ friend TrailingObjects;
+
+ const ASTContext &Context;
+ QualType Pattern;
+ Expr *IndexExpr;
+
+ unsigned Size;
+ int Index = -1;
+
+protected:
+ friend class ASTContext; // ASTContext creates these.
+ PackIndexingType(const ASTContext &Context, QualType Canonical,
+ QualType Pattern, Expr *IndexExpr,
+ ArrayRef<QualType> Expansions = {}, int Index = -1);
+
+public:
+ Expr *getIndexExpr() const { return IndexExpr; }
+ QualType getPattern() const { return Pattern; }
+
+ bool isSugared() const { return hasSelectedType(); }
+
+ QualType desugar() const {
+ if (hasSelectedType())
+ return getSelectedType();
+ return QualType(this, 0);
+ }
+
+ QualType getSelectedType() const {
+ assert(hasSelectedType() && "Type is dependant");
+ return *(getExpansionsPtr() + Index);
+ }
+
+ bool hasSelectedType() const { return Index != -1 && !isDependentType(); }
+
+ ArrayRef<QualType> getExpansions() const {
+ return {getExpansionsPtr(), Size};
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == PackIndexing;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ if (hasSelectedType())
+ getSelectedType().Profile(ID);
+ else
+ Profile(ID, Context, getPattern(), getIndexExpr());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType Pattern, Expr *E);
+
+private:
+ const QualType *getExpansionsPtr() const {
+ return getTrailingObjects<QualType>();
+ }
+
+ static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr,
+ ArrayRef<QualType> Expansions = {});
+
+ unsigned numTrailingObjects(OverloadToken<QualType>) const { return Size; }
+};
+
/// A unary type transform, which is a type constructed from another.
class UnaryTransformType : public Type {
public:
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 04780fdeae3bc10..a17b4af13d03f9a 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -2059,6 +2059,34 @@ class DecltypeTypeLoc
}
};
+struct PackIndexingTypeLocInfo {
+ SourceLocation EllipsisLoc;
+};
+
+class PackIndexingTypeLoc
+ : public ConcreteTypeLoc<UnqualTypeLoc, PackIndexingTypeLoc,
+ PackIndexingType, PackIndexingTypeLocInfo> {
+
+public:
+ Expr *getIndexExpr() const { return getTypePtr()->getIndexExpr(); }
+ QualType getPattern() const { return getTypePtr()->getPattern(); }
+
+ SourceLocation getEllipsisLoc() const { return getLocalData()->EllipsisLoc; }
+ void setEllipsisLoc(SourceLocation Loc) { getLocalData()->EllipsisLoc = Loc; }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setEllipsisLoc(Loc);
+ }
+
+ TypeLoc getPatternLoc() const { return getInnerTypeLoc(); }
+
+ QualType getInnerType() const { return this->getTypePtr()->getPattern(); }
+
+ SourceRange getLocalSourceRange() const {
+ return SourceRange(getEllipsisLoc(), getEllipsisLoc());
+ }
+};
+
struct UnaryTransformTypeLocInfo {
// FIXME: While there's only one unary transform right now, future ones may
// need different representations
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 682c869b0c58479..0ba172a4035fdb4 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -433,6 +433,20 @@ let Class = DecltypeType in {
}]>;
}
+let Class = PackIndexingType in {
+ def : Property<"pattern", QualType> {
+ let Read = [{ node->getPattern() }];
+ }
+ def : Property<"indexExpression", ExprRef> {
+ let Read = [{ node->getIndexExpr() }];
+ }
+
+ def : Creator<[{
+ return ctx.getPackIndexingType(pattern, indexExpression);
+ }]>;
+}
+
+
let Class = UnaryTransformType in {
def : Property<"baseType", QualType> {
let Read = [{ node->getBaseType() }];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a1c32abb4dcd880..e9e203fc27691b4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5721,9 +5721,12 @@ def err_function_parameter_pack_without_parameter_packs : Error<
def err_ellipsis_in_declarator_not_parameter : Error<
"only function and template parameters can be parameter packs">;
-def err_sizeof_pack_no_pack_name : Error<
+def err_expected_name_of_pack : Error<
"%0 does not refer to the name of a parameter pack">;
+def err_pack_index_out_of_bound : Error<
+ "%0 is not a valid index for pack %1 of size %2">;
+
def err_fold_expression_packs_both_sides : Error<
"binary fold expression has unexpanded parameter packs in both operands">;
def err_fold_expression_empty : Error<
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 87f29c8ae10bd9a..bff4c1616c1d027 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -94,6 +94,7 @@ namespace clang {
TST_auto_type, // __auto_type extension
TST_unknown_anytype, // __unknown_anytype extension
TST_atomic, // C11 _Atomic
+ TST_indexed_typename_pack,
#define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types
#include "clang/Basic/OpenCLImageTypes.def"
TST_error // erroneous type
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index cec301dfca2817b..9d03800840fcd0b 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -154,6 +154,7 @@ def UnresolvedMemberExpr : StmtNode<OverloadExpr>;
def CXXNoexceptExpr : StmtNode<Expr>;
def PackExpansionExpr : StmtNode<Expr>;
def SizeOfPackExpr : StmtNode<Expr>;
+def PackIndexingExpr : StmtNode<Expr>;
def SubstNonTypeTemplateParmExpr : StmtNode<Expr>;
def SubstNonTypeTemplateParmPackExpr : StmtNode<Expr>;
def FunctionParmPackExpr : StmtNode<Expr>;
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index c10e2adfbe6e966..e8b93e0bd1b5dee 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -840,6 +840,8 @@ ANNOTATION(primary_expr) // annotation for a primary expression, used when
// message send
ANNOTATION(decltype) // annotation for a decltype expression,
// e.g., "decltype(foo.bar())"
+ANNOTATION(indexed_pack_type) // annotation for an indexed pack of type,
+ // e.g., "T...[expr]"
// Annotation for #pragma unused(...)
// For each argument inside the parentheses the pragma handler will produce
diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td
index 649b071cebb9404..6419762417371b9 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -103,6 +103,7 @@ def InjectedClassNameType : TypeNode<Type>, AlwaysDependent, LeafType;
def DependentNameType : TypeNode<Type>, AlwaysDependent;
def DependentTemplateSpecializationType : TypeNode<Type>, AlwaysDependent;
def PackExpansionType : TypeNode<Type>, AlwaysDependent;
+def PackIndexingType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def ObjCTypeParamType : TypeNode<Type>, NeverCanonical;
def ObjCObjectType : TypeNode<Type>;
def ObjCInterfaceType : TypeNode<ObjCObjectType>, LeafType;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index bde1ac2242cd6c2..b28f8a15932d86c 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1911,6 +1911,10 @@ class Parser : public CodeCompletionHandler {
// C++ Expressions
ExprResult tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand,
Token &Replacement);
+
+ ExprResult tryParseCXXPackIndexingExpression(ExprResult PackIdExpression);
+ ExprResult ParseCXXPackIndexingExpression(ExprResult PackIdExpression);
+
ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
bool areTokensAdjacent(const Token &A, const Token &B);
@@ -2457,6 +2461,11 @@ class Parser : public CodeCompletionHandler {
DeclSpecContext DSC, LateParsedAttrList *LateAttrs,
ImplicitTypenameContext AllowImplicitTypename);
+ SourceLocation ParseIndexedTypeNamePack(DeclSpec &DS);
+ void AnnotateExistingIndexedTypeNamePack(ParsedType T,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc);
+
bool DiagnoseMissingSemiAfterTagDefinition(
DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext,
LateParsedAttrList *LateAttrs = nullptr);
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 4561cca929c0d0b..4726cbbd1af50c9 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -309,6 +309,7 @@ class DeclSpec {
static const TST TST_typeof_unqualExpr = clang::TST_typeof_unqualExpr;
static const TST TST_decltype = clang::TST_decltype;
static const TST TST_decltype_auto = clang::TST_decltype_auto;
+ static const TST TST_indexed_typename_pack = clang::TST_indexed_typename_pack;
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
static const TST TST_##Trait = clang::TST_##Trait;
#include "clang/Basic/TransformTypeTraits.def"
@@ -389,6 +390,7 @@ class DeclSpec {
Expr *ExprRep;
TemplateIdAnnotation *TemplateIdRep;
};
+ Expr *PackIndexingExpr = nullptr;
/// ExplicitSpecifier - Store information about explicit spicifer.
ExplicitSpecifier FS_explicit_specifier;
@@ -405,7 +407,7 @@ class DeclSpec {
SourceLocation StorageClassSpecLoc, ThreadStorageClassSpecLoc;
SourceRange TSWRange;
- SourceLocation TSCLoc, TSSLoc, TSTLoc, AltiVecLoc, TSSatLoc;
+ SourceLocation TSCLoc, TSSLoc, TSTLoc, AltiVecLoc, TSSatLoc, EllipsisLoc;
/// TSTNameLoc - If TypeSpecType is any of class, enum, struct, union,
/// typename, then this is the location of the named type (if present);
/// otherwise, it is the same as TSTLoc. Hence, the pair TSTLoc and
@@ -427,7 +429,8 @@ class DeclSpec {
static bool isTypeRep(TST T) {
return T == TST_atomic || T == TST_typename || T == TST_typeofType ||
- T == TST_typeof_unqualType || isTransformTypeTrait(T);
+ T == TST_typeof_unqualType || isTransformTypeTrait(T) ||
+ T == TST_indexed_typename_pack;
}
static bool isExprRep(TST T) {
return T == TST_typeofExpr || T == TST_typeof_unqualExpr ||
@@ -530,6 +533,13 @@ class DeclSpec {
assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");
return ExprRep;
}
+
+ Expr *getPackIndexingExpr() const {
+ assert(TypeSpecType == TST_indexed_typename_pack &&
+ "DeclSpec is not a pack indexing expr");
+ return PackIndexingExpr;
+ }
+
TemplateIdAnnotation *getRepAsTemplateId() const {
assert(isTemplateIdRep((TST) TypeSpecType) &&
"DeclSpec does not store a template id");
@@ -587,6 +597,7 @@ class DeclSpec {
SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; }
SourceLocation getUnalignedSpecLoc() const { return TQ_unalignedLoc; }
SourceLocation getPipeLoc() const { return TQ_pipeLoc; }
+ SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
/// Clear out all of the type qualifiers.
void ClearTypeQualifiers() {
@@ -743,6 +754,9 @@ class DeclSpec {
const PrintingPolicy &Policy);
bool SetTypeSpecSat(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
+
+ void SetPackIndexingExpr(SourceLocation EllipsisLoc, Expr *Pack);
+
bool SetTypeSpecError();
void UpdateDeclRep(Decl *Rep) {
assert(isDeclRep((TST) TypeSpecType));
@@ -1939,6 +1953,8 @@ class Declarator {
/// this declarator as a parameter pack.
SourceLocation EllipsisLoc;
+ Expr *PackIndexingExpr;
+
friend struct DeclaratorChunk;
public:
@@ -2063,6 +2079,7 @@ class Declarator {
ObjCWeakProperty = false;
CommaLoc = SourceLocation();
EllipsisLoc = SourceLocation();
+ PackIndexingExpr = nullptr;
}
/// mayOmitIdentifier - Return true if the identifier is either optional or
@@ -2648,6 +2665,10 @@ class Declarator {
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; }
+ bool hasPackIndexing() const { return PackIndexingExpr != nullptr; }
+ Expr *getPackIndexingExpr() const { return PackIndexingExpr; }
+ void setPackIndexingExpr(Expr *PI) { PackIndexingExpr = PI; }
+
void setFunctionDefinitionKind(FunctionDefinitionKind Val) {
FunctionDefinition = static_cast<unsigned>(Val);
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1f1cbd11ff73581..abcf9aeee06adb0 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2602,6 +2602,14 @@ class Sema final {
/// context, such as when building a type for decltype(auto).
QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true);
+ QualType ActOnPackIndexingType(QualType Pattern, Expr *IndexExpr,
+ SourceLocation Loc,
+ SourceLocation EllipsisLoc);
+ QualType BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
+ SourceLocation Loc, SourceLocation EllipsisLoc,
+ bool FullyExpanded = false,
+ ArrayRef<QualType> Expansions = {});
+
using UTTKind = UnaryTransformType::UTTKind;
QualType BuildUnaryTransformType(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
@@ -5873,6 +5881,18 @@ class Sema final {
IdentifierInfo &Name,
SourceLocation NameLoc,
SourceLocation RParenLoc);
+
+ ExprResult ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
+ SourceLocation EllipsisLoc,
+ SourceLocation LSquareLoc, Expr *IndexExpr,
+ SourceLocation RSquareLoc);
+
+ ExprResult BuildPackIndexingExpr(Expr *PackExpression,
+ SourceLocation EllipsisLoc, Expr *IndexExpr,
+ SourceLocation RSquareLoc,
+ ArrayRef<Expr *> ExpandedExprs = {},
+ bool EmptyPack = false);
+
ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, Expr *Input);
@@ -7140,6 +7160,11 @@ class Sema final {
const DeclSpec &DS,
SourceLocation ColonColonLoc);
+ bool ActOnCXXNestedNameSpecifierIndexedPack(CXXScopeSpec &SS,
+ const DeclSpec &DS,
+ SourceLocation ColonColonLoc,
+ QualType Type);
+
bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
NestedNameSpecInfo &IdInfo,
bool EnteringContext);
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index fdd64f2abbe9375..ea084b328d61244 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1895,6 +1895,7 @@ enum StmtCode {
EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr
EXPR_PACK_EXPANSION, // PackExpansionExpr
+ EXPR_PACK_INDEXING, // PackIndexingExpr
EXPR_SIZEOF_PACK, // SizeOfPackExpr
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr
diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def
index 89ae1a2fa39546e..adbd5ec5d4b544f 100644
--- a/clang/include/clang/Serialization/TypeBitCodes.def
+++ b/clang/include/clang/Serialization/TypeBitCodes.def
@@ -64,5 +64,7 @@ TYPE_BIT_CODE(ConstantMatrix, CONSTANT_MATRIX, 52)
TYPE_BIT_CODE(DependentSizedMatrix, DEPENDENT_SIZE_MATRIX, 53)
TYPE_BIT_CODE(Using, USING, 54)
TYPE_BIT_CODE(BTFTagAttributed, BTFTAG_ATTRIBUTED, 55)
+TYPE_BIT_CODE(PackIndexing, PACK_INDEXING, 56)
+
#undef TYPE_BIT_CODE
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index ab16ca10395fa83..4512a0fbd1ef0f1 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3598,6 +3598,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::Auto:
case Type::DeducedTemplateSpecialization:
case Type::PackExpansion:
+ case Type::PackIndexing:
case Type::BitInt:
case Type::DependentBitInt:
llvm_unreachable("type should never be variably-modified");
@@ -5701,6 +5702,39 @@ QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
return QualType(dt, 0);
}
+QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
+ bool FullyExpanded,
+ ArrayRef<QualType> Expansions,
+ int Index) const {
+ QualType Canonical;
+ if (FullyExpanded && Index != -1) {
+ Canonical = getCanonicalType(Expansions[Index]);
+ } else {
+ llvm::FoldingSetNodeID ID;
+ PackIndexingType::Profile(ID, *this, Pattern, IndexExpr);
+ void *InsertPos = nullptr;
+ PackIndexingType *Canon =
+ DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (!Canon) {
+ void *Mem = Allocate(
+ PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
+ TypeAlignment);
+ Canon = new (Mem) PackIndexingType(*this, QualType(), Pattern, IndexExpr,
+ Expansions, Index);
+ DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
+ }
+ Canonical = QualType(Canon, 0);
+ }
+
+ void *Mem =
+ Allocate(PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
+ TypeAlignment);
+ auto *T = new (Mem)
+ PackIndexingType(*this, Canonical, Pattern, IndexExpr, Expansions, Index);
+ Types.push_back(T);
+ return QualType(T, 0);
+}
+
/// getUnaryTransformationType - We don't unique these, since the memory
/// savings are minimal and these are rare.
QualType ASTContext::getUnaryTransformType(QualType BaseType,
@@ -12917,6 +12951,14 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
// As Decltype is not uniqued, building a common type would be wasteful.
return QualType(DX, 0);
}
+ case Type::PackIndexing: {
+ const auto *DX = cast<PackIndexingType>(X);
+ [[maybe_unused]] const auto *DY = cast<PackIndexingType>(Y);
+ assert(DX->isDependentType());
+ assert(DY->isDependentType());
+ assert(Ctx.hasSameExpr(DX->getIndexExpr(), DY->getIndexExpr()));
+ return QualType(DX, 0);
+ }
case Type::DependentName: {
const auto *NX = cast<DependentNameType>(X),
*NY = cast<DependentNameType>(Y);
@@ -13077,6 +13119,7 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
return Ctx.getAutoType(Ctx.getQualifiedType(Underlying), AX->getKeyword(),
/*IsDependent=*/false, /*IsPack=*/false, CD, As);
}
+ case Type::PackIndexing:
case Type::Decltype:
return QualType();
case Type::DeducedTemplateSpecialization:
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 12734d62ed9fb76..30567aa1163c4a8 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1369,6 +1369,18 @@ ExpectedType ASTNodeImporter::VisitParenType(const ParenType *T) {
return Importer.getToContext().getParenType(*ToInnerTypeOrErr);
}
+ExpectedType
+ASTNodeImporter::VisitPackIndexingType(clang::PackIndexingType const *T) {
+
+ ExpectedType Pattern = import(T->getPattern());
+ if (!Pattern)
+ return Pattern.takeError();
+ ExpectedExpr Index = import(T->getIndexExpr());
+ if (!Index)
+ return Index.takeError();
+ return Importer.getToContext().getPackIndexingType(*Pattern, *Index);
+}
+
ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
Expected<TypedefNameDecl *> ToDeclOrErr = import(T->getDecl());
if (!ToDeclOrErr)
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index be7a850a2982c73..a7ddf6d6f896d5a 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1292,6 +1292,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+ case Type::PackIndexing:
+ if (!IsStructurallyEquivalent(Context,
+ cast<PackIndexingType>(T1)->getPattern(),
+ cast<PackIndexingType>(T2)->getPattern()))
+ if (!IsStructurallyEquivalent(Context,
+ cast<PackIndexingType>(T1)->getIndexExpr(),
+ cast<PackIndexingType>(T2)->getIndexExpr()))
+ return false;
+ break;
+
case Type::ObjCInterface: {
const auto *Iface1 = cast<ObjCInterfaceType>(T1);
const auto *Iface2 = cast<ObjCInterfaceType>(T2);
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index f1efa98e175edf5..c2cd46dfbafcdfb 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3397,6 +3397,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
return Exp->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
break;
}
+ case PackIndexingExprClass: {
+ return cast<PackIndexingExpr>(this)
+ ->getSelectedExpr()
+ ->isConstantInitializer(Ctx, false, Culprit);
+ }
case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
case ImplicitCastExprClass:
@@ -3572,6 +3577,9 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
// These never have a side-effect.
return false;
+ case PackIndexingExprClass:
+ return cast<PackIndexingExpr>(this)->getSelectedExpr()->HasSideEffects(
+ Ctx, IncludePossibleEffects);
case ConstantExprClass:
// FIXME: Move this into the "return false;" block above.
return cast<ConstantExpr>(this)->getSubExpr()->HasSideEffects(
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index a775beadff9da53..141654e0abf02df 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1665,6 +1665,43 @@ 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) {
+ QualType Type;
+ if (Index && !SubstitutedExprs.empty())
+ Type = SubstitutedExprs[*Index]->getType();
+ else
+ Type = Context.DependentTy;
+
+ void *Storage =
+ Context.Allocate(totalSizeToAlloc<Expr *>(SubstitutedExprs.size()));
+ return new (Storage)
+ PackIndexingExpr(Type, EllipsisLoc, RSquareLoc, PackIdExpr, IndexExpr,
+ Index, SubstitutedExprs);
+}
+
+NamedDecl *PackIndexingExpr::getPackDecl() const {
+ if (auto *D = dyn_cast<DeclRefExpr>(getPackIdExpression()); D) {
+ NamedDecl *ND = dyn_cast<NamedDecl>(D->getDecl());
+ assert(ND && "exected a named decl");
+ return ND;
+ }
+ assert(false && "Non variables packs not supported");
+ return nullptr;
+}
+
+PackIndexingExpr *
+PackIndexingExpr::CreateDeserialized(ASTContext &Context,
+ unsigned NumTransformedExprs) {
+ void *Storage =
+ Context.Allocate(totalSizeToAlloc<Expr *>(NumTransformedExprs));
+ return new (Storage) PackIndexingExpr(EmptyShell{});
+}
+
QualType SubstNonTypeTemplateParmExpr::getParameterType(
const ASTContext &Context) const {
// Note that, for a class type NTTP, we will have an lvalue of type 'const
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index ffa7c6802ea6e19..7026fca8554ce9f 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -216,6 +216,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return ClassifyInternal(Ctx,
cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
+ case Expr::PackIndexingExprClass:
+ return ClassifyInternal(Ctx, cast<PackIndexingExpr>(E)->getSelectedExpr());
+
// C, C++98 [expr.sub]p1: The result is an lvalue of type "T".
// C++11 (DR1213): in the case of an array operand, the result is an lvalue
// if that operand is an lvalue and an xvalue otherwise.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1d07d022b25848..a41bdac46c814a9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8254,6 +8254,10 @@ class ExprEvaluatorBase
llvm_unreachable("Return from function from the loop above.");
}
+ bool VisitPackIndexingExpr(const PackIndexingExpr *E) {
+ return StmtVisitorTy::Visit(E->getSelectedExpr());
+ }
+
/// Visit a value which is evaluated, but whose value is ignored.
void VisitIgnoredValue(const Expr *E) {
EvaluateIgnoredValue(Info, E);
@@ -16062,6 +16066,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::SourceLocExprClass:
return NoDiag();
+ case Expr::PackIndexingExprClass:
+ return CheckICE(cast<PackIndexingExpr>(E)->getSelectedExpr(), Ctx);
+
case Expr::SubstNonTypeTemplateParmExprClass:
return
CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 688141b30441e83..c0add78bf90ff7f 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2448,6 +2448,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::PackIndexing:
case Type::TemplateTypeParm:
case Type::UnaryTransform:
case Type::SubstTemplateTypeParm:
@@ -4202,6 +4203,13 @@ void CXXNameMangler::mangleType(const PackExpansionType *T) {
mangleType(T->getPattern());
}
+void CXXNameMangler::mangleType(const PackIndexingType *T) {
+ if (!T->hasSelectedType())
+ mangleType(T->getPattern());
+ else
+ mangleType(T->getSelectedType());
+}
+
void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
mangleSourceName(T->getDecl()->getIdentifier());
}
@@ -4704,6 +4712,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
case Expr::OMPIteratorExprClass:
case Expr::CXXInheritedCtorInitExprClass:
case Expr::CXXParenListInitExprClass:
+ case Expr::PackIndexingExprClass:
llvm_unreachable("unexpected statement kind");
case Expr::ConstantExprClass:
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 36b5bf64f675a88..b272a546573a31b 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -3408,6 +3408,12 @@ void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, Qualifiers,
<< Range;
}
+void MicrosoftCXXNameMangler::mangleType(const PackIndexingType *T,
+ Qualifiers Quals, SourceRange Range) {
+ manglePointerCVQualifiers(Quals);
+ mangleType(T->getSelectedType(), Range);
+}
+
void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 9b5bf436c13be99..1df040e06db35e9 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2449,6 +2449,10 @@ void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
OS << "sizeof...(" << *E->getPack() << ")";
}
+void StmtPrinter::VisitPackIndexingExpr(PackIndexingExpr *E) {
+ OS << E->getPackIdExpression() << "...[" << E->getIndexExpr() << "]";
+}
+
void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *Node) {
OS << *Node->getParameterPack();
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index dd0838edab7b3f9..7459f967da09524 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2219,6 +2219,12 @@ void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) {
}
}
+void StmtProfiler::VisitPackIndexingExpr(const PackIndexingExpr *E) {
+ VisitExpr(E);
+ VisitExpr(E->getPackIdExpression());
+ VisitExpr(E->getIndexExpr());
+}
+
void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
const SubstNonTypeTemplateParmPackExpr *S) {
VisitExpr(S);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index d4103025591e730..4cddc546fabbfef 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3813,6 +3813,45 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
E->Profile(ID, Context, true);
}
+PackIndexingType::PackIndexingType(const ASTContext &Context,
+ QualType Canonical, QualType Pattern,
+ Expr *IndexExpr,
+ ArrayRef<QualType> Expansions, int Index)
+ : Type(PackIndexing, Canonical,
+ computeDependence(Pattern, IndexExpr, Expansions)),
+ Context(Context), Pattern(Pattern), IndexExpr(IndexExpr),
+ Size(Expansions.size()), Index(Index) {
+
+ std::uninitialized_copy(Expansions.begin(), Expansions.end(),
+ getTrailingObjects<QualType>());
+}
+
+TypeDependence
+PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr,
+ ArrayRef<QualType> Expansions) {
+ TypeDependence IndexD = toTypeDependence(IndexExpr->getDependence());
+
+ TypeDependence TD = IndexD | (IndexExpr->isInstantiationDependent()
+ ? TypeDependence::DependentInstantiation
+ : TypeDependence::None);
+ if (Expansions.empty())
+ TD |= Pattern->getDependence() & TypeDependence::DependentInstantiation;
+ else
+ for (const QualType &T : Expansions)
+ TD |= T->getDependence();
+
+ if (!(IndexD & TypeDependence::UnexpandedPack))
+ TD &= ~TypeDependence::UnexpandedPack;
+ return TD;
+}
+
+void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Context, QualType Pattern,
+ Expr *E) {
+ Pattern.Profile(ID);
+ E->Profile(ID, Context, true);
+}
+
UnaryTransformType::UnaryTransformType(QualType BaseType,
QualType UnderlyingType, UTTKind UKind,
QualType CanonicalType)
@@ -4488,6 +4527,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::PackIndexing:
case Type::UnaryTransform:
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index e9b6e810b02e8dd..e5e8211f55e578c 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -284,6 +284,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::FunctionNoProto:
case Type::Paren:
case Type::PackExpansion:
+
case Type::SubstTemplateTypeParm:
case Type::MacroQualified:
CanPrefixQualifiers = false;
@@ -296,6 +297,11 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
CanPrefixQualifiers = AttrTy->getAttrKind() == attr::AddressSpace;
break;
}
+ case Type::PackIndexing: {
+ return canPrefixQualifiers(
+ cast<PackIndexingType>(UnderlyingType)->getPattern().getTypePtr(),
+ NeedARCStrongQualifier);
+ }
}
return CanPrefixQualifiers;
@@ -1188,6 +1194,18 @@ void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {
spaceBeforePlaceHolder(OS);
}
+void TypePrinter::printPackIndexingBefore(const PackIndexingType *T,
+ raw_ostream &OS) {
+ if (T->isInstantiationDependentType())
+ OS << T->getPattern() << "...[" << T->getIndexExpr() << "]";
+ else
+ OS << T->getSelectedType();
+ spaceBeforePlaceHolder(OS);
+}
+
+void TypePrinter::printPackIndexingAfter(const PackIndexingType *T,
+ raw_ostream &OS) {}
+
void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) {}
void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T,
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 0f3f684d61dc943..81af8317300d9a4 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -3483,6 +3483,10 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
T = DT;
break;
}
+ case Type::PackIndexing: {
+ T = cast<PackIndexingType>(T)->getSelectedType();
+ break;
+ }
case Type::Adjusted:
case Type::Decayed:
// Decayed and adjusted types use the adjusted type in LLVM and DWARF.
@@ -3666,6 +3670,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::PackIndexing:
case Type::UnaryTransform:
break;
}
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 9196c953145b214..8c8c937b512acad 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1675,6 +1675,8 @@ LValue CodeGenFunction::EmitLValueHelper(const Expr *E,
return EmitCoawaitLValue(cast<CoawaitExpr>(E));
case Expr::CoyieldExprClass:
return EmitCoyieldLValue(cast<CoyieldExpr>(E));
+ case Expr::PackIndexingExprClass:
+ return EmitLValue(cast<PackIndexingExpr>(E)->getSelectedExpr());
}
}
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 810b28f25fa18bf..22f55fe9aac904e 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -235,6 +235,9 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
RValue Res = CGF.EmitAtomicExpr(E);
EmitFinalDestCopy(E->getType(), Res);
}
+ void VisitPackIndexingExpr(PackIndexingExpr *E) {
+ Visit(E->getSelectedExpr());
+ }
};
} // end anonymous namespace.
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 839fe16cd772534..9ddf0e763f139b8 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -354,6 +354,10 @@ class ComplexExprEmitter
ComplexPairTy VisitAtomicExpr(AtomicExpr *E) {
return CGF.EmitAtomicExpr(E).getComplexVal();
}
+
+ ComplexPairTy VisitPackIndexingExpr(PackIndexingExpr *E) {
+ return Visit(E->getSelectedExpr());
+ }
};
} // end anonymous namespace.
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 604e3958161db23..afadef7c4c10551 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1388,6 +1388,10 @@ class ConstExprEmitter :
return nullptr;
}
+ llvm::Constant *VisitPackIndexingExpr(PackIndexingExpr *E, QualType T) {
+ return Visit(E->getSelectedExpr(), T);
+ }
+
// Utility methods
llvm::Type *ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 181b15e9c7d0a7c..5502f685f64743b 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -904,6 +904,9 @@ class ScalarExprEmitter
}
Value *VisitAsTypeExpr(AsTypeExpr *CE);
Value *VisitAtomicExpr(AtomicExpr *AE);
+ Value *VisitPackIndexingExpr(PackIndexingExpr *E) {
+ return Visit(E->getSelectedExpr());
+ }
};
} // end anonymous namespace.
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 2673e4a5cee7bb5..1ad905078d349cb 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2407,6 +2407,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::Decltype:
case Type::Auto:
case Type::DeducedTemplateSpecialization:
+ case Type::PackIndexing:
// Stop walking: nothing to do.
return;
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 573c90a36eeab36..518a168ee246fb0 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -978,6 +978,20 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
} else {
break;
}
+ // Pack indexing
+ if (getLangOpts().CPlusPlus26 && Tok.is(tok::ellipsis) &&
+ NextToken().is(tok::l_square)) {
+ Toks.push_back(Tok);
+ SourceLocation OpenLoc = ConsumeToken();
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ if (!ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/true)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::r_square;
+ Diag(OpenLoc, diag::note_matching) << tok::l_square;
+ return true;
+ }
+ }
+
} while (Tok.is(tok::coloncolon));
if (Tok.is(tok::code_completion)) {
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 356e7851ec639c1..85a810030908197 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4447,6 +4447,10 @@ void Parser::ParseDeclarationSpecifiers(
ParseDecltypeSpecifier(DS);
continue;
+ case tok::annot_indexed_pack_type:
+ ParseIndexedTypeNamePack(DS);
+ continue;
+
case tok::annot_pragma_pack:
HandlePragmaPack();
continue;
@@ -5756,6 +5760,7 @@ bool Parser::isDeclarationSpecifier(
// C++11 decltype and constexpr.
case tok::annot_decltype:
+ case tok::annot_indexed_pack_type:
case tok::kw_constexpr:
// C++20 consteval and constinit.
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 82fe12170f6660a..c066a758b8e0e5e 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1196,6 +1196,95 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
PP.AnnotateCachedTokens(Tok);
}
+SourceLocation Parser::ParseIndexedTypeNamePack(DeclSpec &DS) {
+ assert(Tok.isOneOf(tok::annot_indexed_pack_type, tok::identifier) &&
+ "Expected an identifier");
+
+ TypeResult Type;
+ SourceLocation StartLoc;
+ SourceLocation EllipsisLoc;
+ const char *PrevSpec;
+ unsigned DiagID;
+ const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
+
+ if (Tok.is(tok::annot_indexed_pack_type)) {
+ StartLoc = Tok.getLocation();
+ SourceLocation EndLoc;
+ Type = getTypeAnnotation(Tok);
+ EndLoc = Tok.getAnnotationEndLoc();
+ // Unfortunately, we don't know the LParen source location as the annotated
+ // token doesn't have it.
+ DS.setTypeArgumentRange(SourceRange(SourceLocation(), EndLoc));
+ ConsumeAnnotationToken();
+ if (Type.isInvalid()) {
+ DS.SetTypeSpecError();
+ return EndLoc;
+ }
+ DS.SetTypeSpecType(DeclSpec::TST_indexed_typename_pack, StartLoc, PrevSpec,
+ DiagID, Type, Policy);
+ return EndLoc;
+ } else {
+ if (!NextToken().is(tok::ellipsis) ||
+ !GetLookAheadToken(2).is(tok::l_square)) {
+ DS.SetTypeSpecError();
+ return Tok.getEndLoc();
+ }
+
+ ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), getCurScope());
+ if (!Ty) {
+ DS.SetTypeSpecError();
+ return Tok.getEndLoc();
+ }
+ Type = Ty;
+
+ StartLoc = ConsumeToken();
+ EllipsisLoc = ConsumeToken();
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+ ExprResult IndexExpr = ParseConstantExpression();
+ if (T.consumeClose()) {
+ DS.SetTypeSpecError();
+ return IndexExpr.isInvalid() ? StartLoc : IndexExpr.get()->getEndLoc();
+ }
+ if (IndexExpr.isInvalid()) {
+ DS.SetTypeSpecError();
+ return T.getCloseLocation();
+ }
+ DS.SetRangeStart(StartLoc);
+ DS.SetRangeEnd(T.getCloseLocation());
+ DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec, DiagID, Type,
+ Policy);
+ DS.SetPackIndexingExpr(EllipsisLoc, IndexExpr.get());
+ return T.getCloseLocation();
+ ;
+ }
+ return SourceLocation();
+}
+
+void Parser::AnnotateExistingIndexedTypeNamePack(ParsedType T,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ // make sure we have a token we can turn into an annotation token
+ if (PP.isBacktrackEnabled()) {
+ PP.RevertCachedTokens(1);
+ if (!T) {
+ // We encountered an error in parsing 'decltype(...)' so lets annotate all
+ // the tokens in the backtracking cache - that we likely had to skip over
+ // to get to a token that allows us to resume parsing, such as a
+ // semi-colon.
+ EndLoc = PP.getLastCachedTokenLocation();
+ }
+ } else
+ PP.EnterToken(Tok, /*IsReinject*/ true);
+
+ Tok.setKind(tok::annot_indexed_pack_type);
+ setTypeAnnotation(Tok, T);
+ Tok.setAnnotationEndLoc(EndLoc);
+ Tok.setLocation(StartLoc);
+ PP.AnnotateCachedTokens(Tok);
+}
+
DeclSpec::TST Parser::TypeTransformTokToDeclSpec() {
switch (Tok.getKind()) {
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
@@ -1293,6 +1382,14 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
return Actions.ActOnTypeName(DeclaratorInfo);
}
+ if (Tok.is(tok::annot_indexed_pack_type)) {
+ DeclSpec DS(AttrFactory);
+ ParseIndexedTypeNamePack(DS);
+ Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+ DeclaratorContext::TypeName);
+ return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ }
+
// Check whether we have a template-id that names a type.
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
@@ -3836,6 +3933,10 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// ParseOptionalCXXScopeSpecifier at this point.
// FIXME: Can we get here with a scope specifier?
ParseDecltypeSpecifier(DS);
+ } else if (Tok.is(tok::annot_indexed_pack_type)) {
+ // Uses of T...[N] will already have been converted to
+ // annot_indexed_pack_type by ParseOptionalCXXScopeSpecifier at this point.
+ ParseIndexedTypeNamePack(DS);
} else {
TemplateIdAnnotation *TemplateId = Tok.is(tok::annot_template_id)
? takeTemplateIdAnnotation(Tok)
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index e862856a08ca117..dc65832c06f3a5c 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1067,6 +1067,17 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// where the syntax forbids a type.
const Token &Next = NextToken();
+ if (getLangOpts().CPlusPlus26 && Next.is(tok::ellipsis) &&
+ Tok.is(tok::identifier) && GetLookAheadToken(2).is(tok::l_square)) {
+ // Annotate the token and tail recurse.
+ // If the token is not annotated, then it might be an expression pack
+ // indexing
+ if (!TryAnnotateTypeOrScopeToken() &&
+ Tok.is(tok::annot_indexed_pack_type))
+ return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
+ isVectorLiteral, NotPrimaryExpression);
+ }
+
// If this identifier was reverted from a token ID, and the next token
// is a parenthesis, this is likely to be a use of a type trait. Check
// those tokens.
@@ -1289,6 +1300,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
/*isVectorLiteral=*/false,
NotPrimaryExpression);
}
+ Res = tryParseCXXPackIndexingExpression(Res);
if (!Res.isInvalid() && Tok.is(tok::less))
checkPotentialAngleBracket(Res);
break;
@@ -1549,6 +1561,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
[[fallthrough]];
case tok::annot_decltype:
+ case tok::annot_indexed_pack_type:
case tok::kw_char:
case tok::kw_wchar_t:
case tok::kw_char8_t:
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index d61f414406f0265..33d88b4e6294554 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -233,6 +233,32 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
HasScopeSpecifier = true;
}
+ else if (getLangOpts().CPlusPlus26 && !HasScopeSpecifier &&
+ Tok.is(tok::identifier) && GetLookAheadToken(1).is(tok::ellipsis) &&
+ GetLookAheadToken(2).is(tok::l_square)) {
+ SourceLocation Start = Tok.getLocation();
+ DeclSpec DS(AttrFactory);
+ SourceLocation CCLoc;
+ SourceLocation EndLoc = ParseIndexedTypeNamePack(DS);
+ if (DS.getTypeSpecType() == DeclSpec::TST_error)
+ return false;
+ QualType Type = Actions.ActOnPackIndexingType(
+ DS.getRepAsType().get(), DS.getPackIndexingExpr(), DS.getBeginLoc(),
+ DS.getEllipsisLoc());
+ if (Type.isNull())
+ return true;
+
+ if (!TryConsumeToken(tok::coloncolon, CCLoc)) {
+ AnnotateExistingIndexedTypeNamePack(ParsedType::make(Type), Start,
+ EndLoc);
+ return false;
+ }
+ if (Actions.ActOnCXXNestedNameSpecifierIndexedPack(SS, DS, CCLoc,
+ std::move(Type)))
+ SS.SetInvalid(SourceRange(Start, CCLoc));
+ HasScopeSpecifier = true;
+ }
+
// Preferred type might change when parsing qualifiers, we need the original.
auto SavedType = PreferredType;
while (true) {
@@ -617,11 +643,39 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS,
break;
}
+ // Might be a pack index expression!
+ if (getLangOpts().CPlusPlus26)
+ E = tryParseCXXPackIndexingExpression(E);
+
if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less))
checkPotentialAngleBracket(E);
return E;
}
+ExprResult Parser::ParseCXXPackIndexingExpression(ExprResult PackIdExpression) {
+ assert(Tok.is(tok::ellipsis) && NextToken().is(tok::l_square) &&
+ "expected ...[");
+ SourceLocation EllipsisLoc = ConsumeToken();
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+ ExprResult IndexExpr = ParseConstantExpression();
+ if (T.consumeClose() || IndexExpr.isInvalid())
+ return ExprError();
+ return Actions.ActOnPackIndexingExpr(getCurScope(), PackIdExpression.get(),
+ EllipsisLoc, T.getOpenLocation(),
+ IndexExpr.get(), T.getCloseLocation());
+}
+
+ExprResult
+Parser::tryParseCXXPackIndexingExpression(ExprResult PackIdExpression) {
+ ExprResult E = PackIdExpression;
+ if (!PackIdExpression.isInvalid() && !PackIdExpression.isUnset() &&
+ Tok.is(tok::ellipsis) && NextToken().is(tok::l_square)) {
+ E = ParseCXXPackIndexingExpression(E);
+ }
+ return E;
+}
+
/// ParseCXXIdExpression - Handle id-expression.
///
/// id-expression:
@@ -1810,6 +1864,15 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
return ExprError();
}
+ // pack-index-specifier
+ if (getLangOpts().CPlusPlus26 && GetLookAheadToken(1).is(tok::ellipsis) &&
+ GetLookAheadToken(2).is(tok::l_square)) {
+ DeclSpec DS(AttrFactory);
+ ParseIndexedTypeNamePack(DS);
+ return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
+ TildeLoc, DS);
+ }
+
// Parse the second type.
UnqualifiedId SecondTypeName;
IdentifierInfo *Name = Tok.getIdentifierInfo();
@@ -2253,7 +2316,6 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
getTypeAnnotation(Tok), Policy);
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeAnnotationToken();
-
DS.Finish(Actions, Policy);
return;
}
@@ -2364,6 +2426,10 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetRangeEnd(ParseDecltypeSpecifier(DS));
return DS.Finish(Actions, Policy);
+ case tok::annot_indexed_pack_type:
+ DS.SetRangeEnd(ParseIndexedTypeNamePack(DS));
+ return DS.Finish(Actions, Policy);
+
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 5bfabf55f50c445..09b62a13310b628 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1363,6 +1363,16 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
};
switch (Tok.getKind()) {
case tok::identifier: {
+ if (GetLookAheadToken(1).is(tok::ellipsis) &&
+ GetLookAheadToken(2).is(tok::l_square)) {
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error;
+ if (Tok.is(tok::identifier))
+ return TPResult::False;
+ return isCXXDeclarationSpecifier(ImplicitTypenameContext::No,
+ BracedCastResult, InvalidAsDeclSpec);
+ }
+
// Check for need to substitute AltiVec __vector keyword
// for "vector" identifier.
if (TryAltiVecVectorToken())
@@ -1755,6 +1765,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
return TPResult::True;
}
+
[[fallthrough]];
case tok::kw_char:
@@ -1782,6 +1793,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
case tok::kw__Accum:
case tok::kw__Fract:
case tok::kw__Sat:
+ case tok::annot_indexed_pack_type:
#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
if (NextToken().is(tok::l_paren))
@@ -1860,6 +1872,7 @@ bool Parser::isCXXDeclarationSpecifierAType() {
switch (Tok.getKind()) {
// typename-specifier
case tok::annot_decltype:
+ case tok::annot_indexed_pack_type:
case tok::annot_template_id:
case tok::annot_typename:
case tok::kw_typeof:
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 0b092181bca7bba..8f98182cad24f1e 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1992,7 +1992,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) ||
Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) ||
- Tok.is(tok::kw___super) || Tok.is(tok::kw_auto)) &&
+ Tok.is(tok::kw___super) || Tok.is(tok::kw_auto) ||
+ Tok.is(tok::annot_indexed_pack_type)) &&
"Cannot be a type or scope token!");
if (Tok.is(tok::kw_typename)) {
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 781f24cb71ae994..2a559561c810c4d 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -374,6 +374,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_void:
case TST_wchar:
case TST_BFloat16:
+ case TST_indexed_typename_pack:
#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
return false;
@@ -585,6 +586,8 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_struct: return "struct";
case DeclSpec::TST_interface: return "__interface";
case DeclSpec::TST_typename: return "type-name";
+ case DeclSpec::TST_indexed_typename_pack:
+ return "type-name-pack-indexing";
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
case DeclSpec::TST_typeof_unqualType:
@@ -775,6 +778,15 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
TSTLoc = TagKwLoc;
TSTNameLoc = TagNameLoc;
TypeSpecOwned = false;
+
+ if (T == TST_indexed_typename_pack) {
+ // we got there from a an annotation. Reconstruct the type
+ // Ugly...
+ QualType QT = Rep.get();
+ const PackIndexingType *LIT = cast<PackIndexingType>(QT);
+ TypeRep = ParsedType::make(LIT->getPattern());
+ PackIndexingExpr = LIT->getIndexExpr();
+ }
return false;
}
@@ -973,6 +985,15 @@ bool DeclSpec::SetBitIntType(SourceLocation KWLoc, Expr *BitsExpr,
return false;
}
+void DeclSpec::SetPackIndexingExpr(SourceLocation EllipsisLoc,
+ Expr *IndexingExpr) {
+ assert(TypeSpecType == TST_typename &&
+ "pack indexing can only be applied to typename");
+ TypeSpecType = TST_indexed_typename_pack;
+ PackIndexingExpr = IndexingExpr;
+ this->EllipsisLoc = EllipsisLoc;
+}
+
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, const LangOptions &Lang) {
// Duplicates are permitted in C99 onwards, but are not permitted in C89 or
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 44a40215b90dfb4..98833e931c6dad7 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -867,6 +867,29 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
return false;
}
+bool Sema::ActOnCXXNestedNameSpecifierIndexedPack(CXXScopeSpec &SS,
+ const DeclSpec &DS,
+ SourceLocation ColonColonLoc,
+ QualType Type) {
+ if (SS.isInvalid() || DS.getTypeSpecType() == DeclSpec::TST_error)
+ return true;
+
+ assert(DS.getTypeSpecType() == DeclSpec::TST_indexed_typename_pack);
+
+ if (Type.isNull())
+ return true;
+
+ TypeLocBuilder TLB;
+ TLB.pushTrivial(getASTContext(),
+ cast<PackIndexingType>(Type.getTypePtr())->getPattern(),
+ DS.getBeginLoc());
+ PackIndexingTypeLoc PIT = TLB.push<PackIndexingTypeLoc>(Type);
+ PIT.setEllipsisLoc(DS.getEllipsisLoc());
+ SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, Type),
+ ColonColonLoc);
+ return false;
+}
+
/// IsInvalidUnlessNestedName - This method is used for error recovery
/// purposes to determine whether the specified identifier is only valid as
/// a nested name specifier, for example a namespace name. It is
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f9bf1d14bdc4f68..dc019a3a7dea5da 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -163,6 +163,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw_char32_t:
case tok::kw_typeof:
case tok::annot_decltype:
+ case tok::annot_indexed_pack_type:
case tok::kw_decltype:
return getLangOpts().CPlusPlus;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index df5bd55e7c28368..286f56f671b8b81 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4494,6 +4494,10 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
} else if (DS.getTypeSpecType() == TST_decltype_auto) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
return true;
+ } else if (DS.getTypeSpecType() == TST_indexed_typename_pack) {
+ BaseType =
+ ActOnPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
+ DS.getBeginLoc(), DS.getEllipsisLoc());
} else {
LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
LookupParsedName(R, S, &SS);
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 75730ea888afb41..8d58ef5ee16d52d 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1410,6 +1410,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::OpaqueValueExprClass:
case Expr::PredefinedExprClass:
case Expr::SizeOfPackExprClass:
+ case Expr::PackIndexingExprClass:
case Expr::StringLiteralClass:
case Expr::SourceLocExprClass:
case Expr::ConceptSpecializationExprClass:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 790ea217ef8190d..2f1ddfb215116d0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4715,6 +4715,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::Decltype:
T = cast<DecltypeType>(Ty)->desugar();
break;
+ case Type::PackIndexing:
+ T = cast<PackIndexingType>(Ty)->desugar();
+ break;
case Type::Using:
T = cast<UsingType>(Ty)->desugar();
break;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 953bfe484a52802..87d4671147066d5 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8099,20 +8099,36 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
SourceLocation TildeLoc,
const DeclSpec& DS) {
QualType ObjectType;
+ QualType T;
+ TypeLocBuilder TLB;
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
return ExprError();
- if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto) {
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_decltype_auto: {
Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
return true;
}
-
- QualType T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false);
-
- TypeLocBuilder TLB;
- DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
- DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
- DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
+ case DeclSpec::TST_decltype: {
+ T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false);
+ DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
+ DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
+ DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
+ break;
+ }
+ case DeclSpec::TST_indexed_typename_pack: {
+ T = ActOnPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
+ DS.getBeginLoc(), DS.getEllipsisLoc());
+ TLB.pushTrivial(getASTContext(),
+ cast<PackIndexingType>(T.getTypePtr())->getPattern(),
+ DS.getBeginLoc());
+ PackIndexingTypeLoc PITL = TLB.push<PackIndexingTypeLoc>(T);
+ PITL.setEllipsisLoc(DS.getEllipsisLoc());
+ break;
+ }
+ default:
+ llvm_unreachable("Unsupported type in pseudo destructor");
+ }
TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T);
PseudoDestructorTypeStorage Destructed(DestructedTypeInfo);
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 9bfa71dc8bcf1db..3f33ecb89502eaf 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6440,6 +6440,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) {
return false;
}
+bool UnnamedLocalNoLinkageFinder::VisitPackIndexingType(
+ const PackIndexingType *) {
+ return false;
+}
+
bool UnnamedLocalNoLinkageFinder::VisitUnaryTransformType(
const UnaryTransformType*) {
return false;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index e9e7ab5bb6698a0..b7ce44720ee32c6 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -646,6 +646,7 @@ static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) {
case Type::TypeOf:
case Type::DependentName:
case Type::Decltype:
+ case Type::PackIndexing:
case Type::UnresolvedUsing:
case Type::TemplateTypeParm:
return true;
@@ -2244,6 +2245,15 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
case Type::Pipe:
// No template argument deduction for these types
return Sema::TDK_Success;
+
+ case Type::PackIndexing: {
+ const PackIndexingType *PIT = P->getAs<PackIndexingType>();
+ if (PIT->hasSelectedType()) {
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, PIT->getSelectedType(), A, Info, Deduced, TDF);
+ }
+ return Sema::TDK_IncompletePack;
+ }
}
llvm_unreachable("Invalid Type Class!");
@@ -6422,6 +6432,12 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
OnlyDeduced, Depth, Used);
break;
+ case Type::PackIndexing:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(Ctx, cast<PackIndexingType>(T)->getPattern(),
+ OnlyDeduced, Depth, Used);
+ break;
+
case Type::UnaryTransform:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 4a7872b2cc73c59..ff6cd66fe780b48 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -184,6 +184,15 @@ namespace {
bool TraversePackExpansionTypeLoc(PackExpansionTypeLoc TL) { return true; }
bool TraversePackExpansionExpr(PackExpansionExpr *E) { return true; }
bool TraverseCXXFoldExpr(CXXFoldExpr *E) { return true; }
+ bool TraversePackIndexingExpr(PackIndexingExpr *E) {
+ return inherited::TraverseStmt(E->getIndexExpr());
+ }
+ bool TraversePackIndexingType(PackIndexingType *E) {
+ return inherited::TraverseStmt(E->getIndexExpr());
+ }
+ bool TraversePackIndexingTypeLoc(PackIndexingTypeLoc TL) {
+ return inherited::TraverseStmt(TL.getIndexExpr());
+ }
///@}
@@ -865,6 +874,7 @@ std::optional<unsigned> Sema::getNumArgumentsInExpansion(
bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
switch (DS.getTypeSpecType()) {
+ case TST_indexed_typename_pack:
case TST_typename:
case TST_typeof_unqualType:
case TST_typeofType:
@@ -1050,8 +1060,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
}
if (!ParameterPack || !ParameterPack->isParameterPack()) {
- Diag(NameLoc, diag::err_sizeof_pack_no_pack_name)
- << &Name;
+ Diag(NameLoc, diag::err_expected_name_of_pack) << &Name;
return ExprError();
}
@@ -1061,6 +1070,59 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
RParenLoc);
}
+static bool isParameterPack(Expr *PackExpression) {
+ if (auto D = dyn_cast<DeclRefExpr>(PackExpression); D) {
+ ValueDecl *VD = D->getDecl();
+ return VD->isParameterPack();
+ }
+ return false;
+}
+
+ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
+ SourceLocation EllipsisLoc,
+ SourceLocation LSquareLoc,
+ Expr *IndexExpr,
+ SourceLocation RSquareLoc) {
+ bool isParameterPack = ::isParameterPack(PackExpression);
+ if (!isParameterPack) {
+ CorrectDelayedTyposInExpr(IndexExpr);
+ Diag(PackExpression->getBeginLoc(), diag::err_expected_name_of_pack)
+ << PackExpression;
+ return ExprError();
+ }
+ return BuildPackIndexingExpr(PackExpression, EllipsisLoc, IndexExpr,
+ RSquareLoc);
+}
+
+ExprResult
+Sema::BuildPackIndexingExpr(Expr *PackExpression, SourceLocation EllipsisLoc,
+ Expr *IndexExpr, SourceLocation RSquareLoc,
+ ArrayRef<Expr *> ExpandedExprs, bool EmptyPack) {
+
+ std::optional<int64_t> Index;
+ if (!IndexExpr->isValueDependent() && !IndexExpr->isTypeDependent()) {
+ llvm::APSInt Value(Context.getIntWidth(Context.getSizeType()));
+ // TODO: do we need a new enumerator instead of CCEK_ArrayBound?
+ ExprResult Res = CheckConvertedConstantExpression(
+ IndexExpr, Context.getSizeType(), Value, CCEK_ArrayBound);
+ if (!Res.isUsable())
+ return ExprError();
+ Index = Value.getExtValue();
+ }
+
+ if (Index && (!ExpandedExprs.empty() || EmptyPack)) {
+ if (*Index < 0 || EmptyPack || *Index >= int64_t(ExpandedExprs.size())) {
+ Diag(PackExpression->getBeginLoc(), diag::err_pack_index_out_of_bound)
+ << *Index << PackExpression << ExpandedExprs.size();
+ return ExprError();
+ }
+ }
+
+ return PackIndexingExpr::Create(getASTContext(), EllipsisLoc, RSquareLoc,
+ PackExpression, IndexExpr, Index,
+ ExpandedExprs);
+}
+
TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(
TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis,
std::optional<unsigned> &NumExpansions) const {
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 92086d7277fd1f0..6cd2f26c10377ff 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1667,6 +1667,19 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
}
+ case DeclSpec::TST_indexed_typename_pack: {
+ Expr *E = DS.getPackIndexingExpr();
+ assert(E && "Didn't get an expression for pack indexing");
+ QualType Pattern = S.GetTypeFromParser(DS.getRepAsType());
+ Result = S.ActOnPackIndexingType(Pattern, E, DS.getBeginLoc(),
+ DS.getEllipsisLoc());
+ if (Result.isNull()) {
+ declarator.setInvalidType(true);
+ Result = Context.IntTy;
+ }
+ break;
+ }
+
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
#include "clang/Basic/TransformTypeTraits.def"
Result = S.GetTypeFromParser(DS.getRepAsType());
@@ -6312,6 +6325,10 @@ namespace {
TL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
}
+ void VisitPackIndexingTypeLoc(PackIndexingTypeLoc TL) {
+ assert(DS.getTypeSpecType() == DeclSpec::TST_indexed_typename_pack);
+ TL.setEllipsisLoc(DS.getEllipsisLoc());
+ }
void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
assert(DS.isTransformTypeTrait(DS.getTypeSpecType()));
TL.setKWLoc(DS.getTypeSpecTypeLoc());
@@ -9727,6 +9744,9 @@ QualType Sema::getDecltypeForExpr(Expr *E) {
if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E))
IDExpr = ImplCastExpr->getSubExpr();
+ if (auto *PackExpr = dyn_cast<PackIndexingExpr>(E))
+ IDExpr = PackExpr->getSelectedExpr();
+
// C++11 [dcl.type.simple]p4:
// The type denoted by decltype(e) is defined as follows:
@@ -9798,6 +9818,46 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
return Context.getDecltypeType(E, getDecltypeForExpr(E));
}
+QualType Sema::ActOnPackIndexingType(QualType Pattern, Expr *IndexExpr,
+ SourceLocation Loc,
+ SourceLocation EllipsisLoc) {
+ if (!Pattern->containsUnexpandedParameterPack()) {
+ Diag(EllipsisLoc, diag::err_expected_name_of_pack) << Pattern;
+ return QualType();
+ }
+ return BuildPackIndexingType(Pattern, IndexExpr, Loc, EllipsisLoc);
+}
+
+QualType Sema::BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
+ SourceLocation Loc,
+ SourceLocation EllipsisLoc,
+ bool FullyExpanded,
+ ArrayRef<QualType> Expansions) {
+
+ std::optional<int64_t> Index;
+ if (FullyExpanded && !IndexExpr->isValueDependent() &&
+ !IndexExpr->isTypeDependent()) {
+ llvm::APSInt Value(Context.getIntWidth(Context.getSizeType()));
+ // TODO: do we need a new enumerator instead of CCEK_ArrayBound?
+ ExprResult Res = CheckConvertedConstantExpression(
+ IndexExpr, Context.getSizeType(), Value, CCEK_ArrayBound);
+ if (!Res.isUsable())
+ return QualType();
+ Index = Value.getExtValue();
+ }
+
+ if (FullyExpanded && Index) {
+ if (*Index < 0 || *Index >= int64_t(Expansions.size())) {
+ Diag(IndexExpr->getBeginLoc(), diag::err_pack_index_out_of_bound)
+ << *Index << Pattern << Expansions.size();
+ return QualType();
+ }
+ }
+
+ return Context.getPackIndexingType(Pattern, IndexExpr, FullyExpanded,
+ Expansions, Index.value_or(-1));
+}
+
static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType,
SourceLocation Loc) {
assert(BaseType->isEnumeralType());
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 40028544e23c8e1..22d7a0f51d5b104 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1047,6 +1047,12 @@ class TreeTransform {
/// Subclasses may override this routine to provide different behavior.
QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc);
+ QualType RebuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
+ SourceLocation Loc,
+ SourceLocation EllipsisLoc,
+ bool FullyExpanded,
+ ArrayRef<QualType> Expansions = {});
+
/// Build a new C++11 auto type.
///
/// By default, builds a new AutoType with the given deduced type.
@@ -3582,6 +3588,16 @@ class TreeTransform {
RParenLoc, Length, PartialArgs);
}
+ ExprResult RebuildPackIndexingExpr(SourceLocation EllipsisLoc,
+ SourceLocation RSquareLoc,
+ Expr *PackIdExpression, Expr *IndexExpr,
+ ArrayRef<Expr *> ExpandedExprs,
+ bool EmptyPack = false) {
+ return getSema().BuildPackIndexingExpr(PackIdExpression, EllipsisLoc,
+ IndexExpr, RSquareLoc, ExpandedExprs,
+ EmptyPack);
+ }
+
/// Build a new expression representing a call to a source location
/// builtin.
///
@@ -6482,6 +6498,100 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
return Result;
}
+template <typename Derived>
+QualType
+TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
+ PackIndexingTypeLoc TL) {
+ // Transform the index
+ ExprResult IndexExpr = getDerived().TransformExpr(TL.getIndexExpr());
+ if (IndexExpr.isInvalid())
+ return QualType();
+ QualType Pattern = TL.getPattern();
+
+ const PackIndexingType *PIT = TL.getTypePtr();
+ SmallVector<QualType, 5> ExpandedTypes;
+ llvm::ArrayRef<QualType> Types = PIT->getExpansions();
+
+ bool NotYetExpanded = Types.empty();
+ bool FullyExpanded = true;
+
+ if (Types.empty())
+ Types = llvm::ArrayRef<QualType>(&Pattern, 1);
+
+ for (const QualType &T : Types) {
+ if (!T->containsUnexpandedParameterPack()) {
+ QualType Transformed = getDerived().TransformType(T);
+ if (Transformed.isNull())
+ return QualType();
+ ExpandedTypes.push_back(Transformed);
+ continue;
+ }
+
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ getSema().collectUnexpandedParameterPacks(T, Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool ShouldExpand = true;
+ bool RetainExpansion = false;
+ std::optional<unsigned> OrigNumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
+ if (getDerived().TryExpandParameterPacks(TL.getEllipsisLoc(), SourceRange(),
+ Unexpanded, ShouldExpand,
+ RetainExpansion, NumExpansions))
+ return QualType();
+ if (!ShouldExpand) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+ QualType Pack = getDerived().TransformType(T);
+ if (Pack.isNull())
+ return QualType();
+ if (NotYetExpanded) {
+ FullyExpanded = false;
+ QualType Out = getDerived().RebuildPackIndexingType(
+ Pack, IndexExpr.get(), SourceLocation(), TL.getEllipsisLoc(),
+ FullyExpanded);
+ if (Out.isNull())
+ return QualType();
+
+ PackIndexingTypeLoc Loc = TLB.push<PackIndexingTypeLoc>(Out);
+ Loc.setEllipsisLoc(TL.getEllipsisLoc());
+ return Out;
+ }
+ ExpandedTypes.push_back(Pack);
+ continue;
+ }
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
+ QualType Out = getDerived().TransformType(T);
+ if (Out.isNull())
+ return QualType();
+ ExpandedTypes.push_back(Out);
+ }
+ // If we're supposed to retain a pack expansion, do so by temporarily
+ // forgetting the partially-substituted parameter pack.
+ if (RetainExpansion) {
+ FullyExpanded = false;
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+ QualType Out = getDerived().TransformType(T);
+ if (Out.isNull())
+ return QualType();
+ ExpandedTypes.push_back(Out);
+ }
+ }
+
+ QualType Result = getDerived().TransformType(TLB, TL.getPatternLoc());
+
+ QualType Out = getDerived().RebuildPackIndexingType(
+ Result, IndexExpr.get(), SourceLocation(), TL.getEllipsisLoc(),
+ FullyExpanded, ExpandedTypes);
+ if (Out.isNull())
+ return Out;
+
+ PackIndexingTypeLoc Loc = TLB.push<PackIndexingTypeLoc>(Out);
+ Loc.setEllipsisLoc(TL.getEllipsisLoc());
+ return Out;
+}
+
template<typename Derived>
QualType TreeTransform<Derived>::TransformUnaryTransformType(
TypeLocBuilder &TLB,
@@ -14158,6 +14268,87 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
Args.size(), std::nullopt);
}
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
+ if (!E->isValueDependent())
+ return E;
+
+ // Transform the index
+ ExprResult IndexExpr = getDerived().TransformExpr(E->getIndexExpr());
+ if (IndexExpr.isInvalid())
+ return ExprError();
+
+ SmallVector<Expr *, 5> ExpandedExprs;
+ if (E->getExpressions().empty()) {
+ Expr *Pattern = E->getPackIdExpression();
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ getSema().collectUnexpandedParameterPacks(E->getPackIdExpression(),
+ Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool ShouldExpand = true;
+ bool RetainExpansion = false;
+ std::optional<unsigned> OrigNumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
+ if (getDerived().TryExpandParameterPacks(
+ E->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded,
+ ShouldExpand, RetainExpansion, NumExpansions))
+ return true;
+ if (!ShouldExpand) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+ ExprResult Pack = getDerived().TransformExpr(Pattern);
+ if (Pack.isInvalid())
+ return ExprError();
+ return getDerived().RebuildPackIndexingExpr(
+ E->getEllipsisLoc(), E->getRSquareLoc(), Pack.get(), IndexExpr.get(),
+ std::nullopt);
+ }
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
+ ExprResult Out = getDerived().TransformExpr(Pattern);
+ if (Out.isInvalid())
+ return true;
+ if (Out.get()->containsUnexpandedParameterPack()) {
+ Out = getDerived().RebuildPackExpansion(Out.get(), E->getEllipsisLoc(),
+ OrigNumExpansions);
+ if (Out.isInvalid())
+ return true;
+ }
+ ExpandedExprs.push_back(Out.get());
+ }
+ // If we're supposed to retain a pack expansion, do so by temporarily
+ // forgetting the partially-substituted parameter pack.
+ if (RetainExpansion) {
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+
+ ExprResult Out = getDerived().TransformExpr(Pattern);
+ if (Out.isInvalid())
+ return true;
+
+ Out = getDerived().RebuildPackExpansion(Out.get(), E->getEllipsisLoc(),
+ OrigNumExpansions);
+ if (Out.isInvalid())
+ return true;
+ ExpandedExprs.push_back(Out.get());
+ }
+ }
+
+ else {
+ if (getDerived().TransformExprs(E->getExpressions().data(),
+ E->getExpressions().size(), false,
+ ExpandedExprs))
+ return ExprError();
+ }
+
+ return getDerived().RebuildPackIndexingExpr(
+ E->getEllipsisLoc(), E->getRSquareLoc(), E->getPackIdExpression(),
+ IndexExpr.get(), ExpandedExprs,
+ /*EmptyPack=*/ExpandedExprs.size() == 0);
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
@@ -15199,6 +15390,15 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, SourceLocation) {
return SemaRef.BuildDecltypeType(E);
}
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildPackIndexingType(
+ QualType Pattern, Expr *IndexExpr, SourceLocation Loc,
+ SourceLocation EllipsisLoc, bool FullyExpanded,
+ ArrayRef<QualType> Expansions) {
+ return SemaRef.BuildPackIndexingType(Pattern, IndexExpr, Loc, EllipsisLoc,
+ FullyExpanded, Expansions);
+}
+
template<typename Derived>
QualType TreeTransform<Derived>::RebuildUnaryTransformType(QualType BaseType,
UnaryTransformType::UTTKind UKind,
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index fecd94e875f671a..89b044a61a7b15f 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -6946,6 +6946,10 @@ void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
TL.setRParenLoc(readSourceLocation());
}
+void TypeLocReader::VisitPackIndexingTypeLoc(PackIndexingTypeLoc TL) {
+ TL.setEllipsisLoc(readSourceLocation());
+}
+
void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
TL.setKWLoc(readSourceLocation());
TL.setLParenLoc(readSourceLocation());
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 85ecfa1a1a0bf2a..583bc616161e552 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2174,6 +2174,22 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
}
}
+void ASTStmtReader::VisitPackIndexingExpr(PackIndexingExpr *E) {
+ VisitExpr(E);
+ unsigned NumTransformedExprs = Record.readInt();
+ E->EllipsisLoc = readSourceLocation();
+ E->RSquareLoc = readSourceLocation();
+ E->SubExprs[0] = Record.readStmt();
+ E->SubExprs[1] = Record.readStmt();
+ E->TransformedExpressions = NumTransformedExprs;
+ bool HasIndexValue = Record.readBool();
+ if (HasIndexValue)
+ E->Index = Record.readInt();
+ auto **Exprs = E->getTrailingObjects<Expr *>();
+ for (unsigned I = 0; I < NumTransformedExprs; ++I)
+ Exprs[I] = Record.readExpr();
+}
+
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
@@ -4102,6 +4118,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
/*NumPartialArgs=*/Record[ASTStmtReader::NumExprFields]);
break;
+ case EXPR_PACK_INDEXING:
+ S = PackIndexingExpr::CreateDeserialized(
+ Context,
+ /*TransformedExprs=*/Record[ASTStmtReader::NumExprFields]);
+ break;
+
case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM:
S = new (Context) SubstNonTypeTemplateParmExpr(Empty);
break;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 03bddfe0f5047db..eb2f8e237109973 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -482,6 +482,10 @@ void ASTRecordWriter::AddConceptReference(const ConceptReference *CR) {
AddASTTemplateArgumentListInfo(CR->getTemplateArgsAsWritten());
}
+void TypeLocWriter::VisitPackIndexingTypeLoc(PackIndexingTypeLoc TL) {
+ addSourceLocation(TL.getEllipsisLoc());
+}
+
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
addSourceLocation(TL.getNameLoc());
auto *CR = TL.getConceptReference();
@@ -784,6 +788,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_ARRAY_TYPE_TRAIT);
RECORD(EXPR_PACK_EXPANSION);
RECORD(EXPR_SIZEOF_PACK);
+ RECORD(EXPR_PACK_INDEXING);
RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM);
RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK);
RECORD(EXPR_FUNCTION_PARM_PACK);
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index e5836f5dcbe955a..e71dba536b6eda7 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2153,6 +2153,22 @@ void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
Code = serialization::EXPR_SIZEOF_PACK;
}
+void ASTStmtWriter::VisitPackIndexingExpr(PackIndexingExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->TransformedExpressions);
+ Record.AddSourceLocation(E->getEllipsisLoc());
+ Record.AddSourceLocation(E->getRSquareLoc());
+ Record.AddStmt(E->getPackIdExpression());
+ Record.AddStmt(E->getIndexExpr());
+ Record.push_back(E->Index.has_value());
+ if (E->Index.has_value())
+ Record.push_back(*E->Index);
+ Record.push_back(E->TransformedExpressions);
+ for (Expr *Sub : E->getExpressions())
+ Record.AddStmt(Sub);
+ Code = serialization::EXPR_PACK_INDEXING;
+}
+
void ASTStmtWriter::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 24e91a22fd6884f..ccc3c0f1e0c1002 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1737,6 +1737,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::RecoveryExprClass:
case Stmt::CXXNoexceptExprClass:
case Stmt::PackExpansionExprClass:
+ case Stmt::PackIndexingExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
case Stmt::FunctionParmPackExprClass:
case Stmt::CoroutineBodyStmtClass:
diff --git a/clang/test/PCH/pack_indexing.cpp b/clang/test/PCH/pack_indexing.cpp
new file mode 100644
index 000000000000000..cf8124617b3c681
--- /dev/null
+++ b/clang/test/PCH/pack_indexing.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++2c -x c++-header %s -emit-pch -o %t.pch
+// RUN: %clang_cc1 -std=c++2c -x c++ /dev/null -include-pch %t.pch
+
+// RUN: %clang_cc1 -std=c++2c -x c++-header %s -emit-pch -fpch-instantiate-templates -o %t.pch
+// RUN: %clang_cc1 -std=c++2c -x c++ /dev/null -include-pch %t.pch
+
+template <int I, typename... U>
+using Type = U...[I];
+
+template <int I, auto...V>
+constexpr auto Var = V...[I];
+
+void fn1() {
+ using A = Type<1, int, long, double>;
+ constexpr auto V = Var<2, 0, 1, 42>;
+}
diff --git a/clang/test/Parser/cxx2b-pack-indexing.cpp b/clang/test/Parser/cxx2b-pack-indexing.cpp
new file mode 100644
index 000000000000000..1e92705dd66c829
--- /dev/null
+++ b/clang/test/Parser/cxx2b-pack-indexing.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -std=c++2c -verify -fsyntax-only %s
+
+template<typename... T>
+struct S {
+ T...1; // expected-error{{expected member name or ';' after declaration specifiers}}
+ T...[; // expected-error{{expected expression}} \
+ // expected-error{{expected ']'}} \
+ // expected-note {{to match this '['}}\
+ // expected-warning{{declaration does not declare anything}}
+
+ T...[1; // expected-error{{expected ']'}} \
+ // expected-note {{to match this '['}}\
+ // expected-warning{{declaration does not declare anything}}
+
+ T...[]; // expected-error{{expected expression}} \
+ // expected-warning{{declaration does not declare anything}}
+
+ void f(auto... v) {
+ decltype(v...[1]) a = v...[1];
+ decltype(v...[1]) b = v...[]; // expected-error{{expected expression}}
+
+ decltype(v...[1]) c = v...[ ; // expected-error{{expected expression}}\
+ // expected-error{{expected ']'}} \
+ // expected-note {{to match this '['}}
+ }
+};
+
+
+template <typename...>
+struct typelist{};
+
+template <typename... T>
+requires requires(T...[0]) { {T...[0](0)}; }
+struct SS : T...[1] {
+ [[no_unique_address]] T...[1] base = {};
+ using foo = T...[1];
+ SS()
+ : T...[1]()
+ {}
+ typelist<T...[0]> a;
+ const T...[0] f(T...[0] && p) noexcept((T...[0])0) {
+ T...[0] (*test)(const volatile T...[0]**);
+ thread_local T...[0] d;
+ [[maybe_unused]] T...[0] a = p;
+ auto ptr = new T...[0](0);
+ (*ptr).~T...[0]();
+ return T...[0](0);
+ typename T...[1]::foo b = 0;
+ T...[1]::i = 0;
+ return (T...[0])(a);
+ new T...[0];
+ [[maybe_unused]] auto l = []<T...[0]>(T...[0][1]) -> T...[0]{return{};};
+ [[maybe_unused]] auto _ = l.template operator()<T...[0]{}>({0});
+ }
+ operator T...[0]() const{}
+};
+
+struct base {
+ using foo = int;
+ static inline int i = 42;
+};
+
+int main() {
+ SS<int, base>().f(0);
+}
diff --git a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp b/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
new file mode 100644
index 000000000000000..31138fb6730c433
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
@@ -0,0 +1,115 @@
+// RUN: %clang_cc1 -std=c++2c -verify %s
+
+struct NotAPack;
+template <typename T, auto V, template<typename> typename Tp>
+void not_pack() {
+ int i = 0;
+ i...[0]; // expected-error {{i does not refer to the name of a parameter pack}}
+ V...[0]; // expected-error {{V does not refer to the name of a parameter pack}}
+ NotAPack...[0]; // expected-error{{'NotAPack' does not refer to the name of a parameter pack}}
+ T...[0]; // expected-error{{'T' does not refer to the name of a parameter pack}}
+ Tp...[0]; // expected-error{{'Tp' does not refer to the name of a parameter pack}}
+}
+
+namespace invalid_indexes {
+
+int non_constant_index(); // expected-note 2{{declared here}}
+
+template <int idx>
+int params(auto... p) {
+ return p...[idx]; //expected-error 3{{is not a valid index for pack p of size}}
+}
+
+template <auto N, typename...T>
+int test_types() {
+ T...[N] a; // expected-error 4{{is not a valid index for pack 'T' of size}}
+}
+
+void test() {
+ params<0>(); // expected-note{{here}}
+ params<1>(0); // expected-note{{here}}
+ params<-1>(0); // expected-note{{here}}
+
+ test_types<-1>(); //expected-note {{in instantiation}}
+ test_types<-1, int>(); //expected-note {{in instantiation}}
+ test_types<0>(); //expected-note {{in instantiation}}
+ test_types<1, int>(); //expected-note {{in instantiation}}
+}
+
+void invalid_indexes(auto... p) {
+ p...[non_constant_index()]; // expected-error {{array size is not a constant expression}}\
+ // expected-note {{cannot be used in a constant expression}}
+
+ const char* no_index = "";
+ p...[no_index]; // expected-error {{value of type 'const char *' is not implicitly convertible to 'unsigned long'}}
+}
+
+void invalid_index_types() {
+ []<typename... T> {
+ T...[non_constant_index()] a; // expected-error {{array size is not a constant expression}}\
+ // expected-note {{cannot be used in a constant expression}}
+ }(); //expected-note {{in instantiation}}
+}
+
+}
+
+template <typename T, typename U>
+constexpr bool is_same = false;
+
+template <typename T>
+constexpr bool is_same<T, T> = true;
+
+template <typename T>
+constexpr bool f(auto&&... p) {
+ return is_same<T, decltype(p...[0])>;
+}
+
+void g() {
+ int a = 0;
+ const int b = 0;
+ static_assert(f<int&&>(0));
+ static_assert(f<int&>(a));
+ static_assert(f<const int&>(b));
+}
+
+template <auto... p>
+struct check_ice {
+ enum e {
+ x = p...[0]
+ };
+};
+
+static_assert(check_ice<42>::x == 42);
+
+struct S{};
+template <auto... p>
+constexpr auto constant_initializer = p...[0];
+constexpr auto InitOk = constant_initializer<S{}>;
+
+consteval int evaluate(auto... p) {
+ return p...[0];
+}
+constexpr int x = evaluate(42, S{});
+static_assert(x == 42);
+
+
+namespace splice {
+template <auto ... Is>
+struct IL{};
+
+template <typename ... Ts>
+struct TL{};
+
+template <typename Tl, typename Il>
+struct SpliceImpl;
+
+template <typename ... Ts, auto ...Is>
+struct SpliceImpl<TL<Ts...>, IL<Is...>>{
+ using type = TL<Ts...[Is]...>;
+};
+
+template <typename Tl, typename Il>
+using Splice = typename SpliceImpl<Tl, Il>::type;
+using type = Splice<TL<char, short, long, double>, IL<1, 2>>;
+static_assert(is_same<type, TL<short, long>>);
+}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index b03ad6054b9acf1..0f92d3395a3f53a 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1891,6 +1891,12 @@ bool CursorVisitor::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
return false;
}
+bool CursorVisitor::VisitPackIndexingTypeLoc(PackIndexingTypeLoc TL) {
+ if (Visit(TL.getPatternLoc()))
+ return true;
+ return Visit(MakeCXCursor(TL.getIndexExpr(), StmtParent, TU));
+}
+
bool CursorVisitor::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
}
@@ -5718,6 +5724,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("PackExpansionExpr");
case CXCursor_SizeOfPackExpr:
return cxstring::createRef("SizeOfPackExpr");
+ case CXCursor_PackIndexingExpr:
+ return cxstring::createRef("PackIndexingExpr");
case CXCursor_LambdaExpr:
return cxstring::createRef("LambdaExpr");
case CXCursor_UnexposedExpr:
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index 978adac5521aaa0..01b8a23f6eac3ba 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -567,6 +567,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
K = CXCursor_SizeOfPackExpr;
break;
+ case Stmt::PackIndexingExprClass:
+ K = CXCursor_PackIndexingExpr;
+ break;
+
case Stmt::DeclRefExprClass:
if (const ImplicitParamDecl *IPD = dyn_cast_or_null<ImplicitParamDecl>(
cast<DeclRefExpr>(S)->getDecl())) {
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index a48f35eb5048378..d9d9e9eb607902c 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -156,7 +156,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
<tr>
<td>Pack Indexing</td>
<td><a href="https://wg21.link/P2662R3">P2662R3</a></td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">Clang 18</td>
</tr>
<tr>
<td>Remove Deprecated Arithmetic Conversion on Enumerations</td>
>From b2c99f7c674d901ef251dbb42e4d0a82be44cedb Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Jan 2024 14:58:15 +0100
Subject: [PATCH 02/12] Address some comments from Erich
---
clang/include/clang-c/Index.h | 2 +-
clang/include/clang/AST/Type.h | 2 +-
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/include/clang/Basic/Specifiers.h | 2 +-
clang/include/clang/Basic/TokenKinds.def | 2 +-
clang/include/clang/Sema/DeclSpec.h | 7 ++++---
clang/lib/AST/ExprCXX.cpp | 2 +-
clang/lib/AST/TypePrinter.cpp | 1 -
clang/lib/Parse/ParseCXXInlineMethods.cpp | 3 +--
clang/lib/Parse/ParseDecl.cpp | 4 ++--
clang/lib/Parse/ParseDeclCXX.cpp | 14 +++++++-------
clang/lib/Parse/ParseExpr.cpp | 4 ++--
clang/lib/Parse/ParseExprCXX.cpp | 2 +-
clang/lib/Parse/ParseTentative.cpp | 4 ++--
clang/lib/Parse/Parser.cpp | 2 +-
clang/lib/Sema/DeclSpec.cpp | 8 ++++----
clang/lib/Sema/SemaCXXScopeSpec.cpp | 2 +-
clang/lib/Sema/SemaDecl.cpp | 2 +-
clang/lib/Sema/SemaDeclCXX.cpp | 2 +-
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
clang/lib/Sema/SemaTemplateDeduction.cpp | 5 ++++-
clang/lib/Sema/SemaTemplateVariadic.cpp | 6 +++---
clang/lib/Sema/SemaType.cpp | 4 ++--
clang/lib/Serialization/ASTReaderStmt.cpp | 5 ++---
clang/test/SemaCXX/cxx2b-pack-indexing.cpp | 4 ++--
25 files changed, 47 insertions(+), 46 deletions(-)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 2c0b89a0d12b21e..b667d406dfa5e59 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -1686,7 +1686,7 @@ enum CXCursorKind {
CXCursor_CXXParenListInitExpr = 155,
/**
- * Represents a C++26 pack indexing expression
+ * Represents a C++26 pack indexing expression.
*/
CXCursor_PackIndexingExpr = 156,
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 16598ec9860b24f..7b2dc106bafba80 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -4970,7 +4970,7 @@ class PackIndexingType final
return *(getExpansionsPtr() + Index);
}
- bool hasSelectedType() const { return Index != -1 && !isDependentType(); }
+ bool hasSelectedType() const { return !isDependentType(); }
ArrayRef<QualType> getExpansions() const {
return {getExpansionsPtr(), Size};
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e9e203fc27691b4..235e09262ec8977 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5725,7 +5725,7 @@ def err_expected_name_of_pack : Error<
"%0 does not refer to the name of a parameter pack">;
def err_pack_index_out_of_bound : Error<
- "%0 is not a valid index for pack %1 of size %2">;
+ "invalid index %0 for pack %1 of size %2">;
def err_fold_expression_packs_both_sides : Error<
"binary fold expression has unexpanded parameter packs in both operands">;
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index bff4c1616c1d027..c0c5e4b6806f826 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -94,7 +94,7 @@ namespace clang {
TST_auto_type, // __auto_type extension
TST_unknown_anytype, // __unknown_anytype extension
TST_atomic, // C11 _Atomic
- TST_indexed_typename_pack,
+ TST_typename_pack_indexing,
#define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types
#include "clang/Basic/OpenCLImageTypes.def"
TST_error // erroneous type
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index e8b93e0bd1b5dee..9117e4376c37155 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -840,7 +840,7 @@ ANNOTATION(primary_expr) // annotation for a primary expression, used when
// message send
ANNOTATION(decltype) // annotation for a decltype expression,
// e.g., "decltype(foo.bar())"
-ANNOTATION(indexed_pack_type) // annotation for an indexed pack of type,
+ANNOTATION(pack_indexing_type) // annotation for an indexed pack of type,
// e.g., "T...[expr]"
// Annotation for #pragma unused(...)
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 4726cbbd1af50c9..77638def60063d9 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -309,7 +309,8 @@ class DeclSpec {
static const TST TST_typeof_unqualExpr = clang::TST_typeof_unqualExpr;
static const TST TST_decltype = clang::TST_decltype;
static const TST TST_decltype_auto = clang::TST_decltype_auto;
- static const TST TST_indexed_typename_pack = clang::TST_indexed_typename_pack;
+ static const TST TST_typename_pack_indexing =
+ clang::TST_typename_pack_indexing;
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
static const TST TST_##Trait = clang::TST_##Trait;
#include "clang/Basic/TransformTypeTraits.def"
@@ -430,7 +431,7 @@ class DeclSpec {
static bool isTypeRep(TST T) {
return T == TST_atomic || T == TST_typename || T == TST_typeofType ||
T == TST_typeof_unqualType || isTransformTypeTrait(T) ||
- T == TST_indexed_typename_pack;
+ T == TST_typename_pack_indexing;
}
static bool isExprRep(TST T) {
return T == TST_typeofExpr || T == TST_typeof_unqualExpr ||
@@ -535,7 +536,7 @@ class DeclSpec {
}
Expr *getPackIndexingExpr() const {
- assert(TypeSpecType == TST_indexed_typename_pack &&
+ assert(TypeSpecType == TST_typename_pack_indexing &&
"DeclSpec is not a pack indexing expr");
return PackIndexingExpr;
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 141654e0abf02df..04ad0fb2d84ba2b 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1690,7 +1690,7 @@ NamedDecl *PackIndexingExpr::getPackDecl() const {
assert(ND && "exected a named decl");
return ND;
}
- assert(false && "Non variables packs not supported");
+ assert(false && "invalid declaration kind in pack indexing expression");
return nullptr;
}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index e5e8211f55e578c..63e56a8296db381 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -284,7 +284,6 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::FunctionNoProto:
case Type::Paren:
case Type::PackExpansion:
-
case Type::SubstTemplateTypeParm:
case Type::MacroQualified:
CanPrefixQualifiers = false;
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 518a168ee246fb0..d790060c17c0496 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -979,8 +979,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
break;
}
// Pack indexing
- if (getLangOpts().CPlusPlus26 && Tok.is(tok::ellipsis) &&
- NextToken().is(tok::l_square)) {
+ if (Tok.is(tok::ellipsis) && NextToken().is(tok::l_square)) {
Toks.push_back(Tok);
SourceLocation OpenLoc = ConsumeToken();
Toks.push_back(Tok);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 85a810030908197..199bde59481eeff 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4447,7 +4447,7 @@ void Parser::ParseDeclarationSpecifiers(
ParseDecltypeSpecifier(DS);
continue;
- case tok::annot_indexed_pack_type:
+ case tok::annot_pack_indexing_type:
ParseIndexedTypeNamePack(DS);
continue;
@@ -5760,7 +5760,7 @@ bool Parser::isDeclarationSpecifier(
// C++11 decltype and constexpr.
case tok::annot_decltype:
- case tok::annot_indexed_pack_type:
+ case tok::annot_pack_indexing_type:
case tok::kw_constexpr:
// C++20 consteval and constinit.
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index c066a758b8e0e5e..f223709a23542d1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1197,7 +1197,7 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
}
SourceLocation Parser::ParseIndexedTypeNamePack(DeclSpec &DS) {
- assert(Tok.isOneOf(tok::annot_indexed_pack_type, tok::identifier) &&
+ assert(Tok.isOneOf(tok::annot_pack_indexing_type, tok::identifier) &&
"Expected an identifier");
TypeResult Type;
@@ -1207,7 +1207,7 @@ SourceLocation Parser::ParseIndexedTypeNamePack(DeclSpec &DS) {
unsigned DiagID;
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
- if (Tok.is(tok::annot_indexed_pack_type)) {
+ if (Tok.is(tok::annot_pack_indexing_type)) {
StartLoc = Tok.getLocation();
SourceLocation EndLoc;
Type = getTypeAnnotation(Tok);
@@ -1220,7 +1220,7 @@ SourceLocation Parser::ParseIndexedTypeNamePack(DeclSpec &DS) {
DS.SetTypeSpecError();
return EndLoc;
}
- DS.SetTypeSpecType(DeclSpec::TST_indexed_typename_pack, StartLoc, PrevSpec,
+ DS.SetTypeSpecType(DeclSpec::TST_typename_pack_indexing, StartLoc, PrevSpec,
DiagID, Type, Policy);
return EndLoc;
} else {
@@ -1278,7 +1278,7 @@ void Parser::AnnotateExistingIndexedTypeNamePack(ParsedType T,
} else
PP.EnterToken(Tok, /*IsReinject*/ true);
- Tok.setKind(tok::annot_indexed_pack_type);
+ Tok.setKind(tok::annot_pack_indexing_type);
setTypeAnnotation(Tok, T);
Tok.setAnnotationEndLoc(EndLoc);
Tok.setLocation(StartLoc);
@@ -1382,7 +1382,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
return Actions.ActOnTypeName(DeclaratorInfo);
}
- if (Tok.is(tok::annot_indexed_pack_type)) {
+ if (Tok.is(tok::annot_pack_indexing_type)) {
DeclSpec DS(AttrFactory);
ParseIndexedTypeNamePack(DS);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
@@ -3933,9 +3933,9 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// ParseOptionalCXXScopeSpecifier at this point.
// FIXME: Can we get here with a scope specifier?
ParseDecltypeSpecifier(DS);
- } else if (Tok.is(tok::annot_indexed_pack_type)) {
+ } else if (Tok.is(tok::annot_pack_indexing_type)) {
// Uses of T...[N] will already have been converted to
- // annot_indexed_pack_type by ParseOptionalCXXScopeSpecifier at this point.
+ // annot_pack_indexing_type by ParseOptionalCXXScopeSpecifier at this point.
ParseIndexedTypeNamePack(DS);
} else {
TemplateIdAnnotation *TemplateId = Tok.is(tok::annot_template_id)
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index dc65832c06f3a5c..dd77e9b8bd9d4b2 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1073,7 +1073,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// If the token is not annotated, then it might be an expression pack
// indexing
if (!TryAnnotateTypeOrScopeToken() &&
- Tok.is(tok::annot_indexed_pack_type))
+ Tok.is(tok::annot_pack_indexing_type))
return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
isVectorLiteral, NotPrimaryExpression);
}
@@ -1561,7 +1561,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
[[fallthrough]];
case tok::annot_decltype:
- case tok::annot_indexed_pack_type:
+ case tok::annot_pack_indexing_type:
case tok::kw_char:
case tok::kw_wchar_t:
case tok::kw_char8_t:
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 33d88b4e6294554..218b8542756e59c 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -2426,7 +2426,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetRangeEnd(ParseDecltypeSpecifier(DS));
return DS.Finish(Actions, Policy);
- case tok::annot_indexed_pack_type:
+ case tok::annot_pack_indexing_type:
DS.SetRangeEnd(ParseIndexedTypeNamePack(DS));
return DS.Finish(Actions, Policy);
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 09b62a13310b628..8bfcd39ca32161a 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1793,7 +1793,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
case tok::kw__Accum:
case tok::kw__Fract:
case tok::kw__Sat:
- case tok::annot_indexed_pack_type:
+ case tok::annot_pack_indexing_type:
#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
if (NextToken().is(tok::l_paren))
@@ -1872,7 +1872,7 @@ bool Parser::isCXXDeclarationSpecifierAType() {
switch (Tok.getKind()) {
// typename-specifier
case tok::annot_decltype:
- case tok::annot_indexed_pack_type:
+ case tok::annot_pack_indexing_type:
case tok::annot_template_id:
case tok::annot_typename:
case tok::kw_typeof:
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 8f98182cad24f1e..3dfd44677e5a2cc 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1993,7 +1993,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(
Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) ||
Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) ||
Tok.is(tok::kw___super) || Tok.is(tok::kw_auto) ||
- Tok.is(tok::annot_indexed_pack_type)) &&
+ Tok.is(tok::annot_pack_indexing_type)) &&
"Cannot be a type or scope token!");
if (Tok.is(tok::kw_typename)) {
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 2a559561c810c4d..313f073445e8f20 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -374,7 +374,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_void:
case TST_wchar:
case TST_BFloat16:
- case TST_indexed_typename_pack:
+ case TST_typename_pack_indexing:
#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
return false;
@@ -586,7 +586,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_struct: return "struct";
case DeclSpec::TST_interface: return "__interface";
case DeclSpec::TST_typename: return "type-name";
- case DeclSpec::TST_indexed_typename_pack:
+ case DeclSpec::TST_typename_pack_indexing:
return "type-name-pack-indexing";
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
@@ -779,7 +779,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
TSTNameLoc = TagNameLoc;
TypeSpecOwned = false;
- if (T == TST_indexed_typename_pack) {
+ if (T == TST_typename_pack_indexing) {
// we got there from a an annotation. Reconstruct the type
// Ugly...
QualType QT = Rep.get();
@@ -989,7 +989,7 @@ void DeclSpec::SetPackIndexingExpr(SourceLocation EllipsisLoc,
Expr *IndexingExpr) {
assert(TypeSpecType == TST_typename &&
"pack indexing can only be applied to typename");
- TypeSpecType = TST_indexed_typename_pack;
+ TypeSpecType = TST_typename_pack_indexing;
PackIndexingExpr = IndexingExpr;
this->EllipsisLoc = EllipsisLoc;
}
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 98833e931c6dad7..fca5bd131bbc0fa 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -874,7 +874,7 @@ bool Sema::ActOnCXXNestedNameSpecifierIndexedPack(CXXScopeSpec &SS,
if (SS.isInvalid() || DS.getTypeSpecType() == DeclSpec::TST_error)
return true;
- assert(DS.getTypeSpecType() == DeclSpec::TST_indexed_typename_pack);
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typename_pack_indexing);
if (Type.isNull())
return true;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index dc019a3a7dea5da..e725e187fc9ea08 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -163,7 +163,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw_char32_t:
case tok::kw_typeof:
case tok::annot_decltype:
- case tok::annot_indexed_pack_type:
+ case tok::annot_pack_indexing_type:
case tok::kw_decltype:
return getLangOpts().CPlusPlus;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 286f56f671b8b81..027f1ea3d3d9e6f 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4494,7 +4494,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
} else if (DS.getTypeSpecType() == TST_decltype_auto) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
return true;
- } else if (DS.getTypeSpecType() == TST_indexed_typename_pack) {
+ } else if (DS.getTypeSpecType() == TST_typename_pack_indexing) {
BaseType =
ActOnPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
DS.getBeginLoc(), DS.getEllipsisLoc());
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 87d4671147066d5..51c61886739bb91 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8116,7 +8116,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
break;
}
- case DeclSpec::TST_indexed_typename_pack: {
+ case DeclSpec::TST_typename_pack_indexing: {
T = ActOnPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
DS.getBeginLoc(), DS.getEllipsisLoc());
TLB.pushTrivial(getASTContext(),
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index b7ce44720ee32c6..c9234bf30a52862 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -6433,9 +6433,12 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
break;
case Type::PackIndexing:
- if (!OnlyDeduced)
+ if (!OnlyDeduced) {
MarkUsedTemplateParameters(Ctx, cast<PackIndexingType>(T)->getPattern(),
OnlyDeduced, Depth, Used);
+ MarkUsedTemplateParameters(Ctx, cast<PackIndexingType>(T)->getIndexExpr(),
+ OnlyDeduced, Depth, Used);
+ }
break;
case Type::UnaryTransform:
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index ff6cd66fe780b48..83b35cee9f4caac 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -874,7 +874,7 @@ std::optional<unsigned> Sema::getNumArgumentsInExpansion(
bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
switch (DS.getTypeSpecType()) {
- case TST_indexed_typename_pack:
+ case TST_typename_pack_indexing:
case TST_typename:
case TST_typeof_unqualType:
case TST_typeofType:
@@ -1071,7 +1071,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
}
static bool isParameterPack(Expr *PackExpression) {
- if (auto D = dyn_cast<DeclRefExpr>(PackExpression); D) {
+ if (auto *D = dyn_cast<DeclRefExpr>(PackExpression); D) {
ValueDecl *VD = D->getDecl();
return VD->isParameterPack();
}
@@ -1100,7 +1100,7 @@ Sema::BuildPackIndexingExpr(Expr *PackExpression, SourceLocation EllipsisLoc,
ArrayRef<Expr *> ExpandedExprs, bool EmptyPack) {
std::optional<int64_t> Index;
- if (!IndexExpr->isValueDependent() && !IndexExpr->isTypeDependent()) {
+ if (!IndexExpr->isInstantiationDependent()) {
llvm::APSInt Value(Context.getIntWidth(Context.getSizeType()));
// TODO: do we need a new enumerator instead of CCEK_ArrayBound?
ExprResult Res = CheckConvertedConstantExpression(
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 6cd2f26c10377ff..aa948a2d526f6ce 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1667,7 +1667,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
}
- case DeclSpec::TST_indexed_typename_pack: {
+ case DeclSpec::TST_typename_pack_indexing: {
Expr *E = DS.getPackIndexingExpr();
assert(E && "Didn't get an expression for pack indexing");
QualType Pattern = S.GetTypeFromParser(DS.getRepAsType());
@@ -6326,7 +6326,7 @@ namespace {
TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
}
void VisitPackIndexingTypeLoc(PackIndexingTypeLoc TL) {
- assert(DS.getTypeSpecType() == DeclSpec::TST_indexed_typename_pack);
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typename_pack_indexing);
TL.setEllipsisLoc(DS.getEllipsisLoc());
}
void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 583bc616161e552..0f3206b0909e2e1 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2176,17 +2176,16 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
void ASTStmtReader::VisitPackIndexingExpr(PackIndexingExpr *E) {
VisitExpr(E);
- unsigned NumTransformedExprs = Record.readInt();
+ E->TransformedExpressions = Record.readInt();
E->EllipsisLoc = readSourceLocation();
E->RSquareLoc = readSourceLocation();
E->SubExprs[0] = Record.readStmt();
E->SubExprs[1] = Record.readStmt();
- E->TransformedExpressions = NumTransformedExprs;
bool HasIndexValue = Record.readBool();
if (HasIndexValue)
E->Index = Record.readInt();
auto **Exprs = E->getTrailingObjects<Expr *>();
- for (unsigned I = 0; I < NumTransformedExprs; ++I)
+ for (unsigned I = 0; I < E->TransformedExpressions; ++I)
Exprs[I] = Record.readExpr();
}
diff --git a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp b/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
index 31138fb6730c433..352a735c4f3215b 100644
--- a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
+++ b/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
@@ -17,12 +17,12 @@ int non_constant_index(); // expected-note 2{{declared here}}
template <int idx>
int params(auto... p) {
- return p...[idx]; //expected-error 3{{is not a valid index for pack p of size}}
+ return p...[idx]; //expected-error 3{{invalid index 0 for pack p of size 0}}
}
template <auto N, typename...T>
int test_types() {
- T...[N] a; // expected-error 4{{is not a valid index for pack 'T' of size}}
+ T...[N] a; // expected-error 4{{invalid index -1 for pack 'T' of size 0}}
}
void test() {
>From e9acd751290b9df2fab194eeeb310960951b1e58 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Jan 2024 17:38:45 +0100
Subject: [PATCH 03/12] Address more of Erich's feedback - Add a
computeDependence function - Remove the Index fron the type / expression: we
do keep it around in some of the functions to avoid haviung to recompute the
index in multiple places in short sucession.
---
clang/include/clang/AST/ASTContext.h | 2 +-
clang/include/clang/AST/ComputeDependence.h | 2 ++
clang/include/clang/AST/ExprCXX.h | 40 ++++++++++-----------
clang/include/clang/AST/Type.h | 9 ++---
clang/include/clang/Sema/Sema.h | 2 +-
clang/lib/AST/ASTContext.cpp | 8 ++---
clang/lib/AST/ComputeDependence.cpp | 17 +++++++++
clang/lib/AST/ExprCXX.cpp | 2 +-
clang/lib/AST/Type.cpp | 13 +++++--
clang/lib/Sema/SemaTemplateVariadic.cpp | 1 +
clang/lib/Sema/SemaType.cpp | 9 ++---
clang/lib/Sema/TreeTransform.h | 29 ++++++++-------
clang/lib/Serialization/ASTReaderStmt.cpp | 3 --
clang/lib/Serialization/ASTWriterStmt.cpp | 3 --
clang/test/SemaCXX/cxx2b-pack-indexing.cpp | 27 ++++++++------
15 files changed, 97 insertions(+), 70 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 9e1c44eb19b805c..668462ef5460646 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1717,7 +1717,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
QualType getPackIndexingType(QualType Pattern, Expr *IndexExpr,
- bool FullyExpanded = false,
+ bool FullySubstituted = false,
ArrayRef<QualType> Expansions = {},
int Index = -1) const;
diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h
index f62611cb4c3cf77..7abf9141237dc87 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -63,6 +63,7 @@ class ArrayTypeTraitExpr;
class ExpressionTraitExpr;
class CXXNoexceptExpr;
class PackExpansionExpr;
+class PackIndexingExpr;
class SubstNonTypeTemplateParmExpr;
class CoroutineSuspendExpr;
class DependentCoawaitExpr;
@@ -150,6 +151,7 @@ ExprDependence computeDependence(ArrayTypeTraitExpr *E);
ExprDependence computeDependence(ExpressionTraitExpr *E);
ExprDependence computeDependence(CXXNoexceptExpr *E, CanThrowResult CT);
ExprDependence computeDependence(PackExpansionExpr *E);
+ExprDependence computeDependence(PackIndexingExpr *E);
ExprDependence computeDependence(SubstNonTypeTemplateParmExpr *E);
ExprDependence computeDependence(CoroutineSuspendExpr *E);
ExprDependence computeDependence(DependentCoawaitExpr *E);
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index af4f2de2f11b87b..18ec26682e4180e 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4346,36 +4346,23 @@ class PackIndexingExpr final
// The pack being indexed, followed by the index
Stmt *SubExprs[2];
- // The evaluated index
- std::optional<int64_t> Index;
-
size_t TransformedExpressions;
PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr,
- std::optional<int64_t> Index = std::nullopt,
ArrayRef<Expr *> SubstitutedExprs = {})
: Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
- SubExprs{PackIdExpr, IndexExpr}, Index(Index),
+ SubExprs{PackIdExpr, IndexExpr},
TransformedExpressions(SubstitutedExprs.size()) {
auto *Exprs = getTrailingObjects<Expr *>();
std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(),
Exprs);
- ExprDependence D = IndexExpr->getDependence();
- if (SubstitutedExprs.empty())
- D |= (PackIdExpr->getDependence() |
- ExprDependence::TypeValueInstantiation) &
- ~ExprDependence::UnexpandedPack;
- else if (!IndexExpr->isValueDependent()) {
- assert(Index && *Index < int64_t(SubstitutedExprs.size()) &&
- "pack index out of bound");
- D |= SubstitutedExprs[*Index]->getDependence();
- setValueKind(SubstitutedExprs[*Index]->getValueKind());
- }
- setDependence(D);
+ setDependence(computeDependence(this));
+ if(!isInstantiationDependent())
+ setValueKind(getSelectedExpr()->getValueKind());
}
/// Create an empty expression.
@@ -4389,8 +4376,7 @@ class PackIndexingExpr final
static PackIndexingExpr *Create(ASTContext &Context,
SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr,
- Expr *IndexExpr,
- std::optional<int64_t> Index = std::nullopt,
+ Expr *IndexExpr, std::optional<int64_t> Index,
ArrayRef<Expr *> SubstitutedExprs = {});
static PackIndexingExpr *CreateDeserialized(ASTContext &Context,
unsigned NumTransformedExprs);
@@ -4413,13 +4399,23 @@ class PackIndexingExpr final
Expr *getIndexExpr() const { return cast<Expr>(SubExprs[1]); }
+
+ std::optional<unsigned> getSelectedIndex() const {
+ if (isInstantiationDependent())
+ return std::nullopt;
+ ConstantExpr* CE = cast<ConstantExpr>(getIndexExpr());
+ auto Index = CE->getResultAsAPSInt();
+ assert(Index.isNonNegative() && "Invalid index");
+ return static_cast<unsigned>(Index.getExtValue());
+ }
+
Expr *getSelectedExpr() const {
- assert(Index && !isInstantiationDependent() &&
- "extracting the indexed expression of a dependant pack");
+ std::optional<unsigned> Index = getSelectedIndex();
+ assert(Index && "extracting the indexed expression of a dependant pack");
return getTrailingObjects<Expr *>()[*Index];
}
- llvm::ArrayRef<Expr *> getExpressions() const {
+ ArrayRef<Expr *> getExpressions() const {
if (TransformedExpressions == 0)
return {};
return {getTrailingObjects<Expr *>(), TransformedExpressions};
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 7b2dc106bafba80..d6a55f39a4bede1 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -4945,13 +4945,12 @@ class PackIndexingType final
Expr *IndexExpr;
unsigned Size;
- int Index = -1;
protected:
friend class ASTContext; // ASTContext creates these.
PackIndexingType(const ASTContext &Context, QualType Canonical,
QualType Pattern, Expr *IndexExpr,
- ArrayRef<QualType> Expansions = {}, int Index = -1);
+ ArrayRef<QualType> Expansions = {});
public:
Expr *getIndexExpr() const { return IndexExpr; }
@@ -4967,10 +4966,12 @@ class PackIndexingType final
QualType getSelectedType() const {
assert(hasSelectedType() && "Type is dependant");
- return *(getExpansionsPtr() + Index);
+ return *(getExpansionsPtr() + *getSelectedIndex());
}
- bool hasSelectedType() const { return !isDependentType(); }
+ std::optional<unsigned> getSelectedIndex() const;
+
+ bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; }
ArrayRef<QualType> getExpansions() const {
return {getExpansionsPtr(), Size};
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index abcf9aeee06adb0..b5946e3f3178ff2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2607,7 +2607,7 @@ class Sema final {
SourceLocation EllipsisLoc);
QualType BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
SourceLocation Loc, SourceLocation EllipsisLoc,
- bool FullyExpanded = false,
+ bool FullySubstituted = false,
ArrayRef<QualType> Expansions = {});
using UTTKind = UnaryTransformType::UTTKind;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 4512a0fbd1ef0f1..30832e7f6e56edd 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5703,11 +5703,11 @@ QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
}
QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
- bool FullyExpanded,
+ bool FullySubstituted,
ArrayRef<QualType> Expansions,
int Index) const {
QualType Canonical;
- if (FullyExpanded && Index != -1) {
+ if (FullySubstituted && Index != -1) {
Canonical = getCanonicalType(Expansions[Index]);
} else {
llvm::FoldingSetNodeID ID;
@@ -5720,7 +5720,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
Canon = new (Mem) PackIndexingType(*this, QualType(), Pattern, IndexExpr,
- Expansions, Index);
+ Expansions);
DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
}
Canonical = QualType(Canon, 0);
@@ -5730,7 +5730,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
Allocate(PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
auto *T = new (Mem)
- PackIndexingType(*this, Canonical, Pattern, IndexExpr, Expansions, Index);
+ PackIndexingType(*this, Canonical, Pattern, IndexExpr, Expansions);
Types.push_back(T);
return QualType(T, 0);
}
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 584b58473294beb..082fa2722388ff8 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -364,6 +364,23 @@ ExprDependence clang::computeDependence(PackExpansionExpr *E) {
ExprDependence::TypeValueInstantiation;
}
+ExprDependence clang::computeDependence(PackIndexingExpr *E) {
+ ExprDependence D = E->getIndexExpr()->getDependence();
+ ArrayRef<Expr *> Exprs = E->getExpressions();
+ if (Exprs.empty())
+ D |= (E->getPackIdExpression()->getDependence() |
+ ExprDependence::TypeValueInstantiation) &
+ ~ExprDependence::UnexpandedPack;
+ else if (!E->getIndexExpr()->isInstantiationDependent()) {
+ std::optional<unsigned> Index = E->getSelectedIndex();
+ assert(Index && *Index < Exprs.size() &&
+ "pack index out of bound");
+ D |= Exprs[*Index]->getDependence();
+ }
+ return D;
+}
+
+
ExprDependence clang::computeDependence(SubstNonTypeTemplateParmExpr *E) {
return E->getReplacement()->getDependence();
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 04ad0fb2d84ba2b..e2cfd1588cb4115 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1681,7 +1681,7 @@ PackIndexingExpr *PackIndexingExpr::Create(ASTContext &Context,
Context.Allocate(totalSizeToAlloc<Expr *>(SubstitutedExprs.size()));
return new (Storage)
PackIndexingExpr(Type, EllipsisLoc, RSquareLoc, PackIdExpr, IndexExpr,
- Index, SubstitutedExprs);
+ SubstitutedExprs);
}
NamedDecl *PackIndexingExpr::getPackDecl() const {
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 4cddc546fabbfef..92c4d06facc4022 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3816,16 +3816,25 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
PackIndexingType::PackIndexingType(const ASTContext &Context,
QualType Canonical, QualType Pattern,
Expr *IndexExpr,
- ArrayRef<QualType> Expansions, int Index)
+ ArrayRef<QualType> Expansions)
: Type(PackIndexing, Canonical,
computeDependence(Pattern, IndexExpr, Expansions)),
Context(Context), Pattern(Pattern), IndexExpr(IndexExpr),
- Size(Expansions.size()), Index(Index) {
+ Size(Expansions.size()) {
std::uninitialized_copy(Expansions.begin(), Expansions.end(),
getTrailingObjects<QualType>());
}
+std::optional<unsigned> PackIndexingType::getSelectedIndex() const {
+ if(isDependentType())
+ return std::nullopt;
+ ConstantExpr* CE = cast<ConstantExpr>(getIndexExpr());
+ auto Index = CE->getResultAsAPSInt();
+ assert(Index.isNonNegative() && "Invalid index");
+ return static_cast<unsigned>(Index.getExtValue());
+}
+
TypeDependence
PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr,
ArrayRef<QualType> Expansions) {
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 83b35cee9f4caac..b8e069bb96c7359 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1108,6 +1108,7 @@ Sema::BuildPackIndexingExpr(Expr *PackExpression, SourceLocation EllipsisLoc,
if (!Res.isUsable())
return ExprError();
Index = Value.getExtValue();
+ IndexExpr = Res.get();
}
if (Index && (!ExpandedExprs.empty() || EmptyPack)) {
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index aa948a2d526f6ce..6d783ad2755efc6 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9831,11 +9831,11 @@ QualType Sema::ActOnPackIndexingType(QualType Pattern, Expr *IndexExpr,
QualType Sema::BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
SourceLocation Loc,
SourceLocation EllipsisLoc,
- bool FullyExpanded,
+ bool FullySubstituted,
ArrayRef<QualType> Expansions) {
std::optional<int64_t> Index;
- if (FullyExpanded && !IndexExpr->isValueDependent() &&
+ if (FullySubstituted && !IndexExpr->isValueDependent() &&
!IndexExpr->isTypeDependent()) {
llvm::APSInt Value(Context.getIntWidth(Context.getSizeType()));
// TODO: do we need a new enumerator instead of CCEK_ArrayBound?
@@ -9844,9 +9844,10 @@ QualType Sema::BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
if (!Res.isUsable())
return QualType();
Index = Value.getExtValue();
+ IndexExpr = Res.get();
}
- if (FullyExpanded && Index) {
+ if (FullySubstituted && Index) {
if (*Index < 0 || *Index >= int64_t(Expansions.size())) {
Diag(IndexExpr->getBeginLoc(), diag::err_pack_index_out_of_bound)
<< *Index << Pattern << Expansions.size();
@@ -9854,7 +9855,7 @@ QualType Sema::BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
}
}
- return Context.getPackIndexingType(Pattern, IndexExpr, FullyExpanded,
+ return Context.getPackIndexingType(Pattern, IndexExpr, FullySubstituted,
Expansions, Index.value_or(-1));
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 22d7a0f51d5b104..509382e5280a843 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1050,7 +1050,7 @@ class TreeTransform {
QualType RebuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
SourceLocation Loc,
SourceLocation EllipsisLoc,
- bool FullyExpanded,
+ bool FullySubstituted,
ArrayRef<QualType> Expansions = {});
/// Build a new C++11 auto type.
@@ -6509,11 +6509,11 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
QualType Pattern = TL.getPattern();
const PackIndexingType *PIT = TL.getTypePtr();
- SmallVector<QualType, 5> ExpandedTypes;
+ SmallVector<QualType, 5> SubtitutedTypes;
llvm::ArrayRef<QualType> Types = PIT->getExpansions();
bool NotYetExpanded = Types.empty();
- bool FullyExpanded = true;
+ bool FullySubstituted = true;
if (Types.empty())
Types = llvm::ArrayRef<QualType>(&Pattern, 1);
@@ -6523,7 +6523,7 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
QualType Transformed = getDerived().TransformType(T);
if (Transformed.isNull())
return QualType();
- ExpandedTypes.push_back(Transformed);
+ SubtitutedTypes.push_back(Transformed);
continue;
}
@@ -6546,10 +6546,10 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
if (Pack.isNull())
return QualType();
if (NotYetExpanded) {
- FullyExpanded = false;
+ FullySubstituted = false;
QualType Out = getDerived().RebuildPackIndexingType(
Pack, IndexExpr.get(), SourceLocation(), TL.getEllipsisLoc(),
- FullyExpanded);
+ FullySubstituted);
if (Out.isNull())
return QualType();
@@ -6557,7 +6557,7 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
Loc.setEllipsisLoc(TL.getEllipsisLoc());
return Out;
}
- ExpandedTypes.push_back(Pack);
+ SubtitutedTypes.push_back(Pack);
continue;
}
for (unsigned I = 0; I != *NumExpansions; ++I) {
@@ -6565,17 +6565,17 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
QualType Out = getDerived().TransformType(T);
if (Out.isNull())
return QualType();
- ExpandedTypes.push_back(Out);
+ SubtitutedTypes.push_back(Out);
}
// If we're supposed to retain a pack expansion, do so by temporarily
// forgetting the partially-substituted parameter pack.
if (RetainExpansion) {
- FullyExpanded = false;
+ FullySubstituted = false;
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
QualType Out = getDerived().TransformType(T);
if (Out.isNull())
return QualType();
- ExpandedTypes.push_back(Out);
+ SubtitutedTypes.push_back(Out);
}
}
@@ -6583,7 +6583,7 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
QualType Out = getDerived().RebuildPackIndexingType(
Result, IndexExpr.get(), SourceLocation(), TL.getEllipsisLoc(),
- FullyExpanded, ExpandedTypes);
+ FullySubstituted, SubtitutedTypes);
if (Out.isNull())
return Out;
@@ -15391,12 +15391,11 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, SourceLocation) {
}
template <typename Derived>
-QualType TreeTransform<Derived>::RebuildPackIndexingType(
- QualType Pattern, Expr *IndexExpr, SourceLocation Loc,
- SourceLocation EllipsisLoc, bool FullyExpanded,
+QualType TreeTransform<Derived>::RebuildPackIndexingType(QualType Pattern, Expr *IndexExpr, SourceLocation Loc,
+ SourceLocation EllipsisLoc, bool FullySubstituted,
ArrayRef<QualType> Expansions) {
return SemaRef.BuildPackIndexingType(Pattern, IndexExpr, Loc, EllipsisLoc,
- FullyExpanded, Expansions);
+ FullySubstituted, Expansions);
}
template<typename Derived>
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 0f3206b0909e2e1..d79f194fd16c60c 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2181,9 +2181,6 @@ void ASTStmtReader::VisitPackIndexingExpr(PackIndexingExpr *E) {
E->RSquareLoc = readSourceLocation();
E->SubExprs[0] = Record.readStmt();
E->SubExprs[1] = Record.readStmt();
- bool HasIndexValue = Record.readBool();
- if (HasIndexValue)
- E->Index = Record.readInt();
auto **Exprs = E->getTrailingObjects<Expr *>();
for (unsigned I = 0; I < E->TransformedExpressions; ++I)
Exprs[I] = Record.readExpr();
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index e71dba536b6eda7..5b0b90234c410b5 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2160,9 +2160,6 @@ void ASTStmtWriter::VisitPackIndexingExpr(PackIndexingExpr *E) {
Record.AddSourceLocation(E->getRSquareLoc());
Record.AddStmt(E->getPackIdExpression());
Record.AddStmt(E->getIndexExpr());
- Record.push_back(E->Index.has_value());
- if (E->Index.has_value())
- Record.push_back(*E->Index);
Record.push_back(E->TransformedExpressions);
for (Expr *Sub : E->getExpressions())
Record.AddStmt(Sub);
diff --git a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp b/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
index 352a735c4f3215b..fbbb50f7f665c82 100644
--- a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
+++ b/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
@@ -17,23 +17,30 @@ int non_constant_index(); // expected-note 2{{declared here}}
template <int idx>
int params(auto... p) {
- return p...[idx]; //expected-error 3{{invalid index 0 for pack p of size 0}}
+ return p...[idx]; // #error-param-size
}
template <auto N, typename...T>
int test_types() {
- T...[N] a; // expected-error 4{{invalid index -1 for pack 'T' of size 0}}
+ T...[N] a; // #error-type-size
}
void test() {
- params<0>(); // expected-note{{here}}
- params<1>(0); // expected-note{{here}}
- params<-1>(0); // expected-note{{here}}
-
- test_types<-1>(); //expected-note {{in instantiation}}
- test_types<-1, int>(); //expected-note {{in instantiation}}
- test_types<0>(); //expected-note {{in instantiation}}
- test_types<1, int>(); //expected-note {{in instantiation}}
+ params<0>(); // expected-note{{here}} \
+ // expected-error@#error-param-size {{invalid index 0 for pack p of size 0}}
+ params<1>(0); // expected-note{{here}} \
+ // expected-error@#error-param-size {{invalid index 1 for pack p of size 1}}
+ params<-1>(0); // expected-note{{here}} \
+ // expected-error@#error-param-size {{invalid index -1 for pack p of size 1}}
+
+ test_types<-1>(); //expected-note {{in instantiation}} \
+ // expected-error@#error-type-size {{invalid index -1 for pack 'T' of size 0}}
+ test_types<-1, int>(); //expected-note {{in instantiation}} \
+ // expected-error@#error-type-size {{invalid index -1 for pack 'T' of size 1}}
+ test_types<0>(); //expected-note {{in instantiation}} \
+ // expected-error@#error-type-size {{invalid index 0 for pack 'T' of size 0}}
+ test_types<1, int>(); //expected-note {{in instantiation}} \
+ // expected-error@#error-type-size {{invalid index 1 for pack 'T' of size 1}}
}
void invalid_indexes(auto... p) {
>From eceb938439f83c537480a84def217a7c66bd9201 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 11 Jan 2024 18:25:11 +0100
Subject: [PATCH 04/12] Allow pack indexing as an extension (wip)
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 ++++++
clang/lib/Parse/ParseDeclCXX.cpp | 7 +++++--
clang/lib/Parse/ParseExprCXX.cpp | 10 +++++-----
clang/lib/Sema/SemaTemplateVariadic.cpp | 6 +++++-
clang/lib/Sema/SemaType.cpp | 5 ++++-
5 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 235e09262ec8977..fc0addafb498d2d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5727,6 +5727,12 @@ def err_expected_name_of_pack : Error<
def err_pack_index_out_of_bound : Error<
"invalid index %0 for pack %1 of size %2">;
+def ext_pack_indexing : ExtWarn<
+ "pack indexing is a C++2c extension">, InGroup<CXX26>;
+def warn_cxx23_pack_indexing : Warning<
+ "pack indexing is incompatible with C++ standards before C++2c">,
+ DefaultIgnore, InGroup<CXXPre26Compat>;
+
def err_fold_expression_packs_both_sides : Error<
"binary fold expression has unexpanded parameter packs in both operands">;
def err_fold_expression_empty : Error<
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index f223709a23542d1..21a9965b23f2daf 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1247,12 +1247,15 @@ SourceLocation Parser::ParseIndexedTypeNamePack(DeclSpec &DS) {
DS.SetTypeSpecError();
return IndexExpr.isInvalid() ? StartLoc : IndexExpr.get()->getEndLoc();
}
+
+ DS.SetRangeStart(StartLoc);
+ DS.SetRangeEnd(T.getCloseLocation());
+
if (IndexExpr.isInvalid()) {
DS.SetTypeSpecError();
return T.getCloseLocation();
}
- DS.SetRangeStart(StartLoc);
- DS.SetRangeEnd(T.getCloseLocation());
+
DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec, DiagID, Type,
Policy);
DS.SetPackIndexingExpr(EllipsisLoc, IndexExpr.get());
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 218b8542756e59c..f3b64e16115daea 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -233,7 +233,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
HasScopeSpecifier = true;
}
- else if (getLangOpts().CPlusPlus26 && !HasScopeSpecifier &&
+ else if (!HasScopeSpecifier &&
Tok.is(tok::identifier) && GetLookAheadToken(1).is(tok::ellipsis) &&
GetLookAheadToken(2).is(tok::l_square)) {
SourceLocation Start = Tok.getLocation();
@@ -241,7 +241,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
SourceLocation CCLoc;
SourceLocation EndLoc = ParseIndexedTypeNamePack(DS);
if (DS.getTypeSpecType() == DeclSpec::TST_error)
- return false;
+ return true;
+
QualType Type = Actions.ActOnPackIndexingType(
DS.getRepAsType().get(), DS.getPackIndexingExpr(), DS.getBeginLoc(),
DS.getEllipsisLoc());
@@ -644,8 +645,7 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS,
}
// Might be a pack index expression!
- if (getLangOpts().CPlusPlus26)
- E = tryParseCXXPackIndexingExpression(E);
+ E = tryParseCXXPackIndexingExpression(E);
if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less))
checkPotentialAngleBracket(E);
@@ -1865,7 +1865,7 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
}
// pack-index-specifier
- if (getLangOpts().CPlusPlus26 && GetLookAheadToken(1).is(tok::ellipsis) &&
+ if (GetLookAheadToken(1).is(tok::ellipsis) &&
GetLookAheadToken(2).is(tok::l_square)) {
DeclSpec DS(AttrFactory);
ParseIndexedTypeNamePack(DS);
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index b8e069bb96c7359..87cd6b909387c3a 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1090,8 +1090,12 @@ ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
<< PackExpression;
return ExprError();
}
- return BuildPackIndexingExpr(PackExpression, EllipsisLoc, IndexExpr,
+ ExprResult Res = BuildPackIndexingExpr(PackExpression, EllipsisLoc, IndexExpr,
RSquareLoc);
+ if(!Res.isInvalid())
+ Diag(Res.get()->getBeginLoc(), getLangOpts().CPlusPlus26?
+ diag::ext_pack_indexing : diag::warn_cxx23_pack_indexing);
+ return Res;
}
ExprResult
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 6d783ad2755efc6..a56ee4e009ccfbe 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9825,7 +9825,10 @@ QualType Sema::ActOnPackIndexingType(QualType Pattern, Expr *IndexExpr,
Diag(EllipsisLoc, diag::err_expected_name_of_pack) << Pattern;
return QualType();
}
- return BuildPackIndexingType(Pattern, IndexExpr, Loc, EllipsisLoc);
+ QualType Type = BuildPackIndexingType(Pattern, IndexExpr, Loc, EllipsisLoc);
+ if(!Type.isNull())
+ Diag(Loc, getLangOpts().CPlusPlus26? diag::ext_pack_indexing : diag::warn_cxx23_pack_indexing);
+ return Type;
}
QualType Sema::BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
>From 5da783b6fe75b07fe0a553d2ace6f54bb3c17ce9 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 12 Jan 2024 19:04:25 +0100
Subject: [PATCH 05/12] * Support pack indexing in older language modes *
improve error recovery for ill-formed pack indexing specifiers
This is important because we need to form a correct type for
an invalid pack indexing that we know is a type pack indexing so
that it is recognized as being part of a declaration.
---
clang/lib/AST/Type.cpp | 7 +-
clang/lib/Parse/ParseDeclCXX.cpp | 65 +++++++++----------
clang/lib/Parse/ParseExprCXX.cpp | 9 +--
clang/lib/Parse/ParseTentative.cpp | 1 +
clang/lib/Sema/SemaDeclCXX.cpp | 2 +-
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
clang/lib/Sema/SemaTemplateVariadic.cpp | 11 ++--
clang/lib/Sema/SemaType.cpp | 16 +++--
clang/test/AST/ast-dump-templates.cpp | 4 +-
.../CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp | 3 +-
clang/test/Parser/cxx0x-ambig.cpp | 3 +-
clang/test/Parser/cxx0x-decl.cpp | 8 ++-
clang/test/Parser/cxx2b-pack-indexing.cpp | 10 +--
clang/test/SemaCXX/cxx2b-pack-indexing.cpp | 8 +--
14 files changed, 79 insertions(+), 70 deletions(-)
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 92c4d06facc4022..11ca02be13ab4b2 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3827,9 +3827,12 @@ PackIndexingType::PackIndexingType(const ASTContext &Context,
}
std::optional<unsigned> PackIndexingType::getSelectedIndex() const {
- if(isDependentType())
+ if (isInstantiationDependentType())
+ return std::nullopt;
+ // Should only be not a constant for error recovery.
+ ConstantExpr *CE = dyn_cast<ConstantExpr>(getIndexExpr());
+ if (!CE)
return std::nullopt;
- ConstantExpr* CE = cast<ConstantExpr>(getIndexExpr());
auto Index = CE->getResultAsAPSInt();
assert(Index.isNonNegative() && "Invalid index");
return static_cast<unsigned>(Index.getExtValue());
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 21a9965b23f2daf..e956928f8a4522f 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1223,46 +1223,41 @@ SourceLocation Parser::ParseIndexedTypeNamePack(DeclSpec &DS) {
DS.SetTypeSpecType(DeclSpec::TST_typename_pack_indexing, StartLoc, PrevSpec,
DiagID, Type, Policy);
return EndLoc;
- } else {
- if (!NextToken().is(tok::ellipsis) ||
- !GetLookAheadToken(2).is(tok::l_square)) {
- DS.SetTypeSpecError();
- return Tok.getEndLoc();
- }
-
- ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), getCurScope());
- if (!Ty) {
- DS.SetTypeSpecError();
- return Tok.getEndLoc();
- }
- Type = Ty;
+ }
+ if (!NextToken().is(tok::ellipsis) ||
+ !GetLookAheadToken(2).is(tok::l_square)) {
+ DS.SetTypeSpecError();
+ return Tok.getEndLoc();
+ }
- StartLoc = ConsumeToken();
- EllipsisLoc = ConsumeToken();
- BalancedDelimiterTracker T(*this, tok::l_square);
- T.consumeOpen();
- ExprResult IndexExpr = ParseConstantExpression();
- if (T.consumeClose()) {
- DS.SetTypeSpecError();
- return IndexExpr.isInvalid() ? StartLoc : IndexExpr.get()->getEndLoc();
- }
+ ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), getCurScope());
+ if (!Ty) {
+ DS.SetTypeSpecError();
+ return Tok.getEndLoc();
+ }
+ Type = Ty;
- DS.SetRangeStart(StartLoc);
- DS.SetRangeEnd(T.getCloseLocation());
+ StartLoc = ConsumeToken();
+ EllipsisLoc = ConsumeToken();
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+ ExprResult IndexExpr = ParseConstantExpression();
+ T.consumeClose();
- if (IndexExpr.isInvalid()) {
- DS.SetTypeSpecError();
- return T.getCloseLocation();
- }
+ DS.SetRangeStart(StartLoc);
+ DS.SetRangeEnd(T.getCloseLocation());
- DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec, DiagID, Type,
- Policy);
- DS.SetPackIndexingExpr(EllipsisLoc, IndexExpr.get());
- return T.getCloseLocation();
- ;
+ if (!IndexExpr.isUsable()) {
+ ASTContext &C = Actions.getASTContext();
+ IndexExpr = IntegerLiteral::Create(C, C.MakeIntValue(0, C.getSizeType()),
+ C.getSizeType(), SourceLocation());
}
- return SourceLocation();
+
+ DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec, DiagID, Type,
+ Policy);
+ DS.SetPackIndexingExpr(EllipsisLoc, IndexExpr.get());
+ return T.getCloseLocation();
}
void Parser::AnnotateExistingIndexedTypeNamePack(ParsedType T,
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index f3b64e16115daea..b1fd24b0dab47c0 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -233,21 +233,22 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
HasScopeSpecifier = true;
}
- else if (!HasScopeSpecifier &&
- Tok.is(tok::identifier) && GetLookAheadToken(1).is(tok::ellipsis) &&
+ else if (!HasScopeSpecifier && Tok.is(tok::identifier) &&
+ GetLookAheadToken(1).is(tok::ellipsis) &&
GetLookAheadToken(2).is(tok::l_square)) {
SourceLocation Start = Tok.getLocation();
DeclSpec DS(AttrFactory);
SourceLocation CCLoc;
SourceLocation EndLoc = ParseIndexedTypeNamePack(DS);
if (DS.getTypeSpecType() == DeclSpec::TST_error)
- return true;
+ return false;
QualType Type = Actions.ActOnPackIndexingType(
DS.getRepAsType().get(), DS.getPackIndexingExpr(), DS.getBeginLoc(),
DS.getEllipsisLoc());
+
if (Type.isNull())
- return true;
+ return false;
if (!TryConsumeToken(tok::coloncolon, CCLoc)) {
AnnotateExistingIndexedTypeNamePack(ParsedType::make(Type), Start,
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 8bfcd39ca32161a..f1737cb8447677d 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1365,6 +1365,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
case tok::identifier: {
if (GetLookAheadToken(1).is(tok::ellipsis) &&
GetLookAheadToken(2).is(tok::l_square)) {
+
if (TryAnnotateTypeOrScopeToken())
return TPResult::Error;
if (Tok.is(tok::identifier))
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 027f1ea3d3d9e6f..5adc262cd6bc97e 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4496,7 +4496,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
return true;
} else if (DS.getTypeSpecType() == TST_typename_pack_indexing) {
BaseType =
- ActOnPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
+ BuildPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
DS.getBeginLoc(), DS.getEllipsisLoc());
} else {
LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 51c61886739bb91..231eec2f1aaefce 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8117,7 +8117,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
break;
}
case DeclSpec::TST_typename_pack_indexing: {
- T = ActOnPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
+ T = BuildPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
DS.getBeginLoc(), DS.getEllipsisLoc());
TLB.pushTrivial(getASTContext(),
cast<PackIndexingType>(T.getTypePtr())->getPattern(),
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 87cd6b909387c3a..889535ed01f9d4a 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1090,11 +1090,12 @@ ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
<< PackExpression;
return ExprError();
}
- ExprResult Res = BuildPackIndexingExpr(PackExpression, EllipsisLoc, IndexExpr,
- RSquareLoc);
- if(!Res.isInvalid())
- Diag(Res.get()->getBeginLoc(), getLangOpts().CPlusPlus26?
- diag::ext_pack_indexing : diag::warn_cxx23_pack_indexing);
+ ExprResult Res =
+ BuildPackIndexingExpr(PackExpression, EllipsisLoc, IndexExpr, RSquareLoc);
+ if (!Res.isInvalid())
+ Diag(Res.get()->getBeginLoc(), getLangOpts().CPlusPlus26
+ ? diag::ext_pack_indexing
+ : diag::warn_cxx23_pack_indexing);
return Res;
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index a56ee4e009ccfbe..2c5d1932f653725 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1671,7 +1671,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Expr *E = DS.getPackIndexingExpr();
assert(E && "Didn't get an expression for pack indexing");
QualType Pattern = S.GetTypeFromParser(DS.getRepAsType());
- Result = S.ActOnPackIndexingType(Pattern, E, DS.getBeginLoc(),
+ Result = S.BuildPackIndexingType(Pattern, E, DS.getBeginLoc(),
DS.getEllipsisLoc());
if (Result.isNull()) {
declarator.setInvalidType(true);
@@ -9821,13 +9821,17 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
QualType Sema::ActOnPackIndexingType(QualType Pattern, Expr *IndexExpr,
SourceLocation Loc,
SourceLocation EllipsisLoc) {
- if (!Pattern->containsUnexpandedParameterPack()) {
- Diag(EllipsisLoc, diag::err_expected_name_of_pack) << Pattern;
+ if (!IndexExpr)
return QualType();
- }
+
+ // Diagnose unexpanded packs but continue to improve recovery.
+ if (!Pattern->containsUnexpandedParameterPack())
+ Diag(Loc, diag::err_expected_name_of_pack) << Pattern;
+
QualType Type = BuildPackIndexingType(Pattern, IndexExpr, Loc, EllipsisLoc);
- if(!Type.isNull())
- Diag(Loc, getLangOpts().CPlusPlus26? diag::ext_pack_indexing : diag::warn_cxx23_pack_indexing);
+ if (!Type.isNull())
+ Diag(Loc, getLangOpts().CPlusPlus26 ? diag::ext_pack_indexing
+ : diag::warn_cxx23_pack_indexing);
return Type;
}
diff --git a/clang/test/AST/ast-dump-templates.cpp b/clang/test/AST/ast-dump-templates.cpp
index 3d26eb917c12022..d25ef36dd4d32c0 100644
--- a/clang/test/AST/ast-dump-templates.cpp
+++ b/clang/test/AST/ast-dump-templates.cpp
@@ -45,9 +45,9 @@ template <typename ...T> struct A {
template <T ...x[3]> struct B {};
};
-// CHECK1-LABEL: template <typename ...T> void f(T ...[3]) {
+// CHECK1-LABEL: template <typename ...T> void f() {
// CHECK1-NEXT: A<T[3]...> a;
-template <typename ...T> void f(T ...[3]) {
+template <typename ...T> void f() {
A<T[3]...> a;
}
diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
index 9cc13b4efb80f10..a0d5e719731908d 100644
--- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
@@ -57,7 +57,8 @@ template<typename T>
void b(T[] ...);
template<typename T>
-void c(T ... []); // expected-error{{type 'T[]' of function parameter pack does not contain any unexpanded parameter packs}}
+void c(T ... []); // expected-error {{expected expression}} \
+ // expected-error {{'T' does not refer to the name of a parameter pack}}
template<typename T>
void d(T ... x[]); // expected-error{{type 'T[]' of function parameter pack does not contain any unexpanded parameter packs}}
diff --git a/clang/test/Parser/cxx0x-ambig.cpp b/clang/test/Parser/cxx0x-ambig.cpp
index 7f3398ad1386c29..9a266aac88512f6 100644
--- a/clang/test/Parser/cxx0x-ambig.cpp
+++ b/clang/test/Parser/cxx0x-ambig.cpp
@@ -122,9 +122,8 @@ namespace ellipsis {
void f(S(...args[sizeof(T)])); // expected-note {{here}} expected-note {{here}}
void f(S(...args)[sizeof(T)]); // expected-error {{redeclared}}
void f(S ...args[sizeof(T)]); // expected-error {{redeclared}}
- void g(S(...[sizeof(T)])); // expected-note {{here}} expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
+ void g(S(...[sizeof(T)])); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
void g(S(...)[sizeof(T)]); // expected-error {{function cannot return array type}}
- void g(S ...[sizeof(T)]); // expected-error {{redeclared}}
void h(T(...)); // function type, expected-error {{unexpanded parameter pack}}
void h(T...); // pack expansion, ok
void i(int(T...)); // expected-note {{here}}
diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp
index 8be98d6ef299892..499d1b6c0c5361e 100644
--- a/clang/test/Parser/cxx0x-decl.cpp
+++ b/clang/test/Parser/cxx0x-decl.cpp
@@ -213,8 +213,12 @@ struct MemberComponentOrder : Base {
void NoMissingSemicolonHere(struct S
[3]);
-template<int ...N> void NoMissingSemicolonHereEither(struct S
- ... [N]);
+template<int ...N> void NoMissingSemicolonHereEither(struct S... [N]);
+// expected-error at -1 {{'S' does not refer to the name of a parameter pack}} \
+// expected-error at -1 {{declaration of anonymous struct must be a definition}} \
+// expected-error at -1 {{expected parameter declarator}}
+
+
// This must be at the end of the file; we used to look ahead past the EOF token here.
// expected-error at +1 {{expected unqualified-id}} expected-error at +1{{expected ';'}}
diff --git a/clang/test/Parser/cxx2b-pack-indexing.cpp b/clang/test/Parser/cxx2b-pack-indexing.cpp
index 1e92705dd66c829..40cde13dccceb2c 100644
--- a/clang/test/Parser/cxx2b-pack-indexing.cpp
+++ b/clang/test/Parser/cxx2b-pack-indexing.cpp
@@ -1,19 +1,19 @@
-// RUN: %clang_cc1 -std=c++2c -verify -fsyntax-only %s
+// RUN: %clang_cc1 -std=c++2c -verify -fsyntax-only -Wno-c++26-extensions %s
template<typename... T>
struct S {
T...1; // expected-error{{expected member name or ';' after declaration specifiers}}
T...[; // expected-error{{expected expression}} \
// expected-error{{expected ']'}} \
- // expected-note {{to match this '['}}\
+ // expected-note {{to match this '['}} \
// expected-warning{{declaration does not declare anything}}
T...[1; // expected-error{{expected ']'}} \
- // expected-note {{to match this '['}}\
- // expected-warning{{declaration does not declare anything}}
+ // expected-note {{to match this '['}} \
+ // expected-warning{{declaration does not declare anything}}
T...[]; // expected-error{{expected expression}} \
- // expected-warning{{declaration does not declare anything}}
+ // expected-warning{{declaration does not declare anything}}
void f(auto... v) {
decltype(v...[1]) a = v...[1];
diff --git a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp b/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
index fbbb50f7f665c82..0d81f2798920f0c 100644
--- a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
+++ b/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2c -verify %s
+// RUN: %clang_cc1 -std=c++2c -verify -Wno-c++26-extensions %s
struct NotAPack;
template <typename T, auto V, template<typename> typename Tp>
@@ -6,9 +6,9 @@ void not_pack() {
int i = 0;
i...[0]; // expected-error {{i does not refer to the name of a parameter pack}}
V...[0]; // expected-error {{V does not refer to the name of a parameter pack}}
- NotAPack...[0]; // expected-error{{'NotAPack' does not refer to the name of a parameter pack}}
- T...[0]; // expected-error{{'T' does not refer to the name of a parameter pack}}
- Tp...[0]; // expected-error{{'Tp' does not refer to the name of a parameter pack}}
+ NotAPack...[0] a; // expected-error{{'NotAPack' does not refer to the name of a parameter pack}}
+ T...[0] b; // expected-error{{'T' does not refer to the name of a parameter pack}}
+ Tp...[0] c; // expected-error{{'Tp' does not refer to the name of a parameter pack}}
}
namespace invalid_indexes {
>From 5d127b857b001487030902f5c41fd169c8e317df Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Sat, 13 Jan 2024 09:25:41 +0100
Subject: [PATCH 06/12] ParseIndexedTypeNamePack -> ParsePackIndexingType
---
clang/include/clang/Parse/Parser.h | 2 +-
clang/lib/Parse/ParseDecl.cpp | 2 +-
clang/lib/Parse/ParseDeclCXX.cpp | 6 +++---
clang/lib/Parse/ParseExprCXX.cpp | 6 +++---
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index b28f8a15932d86c..baad6155b7c6392 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2461,7 +2461,7 @@ class Parser : public CodeCompletionHandler {
DeclSpecContext DSC, LateParsedAttrList *LateAttrs,
ImplicitTypenameContext AllowImplicitTypename);
- SourceLocation ParseIndexedTypeNamePack(DeclSpec &DS);
+ SourceLocation ParsePackIndexingType(DeclSpec &DS);
void AnnotateExistingIndexedTypeNamePack(ParsedType T,
SourceLocation StartLoc,
SourceLocation EndLoc);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 199bde59481eeff..7ea0dccd1c724b5 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4448,7 +4448,7 @@ void Parser::ParseDeclarationSpecifiers(
continue;
case tok::annot_pack_indexing_type:
- ParseIndexedTypeNamePack(DS);
+ ParsePackIndexingType(DS);
continue;
case tok::annot_pragma_pack:
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index e956928f8a4522f..7230bec68393808 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1196,7 +1196,7 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
PP.AnnotateCachedTokens(Tok);
}
-SourceLocation Parser::ParseIndexedTypeNamePack(DeclSpec &DS) {
+SourceLocation Parser::ParsePackIndexingType(DeclSpec &DS) {
assert(Tok.isOneOf(tok::annot_pack_indexing_type, tok::identifier) &&
"Expected an identifier");
@@ -1382,7 +1382,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
if (Tok.is(tok::annot_pack_indexing_type)) {
DeclSpec DS(AttrFactory);
- ParseIndexedTypeNamePack(DS);
+ ParsePackIndexingType(DS);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::TypeName);
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
@@ -3934,7 +3934,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
} else if (Tok.is(tok::annot_pack_indexing_type)) {
// Uses of T...[N] will already have been converted to
// annot_pack_indexing_type by ParseOptionalCXXScopeSpecifier at this point.
- ParseIndexedTypeNamePack(DS);
+ ParsePackIndexingType(DS);
} else {
TemplateIdAnnotation *TemplateId = Tok.is(tok::annot_template_id)
? takeTemplateIdAnnotation(Tok)
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index b1fd24b0dab47c0..fd262ff31e661a7 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -239,7 +239,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
SourceLocation Start = Tok.getLocation();
DeclSpec DS(AttrFactory);
SourceLocation CCLoc;
- SourceLocation EndLoc = ParseIndexedTypeNamePack(DS);
+ SourceLocation EndLoc = ParsePackIndexingType(DS);
if (DS.getTypeSpecType() == DeclSpec::TST_error)
return false;
@@ -1869,7 +1869,7 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
if (GetLookAheadToken(1).is(tok::ellipsis) &&
GetLookAheadToken(2).is(tok::l_square)) {
DeclSpec DS(AttrFactory);
- ParseIndexedTypeNamePack(DS);
+ ParsePackIndexingType(DS);
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
TildeLoc, DS);
}
@@ -2428,7 +2428,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
return DS.Finish(Actions, Policy);
case tok::annot_pack_indexing_type:
- DS.SetRangeEnd(ParseIndexedTypeNamePack(DS));
+ DS.SetRangeEnd(ParsePackIndexingType(DS));
return DS.Finish(Actions, Policy);
// GNU typeof support.
>From 23eff9ab5774e870aa8f680e6870f6bd38d29e5d Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 15 Jan 2024 15:13:07 +0100
Subject: [PATCH 07/12] More cleanups
---
clang/include/clang/AST/ExprCXX.h | 2 --
clang/lib/Parse/ParseExpr.cpp | 2 +-
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 18ec26682e4180e..09fdda84760b548 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4416,8 +4416,6 @@ class PackIndexingExpr final
}
ArrayRef<Expr *> getExpressions() const {
- if (TransformedExpressions == 0)
- return {};
return {getTrailingObjects<Expr *>(), TransformedExpressions};
}
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index dd77e9b8bd9d4b2..34415c51194f62a 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1067,7 +1067,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// where the syntax forbids a type.
const Token &Next = NextToken();
- if (getLangOpts().CPlusPlus26 && Next.is(tok::ellipsis) &&
+ if (Next.is(tok::ellipsis) &&
Tok.is(tok::identifier) && GetLookAheadToken(2).is(tok::l_square)) {
// Annotate the token and tail recurse.
// If the token is not annotated, then it might be an expression pack
>From 992e342c973c92c6e392186a76d03635db8d470d Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 18 Jan 2024 15:29:44 +0100
Subject: [PATCH 08/12] Add extension warnings tests
---
clang/lib/Parse/ParseExpr.cpp | 4 ++--
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
clang/lib/Sema/SemaTemplateVariadic.cpp | 6 +++---
clang/lib/Sema/SemaType.cpp | 6 +++---
.../CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp | 3 ++-
clang/test/Parser/cxx0x-decl.cpp | 3 ++-
...k-indexing.cpp => cxx2c-pack-indexing.cpp} | 2 +-
.../SemaCXX/cxx2c-pack-indexing-ext-diags.cpp | 21 +++++++++++++++++++
...k-indexing.cpp => cxx2c-pack-indexing.cpp} | 2 +-
9 files changed, 36 insertions(+), 13 deletions(-)
rename clang/test/Parser/{cxx2b-pack-indexing.cpp => cxx2c-pack-indexing.cpp} (96%)
create mode 100644 clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
rename clang/test/SemaCXX/{cxx2b-pack-indexing.cpp => cxx2c-pack-indexing.cpp} (98%)
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 34415c51194f62a..6e83b7aa3441b5c 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1067,8 +1067,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// where the syntax forbids a type.
const Token &Next = NextToken();
- if (Next.is(tok::ellipsis) &&
- Tok.is(tok::identifier) && GetLookAheadToken(2).is(tok::l_square)) {
+ if (Next.is(tok::ellipsis) && Tok.is(tok::identifier) &&
+ GetLookAheadToken(2).is(tok::l_square)) {
// Annotate the token and tail recurse.
// If the token is not annotated, then it might be an expression pack
// indexing
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 231eec2f1aaefce..51c61886739bb91 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8117,7 +8117,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
break;
}
case DeclSpec::TST_typename_pack_indexing: {
- T = BuildPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
+ T = ActOnPackIndexingType(DS.getRepAsType().get(), DS.getPackIndexingExpr(),
DS.getBeginLoc(), DS.getEllipsisLoc());
TLB.pushTrivial(getASTContext(),
cast<PackIndexingType>(T.getTypePtr())->getPattern(),
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 889535ed01f9d4a..903fbfd18e779cd 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1094,8 +1094,8 @@ ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
BuildPackIndexingExpr(PackExpression, EllipsisLoc, IndexExpr, RSquareLoc);
if (!Res.isInvalid())
Diag(Res.get()->getBeginLoc(), getLangOpts().CPlusPlus26
- ? diag::ext_pack_indexing
- : diag::warn_cxx23_pack_indexing);
+ ? diag::warn_cxx23_pack_indexing
+ : diag::ext_pack_indexing);
return Res;
}
@@ -1107,7 +1107,7 @@ Sema::BuildPackIndexingExpr(Expr *PackExpression, SourceLocation EllipsisLoc,
std::optional<int64_t> Index;
if (!IndexExpr->isInstantiationDependent()) {
llvm::APSInt Value(Context.getIntWidth(Context.getSizeType()));
- // TODO: do we need a new enumerator instead of CCEK_ArrayBound?
+
ExprResult Res = CheckConvertedConstantExpression(
IndexExpr, Context.getSizeType(), Value, CCEK_ArrayBound);
if (!Res.isUsable())
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 2c5d1932f653725..7cee73d5d6baeb9 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9829,9 +9829,10 @@ QualType Sema::ActOnPackIndexingType(QualType Pattern, Expr *IndexExpr,
Diag(Loc, diag::err_expected_name_of_pack) << Pattern;
QualType Type = BuildPackIndexingType(Pattern, IndexExpr, Loc, EllipsisLoc);
+
if (!Type.isNull())
- Diag(Loc, getLangOpts().CPlusPlus26 ? diag::ext_pack_indexing
- : diag::warn_cxx23_pack_indexing);
+ Diag(Loc, getLangOpts().CPlusPlus26 ? diag::warn_cxx23_pack_indexing
+ : diag::ext_pack_indexing);
return Type;
}
@@ -9845,7 +9846,6 @@ QualType Sema::BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
if (FullySubstituted && !IndexExpr->isValueDependent() &&
!IndexExpr->isTypeDependent()) {
llvm::APSInt Value(Context.getIntWidth(Context.getSizeType()));
- // TODO: do we need a new enumerator instead of CCEK_ArrayBound?
ExprResult Res = CheckConvertedConstantExpression(
IndexExpr, Context.getSizeType(), Value, CCEK_ArrayBound);
if (!Res.isUsable())
diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
index a0d5e719731908d..dbb6e60d9b93d7c 100644
--- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
@@ -58,7 +58,8 @@ void b(T[] ...);
template<typename T>
void c(T ... []); // expected-error {{expected expression}} \
- // expected-error {{'T' does not refer to the name of a parameter pack}}
+ // expected-error {{'T' does not refer to the name of a parameter pack}} \
+ // expected-warning {{pack indexing is a C++2c extension}}
template<typename T>
void d(T ... x[]); // expected-error{{type 'T[]' of function parameter pack does not contain any unexpanded parameter packs}}
diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp
index 499d1b6c0c5361e..3d7c4dfb3f121fc 100644
--- a/clang/test/Parser/cxx0x-decl.cpp
+++ b/clang/test/Parser/cxx0x-decl.cpp
@@ -216,7 +216,8 @@ void NoMissingSemicolonHere(struct S
template<int ...N> void NoMissingSemicolonHereEither(struct S... [N]);
// expected-error at -1 {{'S' does not refer to the name of a parameter pack}} \
// expected-error at -1 {{declaration of anonymous struct must be a definition}} \
-// expected-error at -1 {{expected parameter declarator}}
+// expected-error at -1 {{expected parameter declarator}} \
+// expected-warning at -1 {{pack indexing is a C++2c extension}} \
diff --git a/clang/test/Parser/cxx2b-pack-indexing.cpp b/clang/test/Parser/cxx2c-pack-indexing.cpp
similarity index 96%
rename from clang/test/Parser/cxx2b-pack-indexing.cpp
rename to clang/test/Parser/cxx2c-pack-indexing.cpp
index 40cde13dccceb2c..86e7629e79b3e4c 100644
--- a/clang/test/Parser/cxx2b-pack-indexing.cpp
+++ b/clang/test/Parser/cxx2c-pack-indexing.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2c -verify -fsyntax-only -Wno-c++26-extensions %s
+// RUN: %clang_cc1 -std=c++2c -verify -fsyntax-only %s
template<typename... T>
struct S {
diff --git a/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp b/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
new file mode 100644
index 000000000000000..80dfeb9b6a8bf57
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++2c -verify=cxx26 -fsyntax-only -Wpre-c++26-compat %s
+// RUN: %clang_cc1 -std=c++11 -verify=cxx11 -fsyntax-only -Wc++26-extensions %s
+
+template <typename... T>
+void f(T... t) {
+ // cxx26-warning at +2 {{pack indexing is incompatible with C++ standards before C++2c}}
+ // cxx11-warning at +1 {{pack indexing is a C++2c extension}}
+ using a = T...[0];
+
+ // cxx26-warning at +2 {{pack indexing is incompatible with C++ standards before C++2c}}
+ // cxx11-warning at +1 {{pack indexing is a C++2c extension}}
+ using b = typename T...[0]::a;
+
+ // cxx26-warning at +2 2{{pack indexing is incompatible with C++ standards before C++2c}}
+ // cxx11-warning at +1 2{{pack indexing is a C++2c extension}}
+ t...[0].~T...[0]();
+
+ // cxx26-warning at +2 {{pack indexing is incompatible with C++ standards before C++2c}}
+ // cxx11-warning at +1 {{pack indexing is a C++2c extension}}
+ T...[0] c;
+}
diff --git a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp b/clang/test/SemaCXX/cxx2c-pack-indexing.cpp
similarity index 98%
rename from clang/test/SemaCXX/cxx2b-pack-indexing.cpp
rename to clang/test/SemaCXX/cxx2c-pack-indexing.cpp
index 0d81f2798920f0c..3a2ffcea1e5be66 100644
--- a/clang/test/SemaCXX/cxx2b-pack-indexing.cpp
+++ b/clang/test/SemaCXX/cxx2c-pack-indexing.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2c -verify -Wno-c++26-extensions %s
+// RUN: %clang_cc1 -std=c++2c -verify %s
struct NotAPack;
template <typename T, auto V, template<typename> typename Tp>
>From 523f9c11e9d2463e36e9ac5c15025bfd5f5cfa26 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 18 Jan 2024 15:38:13 +0100
Subject: [PATCH 09/12] Format
---
clang/include/clang/AST/ExprCXX.h | 5 ++---
clang/include/clang/Basic/Specifiers.h | 11 ++++++-----
clang/lib/AST/ASTContext.cpp | 4 ++--
clang/lib/AST/ComputeDependence.cpp | 4 +---
clang/lib/AST/ExprCXX.cpp | 5 ++---
clang/lib/Sema/TreeTransform.h | 3 ++-
6 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 09fdda84760b548..a0e467b35778c5c 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4361,7 +4361,7 @@ class PackIndexingExpr final
Exprs);
setDependence(computeDependence(this));
- if(!isInstantiationDependent())
+ if (!isInstantiationDependent())
setValueKind(getSelectedExpr()->getValueKind());
}
@@ -4399,11 +4399,10 @@ class PackIndexingExpr final
Expr *getIndexExpr() const { return cast<Expr>(SubExprs[1]); }
-
std::optional<unsigned> getSelectedIndex() const {
if (isInstantiationDependent())
return std::nullopt;
- ConstantExpr* CE = cast<ConstantExpr>(getIndexExpr());
+ ConstantExpr *CE = cast<ConstantExpr>(getIndexExpr());
auto Index = CE->getResultAsAPSInt();
assert(Index.isNonNegative() && "Invalid index");
return static_cast<unsigned>(Index.getExtValue());
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index c0c5e4b6806f826..cf849b9b0f00824 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -79,14 +79,14 @@ namespace clang {
TST_enum,
TST_union,
TST_struct,
- TST_class, // C++ class type
- TST_interface, // C++ (Microsoft-specific) __interface type
- TST_typename, // Typedef, C++ class-name or enum name, etc.
+ TST_class, // C++ class type
+ TST_interface, // C++ (Microsoft-specific) __interface type
+ TST_typename, // Typedef, C++ class-name or enum name, etc.
TST_typeofType, // C23 (and GNU extension) typeof(type-name)
TST_typeofExpr, // C23 (and GNU extension) typeof(expression)
TST_typeof_unqualType, // C23 typeof_unqual(type-name)
TST_typeof_unqualExpr, // C23 typeof_unqual(expression)
- TST_decltype, // C++11 decltype
+ TST_decltype, // C++11 decltype
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait,
#include "clang/Basic/TransformTypeTraits.def"
TST_auto, // C++11 auto
@@ -95,7 +95,8 @@ namespace clang {
TST_unknown_anytype, // __unknown_anytype extension
TST_atomic, // C11 _Atomic
TST_typename_pack_indexing,
-#define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types
+#define GENERIC_IMAGE_TYPE(ImgType, Id) \
+ TST_##ImgType##_t, // OpenCL image types
#include "clang/Basic/OpenCLImageTypes.def"
TST_error // erroneous type
};
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 30832e7f6e56edd..2aa6ed089a0814a 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5719,8 +5719,8 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
void *Mem = Allocate(
PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
- Canon = new (Mem) PackIndexingType(*this, QualType(), Pattern, IndexExpr,
- Expansions);
+ Canon = new (Mem)
+ PackIndexingType(*this, QualType(), Pattern, IndexExpr, Expansions);
DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
}
Canonical = QualType(Canon, 0);
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 082fa2722388ff8..9d3856b8f7e08a8 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -373,14 +373,12 @@ ExprDependence clang::computeDependence(PackIndexingExpr *E) {
~ExprDependence::UnexpandedPack;
else if (!E->getIndexExpr()->isInstantiationDependent()) {
std::optional<unsigned> Index = E->getSelectedIndex();
- assert(Index && *Index < Exprs.size() &&
- "pack index out of bound");
+ assert(Index && *Index < Exprs.size() && "pack index out of bound");
D |= Exprs[*Index]->getDependence();
}
return D;
}
-
ExprDependence clang::computeDependence(SubstNonTypeTemplateParmExpr *E) {
return E->getReplacement()->getDependence();
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index e2cfd1588cb4115..a581963188433e0 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1679,9 +1679,8 @@ 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);
}
NamedDecl *PackIndexingExpr::getPackDecl() const {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 509382e5280a843..2922924e550d0cf 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15391,7 +15391,8 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, SourceLocation) {
}
template <typename Derived>
-QualType TreeTransform<Derived>::RebuildPackIndexingType(QualType Pattern, Expr *IndexExpr, SourceLocation Loc,
+QualType TreeTransform<Derived>::RebuildPackIndexingType(
+ QualType Pattern, Expr *IndexExpr, SourceLocation Loc,
SourceLocation EllipsisLoc, bool FullySubstituted,
ArrayRef<QualType> Expansions) {
return SemaRef.BuildPackIndexingType(Pattern, IndexExpr, Loc, EllipsisLoc,
>From b8e82eb8ea3df45b608d76c109a3a85bbf61ad8b Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 26 Jan 2024 19:05:08 +0100
Subject: [PATCH 10/12] Rebase
---
clang/lib/Parse/ParseDeclCXX.cpp | 2 +-
clang/test/Parser/cxx0x-decl.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 7230bec68393808..06ccc1e3d04e942 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1385,7 +1385,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
ParsePackIndexingType(DS);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::TypeName);
- return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ return Actions.ActOnTypeName(DeclaratorInfo);
}
// Check whether we have a template-id that names a type.
diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp
index 3d7c4dfb3f121fc..18095a4d989ddab 100644
--- a/clang/test/Parser/cxx0x-decl.cpp
+++ b/clang/test/Parser/cxx0x-decl.cpp
@@ -217,7 +217,7 @@ template<int ...N> void NoMissingSemicolonHereEither(struct S... [N]);
// expected-error at -1 {{'S' does not refer to the name of a parameter pack}} \
// expected-error at -1 {{declaration of anonymous struct must be a definition}} \
// expected-error at -1 {{expected parameter declarator}} \
-// expected-warning at -1 {{pack indexing is a C++2c extension}} \
+// expected-error at -1 {{pack indexing is a C++2c extension}} \
>From d4e696cc68a887d6ff750278ac8ab0e08a8c1791 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Sat, 27 Jan 2024 07:19:50 +0100
Subject: [PATCH 11/12] Fix test portability on windows
---
clang/test/Parser/cxx2c-pack-indexing.cpp | 2 +-
clang/test/SemaCXX/cxx2c-pack-indexing.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/Parser/cxx2c-pack-indexing.cpp b/clang/test/Parser/cxx2c-pack-indexing.cpp
index 86e7629e79b3e4c..1b84ddfc6c20a56 100644
--- a/clang/test/Parser/cxx2c-pack-indexing.cpp
+++ b/clang/test/Parser/cxx2c-pack-indexing.cpp
@@ -32,7 +32,7 @@ struct typelist{};
template <typename... T>
requires requires(T...[0]) { {T...[0](0)}; }
struct SS : T...[1] {
- [[no_unique_address]] T...[1] base = {};
+ [[maybe_unused]] T...[1] base = {};
using foo = T...[1];
SS()
: T...[1]()
diff --git a/clang/test/SemaCXX/cxx2c-pack-indexing.cpp b/clang/test/SemaCXX/cxx2c-pack-indexing.cpp
index 3a2ffcea1e5be66..bd75c1180a1c19b 100644
--- a/clang/test/SemaCXX/cxx2c-pack-indexing.cpp
+++ b/clang/test/SemaCXX/cxx2c-pack-indexing.cpp
@@ -48,7 +48,7 @@ void invalid_indexes(auto... p) {
// expected-note {{cannot be used in a constant expression}}
const char* no_index = "";
- p...[no_index]; // expected-error {{value of type 'const char *' is not implicitly convertible to 'unsigned long'}}
+ p...[no_index]; // expected-error {{value of type 'const char *' is not implicitly convertible}}
}
void invalid_index_types() {
>From 28ed1fe92aefbdd354f92cedef9f8a323700d125 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Sat, 27 Jan 2024 08:08:13 +0100
Subject: [PATCH 12/12] Pack indexing targets Clang 19
---
clang/www/cxx_status.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index d9d9e9eb607902c..a3c176d02129cfe 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -156,7 +156,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
<tr>
<td>Pack Indexing</td>
<td><a href="https://wg21.link/P2662R3">P2662R3</a></td>
- <td class="unreleased" align="center">Clang 18</td>
+ <td class="unreleased" align="center">Clang 19</td>
</tr>
<tr>
<td>Remove Deprecated Arithmetic Conversion on Enumerations</td>
More information about the cfe-commits
mailing list