From aacdc657fc255b2547bb37ee9bacde2df0452298 Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Wed, 4 Sep 2024 16:34:27 +0800 Subject: [PATCH] [Clang] Preserve the ExpandsToEmpty flag in PackIndexingType (#107181) Similar to PackIndexingExpr, we should avoid another round of transformation of the pattern if the pattern has already turned out to be an empty pack. As an outcome, the empty SubstTemplateTypeParmPackType won't occur, and we don't need to collect any unexpanded packs. Fixes https://github.com/llvm/llvm-project/issues/105903 --- clang/docs/ReleaseNotes.rst | 2 +- clang/include/clang/AST/Type.h | 13 +++++++++---- clang/include/clang/AST/TypeProperties.td | 5 ++++- clang/lib/AST/ASTContext.cpp | 12 +++++++----- clang/lib/AST/Type.cpp | 7 ++++--- clang/lib/Sema/TreeTransform.h | 4 ++-- clang/test/SemaCXX/cxx2c-pack-indexing.cpp | 12 ++++++++++++ 7 files changed, 39 insertions(+), 16 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 511724c73015..4128ca78ce39 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -345,7 +345,7 @@ Bug Fixes to C++ Support - Fixed a constraint comparison bug for friend declarations. (#GH78101) - Fix handling of ``_`` as the name of a lambda's init capture variable. (#GH107024) - Fix an issue with dependent source location expressions (#GH106428), (#GH81155), (#GH80210), (#GH85373) - +- Fixed a bug in the substitution of empty pack indexing types. (#GH105903) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 08f7638d7d8f..853226118af4 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5828,12 +5828,15 @@ class PackIndexingType final QualType Pattern; Expr *IndexExpr; - unsigned Size; + unsigned Size : 31; + + LLVM_PREFERRED_TYPE(bool) + unsigned ExpandsToEmptyPack : 1; protected: friend class ASTContext; // ASTContext creates these. PackIndexingType(const ASTContext &Context, QualType Canonical, - QualType Pattern, Expr *IndexExpr, + QualType Pattern, Expr *IndexExpr, bool ExpandsToEmptyPack, ArrayRef Expansions = {}); public: @@ -5857,6 +5860,8 @@ public: bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; } + bool expandsToEmptyPack() const { return ExpandsToEmptyPack; } + ArrayRef getExpansions() const { return {getExpansionsPtr(), Size}; } @@ -5869,10 +5874,10 @@ public: if (hasSelectedType()) getSelectedType().Profile(ID); else - Profile(ID, Context, getPattern(), getIndexExpr()); + Profile(ID, Context, getPattern(), getIndexExpr(), expandsToEmptyPack()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType Pattern, Expr *E); + QualType Pattern, Expr *E, bool ExpandsToEmptyPack); private: const QualType *getExpansionsPtr() const { diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 3df19315fd57..539a344cb0b6 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -473,9 +473,12 @@ let Class = PackIndexingType in { def : Property<"indexExpression", ExprRef> { let Read = [{ node->getIndexExpr() }]; } + def : Property<"expandsToEmptyPack", Bool> { + let Read = [{ node->expandsToEmptyPack() }]; + } def : Creator<[{ - return ctx.getPackIndexingType(pattern, indexExpression); + return ctx.getPackIndexingType(pattern, indexExpression, expandsToEmptyPack); }]>; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index c61234aa4d1a..341ea98a1b14 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6188,11 +6188,13 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr, ArrayRef Expansions, int Index) const { QualType Canonical; + bool ExpandsToEmptyPack = FullySubstituted && Expansions.empty(); if (FullySubstituted && Index != -1) { Canonical = getCanonicalType(Expansions[Index]); } else { llvm::FoldingSetNodeID ID; - PackIndexingType::Profile(ID, *this, Pattern, IndexExpr); + PackIndexingType::Profile(ID, *this, Pattern, IndexExpr, + ExpandsToEmptyPack); void *InsertPos = nullptr; PackIndexingType *Canon = DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -6200,8 +6202,8 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr, void *Mem = Allocate( PackIndexingType::totalSizeToAlloc(Expansions.size()), TypeAlignment); - Canon = new (Mem) - PackIndexingType(*this, QualType(), Pattern, IndexExpr, Expansions); + Canon = new (Mem) PackIndexingType(*this, QualType(), Pattern, IndexExpr, + ExpandsToEmptyPack, Expansions); DependentPackIndexingTypes.InsertNode(Canon, InsertPos); } Canonical = QualType(Canon, 0); @@ -6210,8 +6212,8 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr, void *Mem = Allocate(PackIndexingType::totalSizeToAlloc(Expansions.size()), TypeAlignment); - auto *T = new (Mem) - PackIndexingType(*this, Canonical, Pattern, IndexExpr, Expansions); + auto *T = new (Mem) PackIndexingType(*this, Canonical, Pattern, IndexExpr, + ExpandsToEmptyPack, Expansions); Types.push_back(T); return QualType(T, 0); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index e89ce2e4b384..b976d1a0ee60 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3992,12 +3992,12 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, PackIndexingType::PackIndexingType(const ASTContext &Context, QualType Canonical, QualType Pattern, - Expr *IndexExpr, + Expr *IndexExpr, bool ExpandsToEmptyPack, ArrayRef Expansions) : Type(PackIndexing, Canonical, computeDependence(Pattern, IndexExpr, Expansions)), Context(Context), Pattern(Pattern), IndexExpr(IndexExpr), - Size(Expansions.size()) { + Size(Expansions.size()), ExpandsToEmptyPack(ExpandsToEmptyPack) { std::uninitialized_copy(Expansions.begin(), Expansions.end(), getTrailingObjects()); @@ -4042,9 +4042,10 @@ PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr, void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType Pattern, - Expr *E) { + Expr *E, bool ExpandsToEmptyPack) { Pattern.Profile(ID); E->Profile(ID, Context, true); + ID.AddBoolean(ExpandsToEmptyPack); } UnaryTransformType::UnaryTransformType(QualType BaseType, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 66e3f27fed9d..27eac401c28f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6687,10 +6687,10 @@ TreeTransform::TransformPackIndexingType(TypeLocBuilder &TLB, bool NotYetExpanded = Types.empty(); bool FullySubstituted = true; - if (Types.empty()) + if (Types.empty() && !PIT->expandsToEmptyPack()) Types = llvm::ArrayRef(&Pattern, 1); - for (const QualType &T : Types) { + for (QualType T : Types) { if (!T->containsUnexpandedParameterPack()) { QualType Transformed = getDerived().TransformType(T); if (Transformed.isNull()) diff --git a/clang/test/SemaCXX/cxx2c-pack-indexing.cpp b/clang/test/SemaCXX/cxx2c-pack-indexing.cpp index 7d7e80874621..962dbb8137f2 100644 --- a/clang/test/SemaCXX/cxx2c-pack-indexing.cpp +++ b/clang/test/SemaCXX/cxx2c-pack-indexing.cpp @@ -258,4 +258,16 @@ void f() { vars<0>::x<0>(); } +} // namespace GH105900 + +namespace GH105903 { + +template struct temp { + template static auto x() -> opts... [s] {} // expected-note {{invalid index 0 for pack 'opts' of size 0}} +}; + +void f() { + temp<>::x<0>(); // expected-error {{no matching}} } + +} // namespace GH105903