Author: Younan Zhang Date: 2024-11-07T15:37:14+08:00 New Revision: adb0d8ddceb143749c519d14b8b31b481071da77
URL: https://github.com/llvm/llvm-project/commit/adb0d8ddceb143749c519d14b8b31b481071da77 DIFF: https://github.com/llvm/llvm-project/commit/adb0d8ddceb143749c519d14b8b31b481071da77.diff LOG: [Clang] Distinguish expanding-pack-in-place cases for SubstTemplateTypeParmTypes (#114220) In 50e5411e4, we preserved the pack substitution index within SubstTemplateTypeParmType nodes and performed in-place expansions of packs such that type constraints on a lambda that serve as a pattern of a fold expression could be evaluated if the type constraints contain any packs that are expanded by the fold expression. However, we made an incorrect assumption of the condition under which in-place expansion should occur. For example, a SizeOfPackExpr case relies on SubstTemplateTypeParmType nodes being transformed to SubstTemplateTypeParmPackTypes rather than expanding them immediately in place. This fixes that by adding a flag to SubstTemplateTypeParmType to discriminate such in-place expansion situations. Fixes https://github.com/llvm/llvm-project/issues/113518 Added: Modified: clang/include/clang/AST/ASTContext.h clang/include/clang/AST/PropertiesBase.td clang/include/clang/AST/Type.h clang/include/clang/AST/TypeProperties.td clang/lib/AST/ASTContext.cpp clang/lib/AST/ASTImporter.cpp clang/lib/AST/Type.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/test/SemaCXX/cxx20-ctad-type-alias.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index dfd5bd8add01a3..89fcb6789d880a 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1747,7 +1747,9 @@ class ASTContext : public RefCountedBase<ASTContext> { QualType getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional<unsigned> PackIndex) const; + std::optional<unsigned> PackIndex, + SubstTemplateTypeParmTypeFlag Flag = + SubstTemplateTypeParmTypeFlag::None) const; QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, unsigned Index, bool Final, const TemplateArgument &ArgPack); diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 5f3a885832e2e4..42883b6419261c 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -137,6 +137,7 @@ def Selector : PropertyType; def SourceLocation : PropertyType; def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; } def ExprRef : SubclassPropertyType<"Expr", StmtRef>; +def SubstTemplateTypeParmTypeFlag : EnumPropertyType; def TemplateArgument : PropertyType; def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">; def TemplateName : DefaultValuePropertyType; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 1bcc7ee0b70dee..8979129017163b 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1802,6 +1802,15 @@ enum class AutoTypeKeyword { GNUAutoType }; +enum class SubstTemplateTypeParmTypeFlag { + None, + + /// Whether to expand the pack using the stored PackIndex in place. This is + /// useful for e.g. substituting into an atomic constraint expression, where + /// that expression is part of an unexpanded pack. + ExpandPacksInPlace, +}; + enum class ArraySizeModifier; enum class ElaboratedTypeKeyword; enum class VectorKind; @@ -2171,6 +2180,9 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { LLVM_PREFERRED_TYPE(bool) unsigned HasNonCanonicalUnderlyingType : 1; + LLVM_PREFERRED_TYPE(SubstTemplateTypeParmTypeFlag) + unsigned SubstitutionFlag : 1; + // The index of the template parameter this substitution represents. unsigned Index : 15; @@ -6387,7 +6399,8 @@ class SubstTemplateTypeParmType final Decl *AssociatedDecl; SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, - unsigned Index, std::optional<unsigned> PackIndex); + unsigned Index, std::optional<unsigned> PackIndex, + SubstTemplateTypeParmTypeFlag Flag); public: /// Gets the type that was substituted for the template @@ -6416,21 +6429,31 @@ class SubstTemplateTypeParmType final return SubstTemplateTypeParmTypeBits.PackIndex - 1; } + SubstTemplateTypeParmTypeFlag getSubstitutionFlag() const { + return static_cast<SubstTemplateTypeParmTypeFlag>( + SubstTemplateTypeParmTypeBits.SubstitutionFlag); + } + bool isSugared() const { return true; } QualType desugar() const { return getReplacementType(); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(), - getPackIndex()); + getPackIndex(), getSubstitutionFlag()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement, const Decl *AssociatedDecl, unsigned Index, - std::optional<unsigned> PackIndex) { + std::optional<unsigned> PackIndex, + SubstTemplateTypeParmTypeFlag Flag) { Replacement.Profile(ID); ID.AddPointer(AssociatedDecl); ID.AddInteger(Index); ID.AddInteger(PackIndex ? *PackIndex - 1 : 0); + ID.AddInteger(llvm::to_underlying(Flag)); + assert((Flag != SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace || + PackIndex) && + "ExpandPacksInPlace needs a valid PackIndex"); } static bool classof(const Type *T) { diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 42f62695963a2d..a8b9c920b617c0 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -824,11 +824,14 @@ let Class = SubstTemplateTypeParmType in { def : Property<"PackIndex", Optional<UInt32>> { let Read = [{ node->getPackIndex() }]; } + def : Property<"SubstitutionFlag", SubstTemplateTypeParmTypeFlag> { + let Read = [{ node->getSubstitutionFlag() }]; + } // The call to getCanonicalType here existed in ASTReader.cpp, too. def : Creator<[{ return ctx.getSubstTemplateTypeParmType( - replacementType, associatedDecl, Index, PackIndex); + replacementType, associatedDecl, Index, PackIndex, SubstitutionFlag); }]>; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 68ddbc5d09dc59..09d159e5c3efd6 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5303,10 +5303,11 @@ QualType ASTContext::getHLSLAttributedResourceType( /// Retrieve a substitution-result type. QualType ASTContext::getSubstTemplateTypeParmType( QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional<unsigned> PackIndex) const { + std::optional<unsigned> PackIndex, + SubstTemplateTypeParmTypeFlag Flag) const { llvm::FoldingSetNodeID ID; SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index, - PackIndex); + PackIndex, Flag); void *InsertPos = nullptr; SubstTemplateTypeParmType *SubstParm = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -5316,7 +5317,7 @@ QualType ASTContext::getSubstTemplateTypeParmType( !Replacement.isCanonical()), alignof(SubstTemplateTypeParmType)); SubstParm = new (Mem) SubstTemplateTypeParmType(Replacement, AssociatedDecl, - Index, PackIndex); + Index, PackIndex, Flag); Types.push_back(SubstParm); SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 6e31df691fa104..35aba41f0052af 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1628,8 +1628,8 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType( return ToReplacementTypeOrErr.takeError(); return Importer.getToContext().getSubstTemplateTypeParmType( - *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(), - T->getPackIndex()); + *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(), T->getPackIndex(), + T->getSubstitutionFlag()); } ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType( diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 6bf2908e667c07..7de13977176f2d 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4219,7 +4219,7 @@ static const TemplateTypeParmDecl *getReplacedParameter(Decl *D, SubstTemplateTypeParmType::SubstTemplateTypeParmType( QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional<unsigned> PackIndex) + std::optional<unsigned> PackIndex, SubstTemplateTypeParmTypeFlag Flag) : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(), Replacement->getDependence()), AssociatedDecl(AssociatedDecl) { @@ -4230,6 +4230,10 @@ SubstTemplateTypeParmType::SubstTemplateTypeParmType( SubstTemplateTypeParmTypeBits.Index = Index; SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0; + SubstTemplateTypeParmTypeBits.SubstitutionFlag = llvm::to_underlying(Flag); + assert((Flag != SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace || + PackIndex) && + "ExpandPacksInPlace needs a valid PackIndex"); assert(AssociatedDecl != nullptr); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index b3ae96582180a5..b1b92c0333c976 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1661,14 +1661,17 @@ namespace { QualType TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, SubstTemplateTypeParmTypeLoc TL) { - if (SemaRef.CodeSynthesisContexts.back().Kind != - Sema::CodeSynthesisContext::ConstraintSubstitution) + const SubstTemplateTypeParmType *Type = TL.getTypePtr(); + if (Type->getSubstitutionFlag() != + SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace) return inherited::TransformSubstTemplateTypeParmType(TLB, TL); - auto PackIndex = TL.getTypePtr()->getPackIndex(); - std::optional<Sema::ArgumentPackSubstitutionIndexRAII> SubstIndex; - if (SemaRef.ArgumentPackSubstitutionIndex == -1 && PackIndex) - SubstIndex.emplace(SemaRef, *PackIndex); + assert(Type->getPackIndex()); + TemplateArgument TA = TemplateArgs( + Type->getReplacedParameter()->getDepth(), Type->getIndex()); + assert(*Type->getPackIndex() + 1 <= TA.pack_size()); + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex( + SemaRef, TA.pack_size() - 1 - *Type->getPackIndex()); return inherited::TransformSubstTemplateTypeParmType(TLB, TL); } @@ -3147,7 +3150,11 @@ struct ExpandPackedTypeConstraints using inherited = TreeTransform<ExpandPackedTypeConstraints>; - ExpandPackedTypeConstraints(Sema &SemaRef) : inherited(SemaRef) {} + const MultiLevelTemplateArgumentList &TemplateArgs; + + ExpandPackedTypeConstraints( + Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs) + : inherited(SemaRef), TemplateArgs(TemplateArgs) {} using inherited::TransformTemplateTypeParmType; @@ -3163,9 +3170,15 @@ struct ExpandPackedTypeConstraints assert(SemaRef.ArgumentPackSubstitutionIndex != -1); + TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex()); + + std::optional<unsigned> PackIndex; + if (Arg.getKind() == TemplateArgument::Pack) + PackIndex = Arg.pack_size() - 1 - SemaRef.ArgumentPackSubstitutionIndex; + QualType Result = SemaRef.Context.getSubstTemplateTypeParmType( - TL.getType(), T->getDecl(), T->getIndex(), - SemaRef.ArgumentPackSubstitutionIndex); + TL.getType(), T->getDecl(), T->getIndex(), PackIndex, + SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace); SubstTemplateTypeParmTypeLoc NewTL = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -3224,8 +3237,8 @@ bool Sema::SubstTypeConstraint( TemplateArgumentListInfo InstArgs; InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); - if (ExpandPackedTypeConstraints(*this).SubstTemplateArguments( - TemplArgInfo->arguments(), InstArgs)) + if (ExpandPackedTypeConstraints(*this, TemplateArgs) + .SubstTemplateArguments(TemplArgInfo->arguments(), InstArgs)) return true; // The type of the original parameter. diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index 675c32a81f1ae8..2d43e46b9e3d76 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -494,3 +494,22 @@ template <typename V> using Alias = S<V>; Alias A(42); } // namespace GH111508 + +namespace GH113518 { + +template <class T, unsigned N> struct array { + T value[N]; +}; + +template <typename Tp, typename... Up> +array(Tp, Up...) -> array<Tp, 1 + sizeof...(Up)>; + +template <typename T> struct ArrayType { + template <unsigned size> using Array = array<T, size>; +}; + +template <ArrayType<int>::Array array> void test() {} + +void foo() { test<{1, 2, 3}>(); } + +} // namespace GH113518 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits