-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang][C++26] Implement Pack Indexing (P2662R3). #72644
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-modules Author: cor3ntin (cor3ntin) Changeshttps://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. Patch is 101.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/72644.diff 69 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ed1a978b5382d71..dab670409077678 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -182,6 +182,8 @@ C++2c Feature Support
This is applied to both C++ standard attributes, and other attributes supported by Clang.
This completes the implementation of `P2361R6 Unevaluated Strings <https://wg21.link/P2361R6>`_
+- 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 24278016431837b..efd6558326099eb 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4344,6 +4344,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 53bc15e1b19f668..1c26f0512fa1342 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1063,6 +1063,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()));
@@ -1341,6 +1346,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()));
})
@@ -2857,6 +2867,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 6c147eb8f640623..a710766d1cf92f9 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -4884,6 +4884,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 471deb14aba51fc..38e40ece425fb8f 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -2055,6 +2055,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 a9dde041bc22a6d..5f80debb9a454f6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5681,9 +5681,15 @@ 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_pack_index_todo : Error<
+ "Pack index not implemented">;
+
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 82a503d01068d53..6b5f8210fa6d0e3 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -836,6 +836,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 30e0352c868637b..c7bbc3d6384306f 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1884,6 +1884,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);
@@ -2430,6 +2434,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_ty...
[truncated]
|
@llvm/pr-subscribers-debuginfo Author: cor3ntin (cor3ntin) Changeshttps://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. Patch is 101.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/72644.diff 69 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ed1a978b5382d71..dab670409077678 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -182,6 +182,8 @@ C++2c Feature Support
This is applied to both C++ standard attributes, and other attributes supported by Clang.
This completes the implementation of `P2361R6 Unevaluated Strings <https://wg21.link/P2361R6>`_
+- 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 24278016431837b..efd6558326099eb 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4344,6 +4344,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 53bc15e1b19f668..1c26f0512fa1342 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1063,6 +1063,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()));
@@ -1341,6 +1346,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()));
})
@@ -2857,6 +2867,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 6c147eb8f640623..a710766d1cf92f9 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -4884,6 +4884,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 471deb14aba51fc..38e40ece425fb8f 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -2055,6 +2055,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 a9dde041bc22a6d..5f80debb9a454f6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5681,9 +5681,15 @@ 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_pack_index_todo : Error<
+ "Pack index not implemented">;
+
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 82a503d01068d53..6b5f8210fa6d0e3 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -836,6 +836,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 30e0352c868637b..c7bbc3d6384306f 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1884,6 +1884,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);
@@ -2430,6 +2434,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_ty...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
ac0f831
to
d3be2f2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A LOT of stuff here... probably going to need a few more cycles on this to completely grok it. I didn't spend much time on tests, but would love if we could come up with some 'common patterns' (particularly any that others have sent you as a 'look at this cool thing i can do with this!) to put in tests.
clang/include/clang-c/Index.h
Outdated
@@ -1685,7 +1685,12 @@ enum CXCursorKind { | |||
*/ | |||
CXCursor_CXXParenListInitExpr = 155, | |||
|
|||
CXCursor_LastExpr = CXCursor_CXXParenListInitExpr, | |||
/** | |||
* Represents a C++26 pack indexing expression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Represents a C++26 pack indexing expression | |
* Represents a C++26 pack indexing expression. |
clang/include/clang/AST/ExprCXX.h
Outdated
std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(), | ||
Exprs); | ||
|
||
ExprDependence D = IndexExpr->getDependence(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I THINK most of this dependence calculation should be moved into the 'calculateDependence' infrastructure, right? There is a file somewhere where all of these are implemented.
clang/include/clang/AST/Type.h
Outdated
return *(getExpansionsPtr() + Index); | ||
} | ||
|
||
bool hasSelectedType() const { return Index != -1 && !isDependentType(); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't JUST the second part of this be sufficient? I would think that as soon as we're not dependent, the index should be 'set', correct? Or am I misunderstanding?
"%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">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"%0 is not a valid index for pack %1 of size %2">; | |
"invalid index %0 for pack %1 of size %2">; |
ArrayRef<Expr *> ExpandedExprs, bool EmptyPack) { | ||
|
||
std::optional<int64_t> Index; | ||
if (!IndexExpr->isValueDependent() && !IndexExpr->isTypeDependent()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this just isInstantiationDependent
?
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? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be nice to have an answer to this :D I'd be concerned about this somehow deciding this is a VLA..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't be a vla
Index = Value.getExtValue(); | ||
} | ||
|
||
if (Index && (!ExpandedExprs.empty() || EmptyPack)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, hrmph... as 'hacky' as caching the index feels, i'm softening here. I guess we needed it all along, so letting it be cached is perhaps not the worst.
I could be greater convinced if we could figure out if we could union-ize the index and the index expression (that is, do we REALLY need the indexexpr once we're instantiated?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think once we have an index, it's always a ConstantExpr so presumably we could extract the value from that.
I suppose keeping the expression is best if people want to do funny things with matchers?
clang/lib/Sema/SemaType.cpp
Outdated
Index = Value.getExtValue(); | ||
} | ||
|
||
if (FullyExpanded && Index) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, not sure what 'fully expanded' means here, can you help?
bool NotYetExpanded = Types.empty(); | ||
bool FullyExpanded = true; | ||
|
||
if (Types.empty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (Types.empty()) | |
if (NotYetExpanded) |
I think? Plus some comments here anyway, there are a couple of states crossing here.
|
||
|
||
std::optional<unsigned> getSelectedIndex() const { | ||
if (isInstantiationDependent()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there good reason this isn't an assert?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's called from places that don't have another way to check whether an it would be valid.
Now that we don't store an index, we have to look at the expression to establish what the index is.
clang/include/clang/AST/ExprCXX.h
Outdated
} | ||
|
||
ArrayRef<Expr *> getExpressions() const { | ||
if (TransformedExpressions == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this test necessary? Worst case it just gives an empty collection, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No more comments, this looks good to me, and now that we are post release-branch, I think I'm happy to have this merged.
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.
- 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.
* 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.
0503895
to
b8e82eb
Compare
The libcxx test failure are unrelated. |
This triggers asan on bots, fix coming in the next couple hours. |
Fixed in 143b510 |
lldb may also need to be fixed?
|
Yes. (I missed that, thanks). I'm not familiar with lldb codebase but the fix looks trivial. |
We do not handle pack indexing types (added by yet #72644) but we add them to some switch statement to ensure CI builds do not fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We hit some odd behavior in our downstream after this patch.
QualType desugar() const { | ||
if (hasSelectedType()) | ||
return getSelectedType(); | ||
return QualType(this, 0); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct? Calling getTypeInfo
on a PackIndexingType where hasSelectedType is false will cause it to infinitely recurse as it tries to desugar itself over and over again. This seems to happen if the type is broken, like the not_pack examples in cxx2c-pack-indexing.cpp.
Maybe the issue lies elsewhere, but something is strange with the error recovery for these types. Perhaps because isDependentType
isn't true for them when they are broken?
} | ||
|
||
QualType getSelectedType() const { | ||
assert(hasSelectedType() && "Type is dependant"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to dump/print a broken pack indexing expression/type breaks on this assertion. Try adding -ast-dump to cxx2c-pack-indexing.cpp and see what happens.
Ping. Just wondering if anyone has seen the above. @cor3ntin ? |
@bevin-hansson Thanks for letting me know, I'll look into it |
Fix a crash caused by incorrect assumptions Reported here llvm#72644 (comment)
Fix a crash caused by incorrect assumptions Reported here llvm#72644 (comment)
Fix a crash caused by incorrect assumptions Reported here #72644 (comment)
Fix a crash caused by incorrect assumptions Reported here llvm#72644 (comment)
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.