diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index a4d36f2eacd5d..e54fa8e47b736 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1731,7 +1731,9 @@ class ASTContext : public RefCountedBase { QualType getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional PackIndex) const; + std::optional 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 3057669e3758b..46e5c75086875 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -136,6 +136,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 40e617bf8f3b8..1faaf93c41e22 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1801,6 +1801,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; @@ -2170,6 +2179,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; @@ -6393,7 +6405,8 @@ class SubstTemplateTypeParmType final Decl *AssociatedDecl; SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, - unsigned Index, std::optional PackIndex); + unsigned Index, std::optional PackIndex, + SubstTemplateTypeParmTypeFlag Flag); public: /// Gets the type that was substituted for the template @@ -6422,21 +6435,31 @@ class SubstTemplateTypeParmType final return SubstTemplateTypeParmTypeBits.PackIndex - 1; } + SubstTemplateTypeParmTypeFlag getSubstitutionFlag() const { + return static_cast( + 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 PackIndex) { + std::optional 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 d05072607e949..80c3c5352606c 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -820,11 +820,14 @@ let Class = SubstTemplateTypeParmType in { def : Property<"PackIndex", Optional> { 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 4bf8ddd762e9a..cc8115604e803 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5248,10 +5248,11 @@ QualType ASTContext::getHLSLAttributedResourceType( /// Retrieve a substitution-result type. QualType ASTContext::getSubstTemplateTypeParmType( QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional PackIndex) const { + std::optional 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); @@ -5261,7 +5262,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 e7a6509167f0a..730f077137aa4 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1627,8 +1627,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 5232efae4e363..cd127fcd165b6 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4194,7 +4194,7 @@ static const TemplateTypeParmDecl *getReplacedParameter(Decl *D, SubstTemplateTypeParmType::SubstTemplateTypeParmType( QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional PackIndex) + std::optional PackIndex, SubstTemplateTypeParmTypeFlag Flag) : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(), Replacement->getDependence()), AssociatedDecl(AssociatedDecl) { @@ -4205,6 +4205,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 457a9968c32a4..7e565b20135ff 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1648,14 +1648,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 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); } @@ -3133,7 +3136,11 @@ struct ExpandPackedTypeConstraints using inherited = TreeTransform; - ExpandPackedTypeConstraints(Sema &SemaRef) : inherited(SemaRef) {} + const MultiLevelTemplateArgumentList &TemplateArgs; + + ExpandPackedTypeConstraints( + Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs) + : inherited(SemaRef), TemplateArgs(TemplateArgs) {} using inherited::TransformTemplateTypeParmType; @@ -3149,9 +3156,15 @@ struct ExpandPackedTypeConstraints assert(SemaRef.ArgumentPackSubstitutionIndex != -1); + TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex()); + + std::optional 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(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -3210,8 +3223,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 675c32a81f1ae..2d43e46b9e3d7 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -494,3 +494,22 @@ template using Alias = S; Alias A(42); } // namespace GH111508 + +namespace GH113518 { + +template struct array { + T value[N]; +}; + +template +array(Tp, Up...) -> array; + +template struct ArrayType { + template using Array = array; +}; + +template ::Array array> void test() {} + +void foo() { test<{1, 2, 3}>(); } + +} // namespace GH113518