https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/132626
>From 17bbac4d1f447a448168de629f44d8c227d468e5 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <mizve...@gmail.com> Date: Sat, 22 Mar 2025 17:29:16 -0300 Subject: [PATCH 1/3] Revert "[Clang] Distinguish expanding-pack-in-place cases for SubstTemplateTypeParmTypes (#114220)" This reverts commit adb0d8ddceb143749c519d14b8b31b481071da77. --- clang/include/clang/AST/ASTContext.h | 4 +-- clang/include/clang/AST/PropertiesBase.td | 1 - clang/include/clang/AST/Type.h | 29 ++-------------- clang/include/clang/AST/TypeProperties.td | 5 +-- clang/lib/AST/ASTContext.cpp | 7 ++-- clang/lib/AST/ASTImporter.cpp | 4 +-- clang/lib/AST/Type.cpp | 6 +--- clang/lib/Sema/SemaTemplateInstantiate.cpp | 35 ++++++-------------- clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 2 +- 9 files changed, 23 insertions(+), 70 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index af8c49e99a7ce..1f7c75559e1e9 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1798,9 +1798,7 @@ class ASTContext : public RefCountedBase<ASTContext> { QualType getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional<unsigned> PackIndex, - SubstTemplateTypeParmTypeFlag Flag = - SubstTemplateTypeParmTypeFlag::None) const; + std::optional<unsigned> PackIndex) 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 42883b6419261..5f3a885832e2e 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -137,7 +137,6 @@ 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 65756203f2073..3b80f962a3bc6 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1786,15 +1786,6 @@ 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; @@ -2164,9 +2155,6 @@ 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; @@ -6396,8 +6384,7 @@ class SubstTemplateTypeParmType final Decl *AssociatedDecl; SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, - unsigned Index, std::optional<unsigned> PackIndex, - SubstTemplateTypeParmTypeFlag Flag); + unsigned Index, std::optional<unsigned> PackIndex); public: /// Gets the type that was substituted for the template @@ -6426,31 +6413,21 @@ 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(), getSubstitutionFlag()); + getPackIndex()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement, const Decl *AssociatedDecl, unsigned Index, - std::optional<unsigned> PackIndex, - SubstTemplateTypeParmTypeFlag Flag) { + std::optional<unsigned> PackIndex) { 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 27f71bf5cc62f..4d89d8a47396a 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -827,14 +827,11 @@ 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, SubstitutionFlag); + replacementType, associatedDecl, Index, PackIndex); }]>; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index de868ac821745..4d2ca9ec1a123 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5449,11 +5449,10 @@ QualType ASTContext::getHLSLAttributedResourceType( /// Retrieve a substitution-result type. QualType ASTContext::getSubstTemplateTypeParmType( QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional<unsigned> PackIndex, - SubstTemplateTypeParmTypeFlag Flag) const { + std::optional<unsigned> PackIndex) const { llvm::FoldingSetNodeID ID; SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index, - PackIndex, Flag); + PackIndex); void *InsertPos = nullptr; SubstTemplateTypeParmType *SubstParm = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -5463,7 +5462,7 @@ QualType ASTContext::getSubstTemplateTypeParmType( !Replacement.isCanonical()), alignof(SubstTemplateTypeParmType)); SubstParm = new (Mem) SubstTemplateTypeParmType(Replacement, AssociatedDecl, - Index, PackIndex, Flag); + Index, PackIndex); Types.push_back(SubstParm); SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 1db30b3f3f76f..b63e4da4896ff 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1631,8 +1631,8 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType( return ToReplacementTypeOrErr.takeError(); return Importer.getToContext().getSubstTemplateTypeParmType( - *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(), T->getPackIndex(), - T->getSubstitutionFlag()); + *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(), + T->getPackIndex()); } ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType( diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 08798219c0b83..478c0b5f779b7 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4270,7 +4270,7 @@ static const TemplateTypeParmDecl *getReplacedParameter(Decl *D, SubstTemplateTypeParmType::SubstTemplateTypeParmType( QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional<unsigned> PackIndex, SubstTemplateTypeParmTypeFlag Flag) + std::optional<unsigned> PackIndex) : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(), Replacement->getDependence()), AssociatedDecl(AssociatedDecl) { @@ -4281,10 +4281,6 @@ 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 00dcadb41e8fb..6c9cd6512859a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1720,17 +1720,14 @@ namespace { QualType TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, SubstTemplateTypeParmTypeLoc TL) { - const SubstTemplateTypeParmType *Type = TL.getTypePtr(); - if (Type->getSubstitutionFlag() != - SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace) + if (SemaRef.CodeSynthesisContexts.back().Kind != + Sema::CodeSynthesisContext::ConstraintSubstitution) return inherited::TransformSubstTemplateTypeParmType(TLB, TL); - 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()); + auto PackIndex = TL.getTypePtr()->getPackIndex(); + std::optional<Sema::ArgumentPackSubstitutionIndexRAII> SubstIndex; + if (SemaRef.ArgumentPackSubstitutionIndex == -1 && PackIndex) + SubstIndex.emplace(SemaRef, *PackIndex); return inherited::TransformSubstTemplateTypeParmType(TLB, TL); } @@ -3176,11 +3173,7 @@ struct ExpandPackedTypeConstraints using inherited = TreeTransform<ExpandPackedTypeConstraints>; - const MultiLevelTemplateArgumentList &TemplateArgs; - - ExpandPackedTypeConstraints( - Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs) - : inherited(SemaRef), TemplateArgs(TemplateArgs) {} + ExpandPackedTypeConstraints(Sema &SemaRef) : inherited(SemaRef) {} using inherited::TransformTemplateTypeParmType; @@ -3196,15 +3189,9 @@ 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(), PackIndex, - SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace); + TL.getType(), T->getDecl(), T->getIndex(), + SemaRef.ArgumentPackSubstitutionIndex); SubstTemplateTypeParmTypeLoc NewTL = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -3263,8 +3250,8 @@ bool Sema::SubstTypeConstraint( TemplateArgumentListInfo InstArgs; InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); - if (ExpandPackedTypeConstraints(*this, TemplateArgs) - .SubstTemplateArguments(TemplArgInfo->arguments(), InstArgs)) + if (ExpandPackedTypeConstraints(*this).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 832ce15e66250..c863cc841af42 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -485,7 +485,7 @@ struct Out { A(T2); }; A(int) -> A<T1>; - + template <typename T3> using B = A<T3>; }; >From e7ecd60e5fb7a9a14f7d85ab23587faadb543819 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <mizve...@gmail.com> Date: Sat, 22 Mar 2025 17:39:37 -0300 Subject: [PATCH 2/3] Revert "[Clang][Sema] Retain the expanding index for unevaluated type constraints (#109518)" This reverts commit 50e5411e4247421fd606f0a206682fcdf0303ae3. --- clang/include/clang/Sema/Sema.h | 1 - clang/lib/Sema/SemaTemplate.cpp | 6 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 127 +-------------------- clang/lib/Sema/SemaType.cpp | 8 +- 4 files changed, 7 insertions(+), 135 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 066bce61c74c1..373738f5f723c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11350,7 +11350,6 @@ class Sema final : public SemaBase { ConceptDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, - QualType ConstrainedType, SourceLocation EllipsisLoc); bool AttachTypeConstraint(AutoTypeLoc TL, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index be81b6a46b2c0..3c83721a481b7 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1133,8 +1133,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), ConceptName, CD, /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, - ConstrainedParameter, Context.getTypeDeclType(ConstrainedParameter), - EllipsisLoc); + ConstrainedParameter, EllipsisLoc); } template <typename ArgumentLocAppender> @@ -1191,7 +1190,6 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, ConceptDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, - QualType ConstrainedType, SourceLocation EllipsisLoc) { // C++2a [temp.param]p4: // [...] If Q is of the form C<A1, ..., An>, then let E' be @@ -1200,7 +1198,7 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs) : nullptr; - QualType ParamAsArgument = ConstrainedType; + QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, NS, NameInfo, NamedConcept, FoundDecl, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 6c9cd6512859a..ec9a2fb1e9542 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1717,21 +1717,6 @@ namespace { SubstTemplateTypeParmPackTypeLoc TL, bool SuppressObjCLifetime); - QualType - TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, - SubstTemplateTypeParmTypeLoc TL) { - if (SemaRef.CodeSynthesisContexts.back().Kind != - Sema::CodeSynthesisContext::ConstraintSubstitution) - return inherited::TransformSubstTemplateTypeParmType(TLB, TL); - - auto PackIndex = TL.getTypePtr()->getPackIndex(); - std::optional<Sema::ArgumentPackSubstitutionIndexRAII> SubstIndex; - if (SemaRef.ArgumentPackSubstitutionIndex == -1 && PackIndex) - SubstIndex.emplace(SemaRef, *PackIndex); - - return inherited::TransformSubstTemplateTypeParmType(TLB, TL); - } - CXXRecordDecl::LambdaDependencyKind ComputeLambdaDependency(LambdaScopeInfo *LSI) { if (auto TypeAlias = @@ -3166,58 +3151,6 @@ namespace { } // namespace -namespace { - -struct ExpandPackedTypeConstraints - : TreeTransform<ExpandPackedTypeConstraints> { - - using inherited = TreeTransform<ExpandPackedTypeConstraints>; - - ExpandPackedTypeConstraints(Sema &SemaRef) : inherited(SemaRef) {} - - using inherited::TransformTemplateTypeParmType; - - QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL, bool) { - const TemplateTypeParmType *T = TL.getTypePtr(); - if (!T->isParameterPack()) { - TemplateTypeParmTypeLoc NewTL = - TLB.push<TemplateTypeParmTypeLoc>(TL.getType()); - NewTL.setNameLoc(TL.getNameLoc()); - return TL.getType(); - } - - assert(SemaRef.ArgumentPackSubstitutionIndex != -1); - - QualType Result = SemaRef.Context.getSubstTemplateTypeParmType( - TL.getType(), T->getDecl(), T->getIndex(), - SemaRef.ArgumentPackSubstitutionIndex); - SubstTemplateTypeParmTypeLoc NewTL = - TLB.push<SubstTemplateTypeParmTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; - } - - QualType TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, - SubstTemplateTypeParmTypeLoc TL) { - const SubstTemplateTypeParmType *T = TL.getTypePtr(); - if (T->getPackIndex()) { - SubstTemplateTypeParmTypeLoc TypeLoc = - TLB.push<SubstTemplateTypeParmTypeLoc>(TL.getType()); - TypeLoc.setNameLoc(TL.getNameLoc()); - return TypeLoc.getType(); - } - return inherited::TransformSubstTemplateTypeParmType(TLB, TL); - } - - bool SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args, - TemplateArgumentListInfo &Out) { - return inherited::TransformTemplateArguments(Args.begin(), Args.end(), Out); - } -}; - -} // namespace - bool Sema::SubstTypeConstraint( TemplateTypeParmDecl *Inst, const TypeConstraint *TC, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -3226,62 +3159,9 @@ bool Sema::SubstTypeConstraint( TC->getTemplateArgsAsWritten(); if (!EvaluateConstraints) { - bool ShouldExpandExplicitTemplateArgs = - TemplArgInfo && ArgumentPackSubstitutionIndex != -1 && - llvm::any_of(TemplArgInfo->arguments(), [](auto &Arg) { - return Arg.getArgument().containsUnexpandedParameterPack(); - }); - - // We want to transform the packs into Subst* nodes for type constraints - // inside a pack expansion. For example, - // - // template <class... Ts> void foo() { - // bar([](C<Ts> auto value) {}...); - // } - // - // As we expand Ts in the process of instantiating foo(), and retain - // the original template depths of Ts until the constraint evaluation, we - // would otherwise have no chance to expand Ts by the time of evaluating - // C<auto, Ts>. - // - // So we form a Subst* node for Ts along with a proper substitution index - // here, and substitute the node with a complete MLTAL later in evaluation. - if (ShouldExpandExplicitTemplateArgs) { - TemplateArgumentListInfo InstArgs; - InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); - InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); - if (ExpandPackedTypeConstraints(*this).SubstTemplateArguments( - TemplArgInfo->arguments(), InstArgs)) - return true; - - // The type of the original parameter. - auto *ConstraintExpr = TC->getImmediatelyDeclaredConstraint(); - QualType ConstrainedType; - - if (auto *FE = dyn_cast<CXXFoldExpr>(ConstraintExpr)) { - assert(FE->getLHS()); - ConstraintExpr = FE->getLHS(); - } - auto *CSE = cast<ConceptSpecializationExpr>(ConstraintExpr); - assert(!CSE->getTemplateArguments().empty() && - "Empty template arguments?"); - ConstrainedType = CSE->getTemplateArguments()[0].getAsType(); - assert(!ConstrainedType.isNull() && - "Failed to extract the original ConstrainedType?"); - - return AttachTypeConstraint( - TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), - /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, - Inst, ConstrainedType, - Inst->isParameterPack() - ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) - ->getEllipsisLoc() - : SourceLocation()); - } - Inst->setTypeConstraint(TC->getConceptReference(), - TC->getImmediatelyDeclaredConstraint()); - return false; + Inst->setTypeConstraint(TC->getConceptReference(), + TC->getImmediatelyDeclaredConstraint()); + return false; } TemplateArgumentListInfo InstArgs; @@ -3297,7 +3177,6 @@ bool Sema::SubstTypeConstraint( TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), TC->getNamedConcept(), /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, Inst, - Context.getTypeDeclType(Inst), Inst->isParameterPack() ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) ->getEllipsisLoc() diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index aec33303780a0..9ba8e7121b731 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3054,9 +3054,7 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(), AutoLoc.getNamedConcept(), /*FoundDecl=*/AutoLoc.getFoundDecl(), AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, - InventedTemplateParam, - S.Context.getTypeDeclType(InventedTemplateParam), - D.getEllipsisLoc()); + InventedTemplateParam, D.getEllipsisLoc()); } } else { // The 'auto' appears in the decl-specifiers; we've not finished forming @@ -3093,9 +3091,7 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, /*FoundDecl=*/ USD ? cast<NamedDecl>(USD) : CD, TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, - InventedTemplateParam, - S.Context.getTypeDeclType(InventedTemplateParam), - D.getEllipsisLoc()); + InventedTemplateParam, D.getEllipsisLoc()); } } } >From 6b4f7cb8797c23de164bd7172e1988ddd7787fff Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <mizve...@gmail.com> Date: Sat, 22 Mar 2025 22:51:42 -0300 Subject: [PATCH 3/3] [clang] Concepts: support pack expansions for type constraints This reverts an earlier attempt to support these expansions, which was limited to type arguments and which subverted the purpose of SubstTemplateTypeParmType. This propagates the ArgumentPackSubstitutionIndex along with the AssociatedConstraint, so that the pack expansion works, without needing any new transforms or otherwise any changes to the template instanntiation process. This keeps the tests from the reverted commits, and adds a few more showing the new solution also works for NTTPs. This patch is incomplete: * It is likely missing plumbing the ArgumentPackSubstitutionIndex into more places. * The Normalization cache is not adapted so it indexes on the ArgumentPackSubstitutionIndex as well. One new test is added, which in any case shows an ambiguous call, but if the normalization cache were corrected, the reason for ambighuity would change from subsumption both ways, to neither subsumes the other. I am not sure if the current language rules would allow for a test case where the pack index would break an ambiguity, this is left for future consideration. --- .../modernize/UseConstraintsCheck.cpp | 4 +- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/AST/ASTConcept.h | 11 +- clang/include/clang/AST/Decl.h | 17 +- clang/include/clang/AST/DeclTemplate.h | 26 ++- clang/include/clang/Sema/Sema.h | 25 ++- clang/include/clang/Sema/SemaConcept.h | 27 ++- clang/lib/AST/ASTImporter.cpp | 3 +- clang/lib/AST/DeclTemplate.cpp | 26 +-- clang/lib/Sema/SemaCodeComplete.cpp | 9 +- clang/lib/Sema/SemaConcept.cpp | 177 ++++++++++-------- clang/lib/Sema/SemaDecl.cpp | 7 +- clang/lib/Sema/SemaExprCXX.cpp | 7 +- clang/lib/Sema/SemaOverload.cpp | 4 +- clang/lib/Sema/SemaTemplate.cpp | 12 +- clang/lib/Sema/SemaTemplateDeduction.cpp | 16 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 16 +- clang/lib/Serialization/ASTReaderDecl.cpp | 4 +- clang/lib/Serialization/ASTWriterDecl.cpp | 1 + .../SemaCXX/fold_lambda_with_variadics.cpp | 29 +++ clang/unittests/AST/SourceLocationTest.cpp | 6 +- 21 files changed, 278 insertions(+), 151 deletions(-) diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp index ea4d99586c711..fb82efb4dd211 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp @@ -356,7 +356,7 @@ static std::vector<FixItHint> handleReturnType(const FunctionDecl *Function, if (!TypeText) return {}; - SmallVector<const Expr *, 3> ExistingConstraints; + SmallVector<AssociatedConstraint, 3> ExistingConstraints; Function->getAssociatedConstraints(ExistingConstraints); if (!ExistingConstraints.empty()) { // FIXME - Support adding new constraints to existing ones. Do we need to @@ -404,7 +404,7 @@ handleTrailingTemplateType(const FunctionTemplateDecl *FunctionTemplate, if (!ConditionText) return {}; - SmallVector<const Expr *, 3> ExistingConstraints; + SmallVector<AssociatedConstraint, 3> ExistingConstraints; Function->getAssociatedConstraints(ExistingConstraints); if (!ExistingConstraints.empty()) { // FIXME - Support adding new constraints to existing ones. Do we need to diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8182bccdd2da8..954e4a1ed5a97 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -346,6 +346,8 @@ Bug Fixes to C++ Support - Clang now uses the parameter location for abbreviated function templates in ``extern "C"``. (#GH46386) - Clang will emit an error instead of crash when use co_await or co_yield in C++26 braced-init-list template parameter initialization. (#GH78426) +- Improved fix for an issue with pack expansions of type constraints, where this + now also works if the constraint has non-type or template template parameters. - Fixes matching of nested template template parameters. (#GH130362) - Correctly diagnoses template template paramters which have a pack parameter not in the last position. diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index 00500e214f4ce..f89899c3ea7b1 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -229,12 +229,15 @@ class TypeConstraint { /// type-constraint. Expr *ImmediatelyDeclaredConstraint = nullptr; ConceptReference *ConceptRef; + int ArgumentPackSubstitutionIndex; public: TypeConstraint(ConceptReference *ConceptRef, - Expr *ImmediatelyDeclaredConstraint) + Expr *ImmediatelyDeclaredConstraint, + int ArgumentPackSubstitutionIndex) : ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint), - ConceptRef(ConceptRef) {} + ConceptRef(ConceptRef), + ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {} /// \brief Get the immediately-declared constraint expression introduced by /// this type-constraint, that is - the constraint expression that is added to @@ -245,6 +248,10 @@ class TypeConstraint { ConceptReference *getConceptReference() const { return ConceptRef; } + int getArgumentPackSubstitutionIndex() const { + return ArgumentPackSubstitutionIndex; + } + // FIXME: Instead of using these concept related functions the callers should // directly work with the corresponding ConceptReference. ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); } diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index efac36e49351e..6557a4c4962ec 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -78,6 +78,18 @@ class UnresolvedSetImpl; class VarTemplateDecl; enum class ImplicitParamKind; +// Holds a constraint expression along with a pack expansion index, if +// expanded. +struct AssociatedConstraint { + const Expr *ConstraintExpr; + int ArgumentPackSubstitutionIndex; + + AssociatedConstraint(const Expr *ConstraintExpr, + int ArgumentPackSubstitutionIndex) + : ConstraintExpr(ConstraintExpr), + ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {} +}; + /// The top declaration context. class TranslationUnitDecl : public Decl, public DeclContext, @@ -2631,9 +2643,10 @@ class FunctionDecl : public DeclaratorDecl, /// /// Use this instead of getTrailingRequiresClause for concepts APIs that /// accept an ArrayRef of constraint expressions. - void getAssociatedConstraints(SmallVectorImpl<const Expr *> &AC) const { + void + getAssociatedConstraints(SmallVectorImpl<AssociatedConstraint> &AC) const { if (auto *TRC = getTrailingRequiresClause()) - AC.push_back(TRC); + AC.emplace_back(TRC, /*ArgumentPackSubstitutionIndex=*/-1); } /// Get the message that indicates why this function was deleted. diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index b27e698236c02..6123273ce5ec1 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -195,7 +195,8 @@ class TemplateParameterList final /// /// The constraints in the resulting list are to be treated as if in a /// conjunction ("and"). - void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const; + void getAssociatedConstraints( + llvm::SmallVectorImpl<AssociatedConstraint> &AC) const; bool hasAssociatedConstraints() const; @@ -422,7 +423,8 @@ class TemplateDecl : public NamedDecl { /// including constraint-expressions derived from the requires-clause, /// trailing requires-clause (for functions and methods) and constrained /// template parameters. - void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const; + void getAssociatedConstraints( + llvm::SmallVectorImpl<AssociatedConstraint> &AC) const; bool hasAssociatedConstraints() const; @@ -1341,7 +1343,8 @@ class TemplateTypeParmDecl final : public TypeDecl, } void setTypeConstraint(ConceptReference *CR, - Expr *ImmediatelyDeclaredConstraint); + Expr *ImmediatelyDeclaredConstraint, + int ArgumentPackSubstitutionIndex); /// Determine whether this template parameter has a type-constraint. bool hasTypeConstraint() const { @@ -1353,9 +1356,11 @@ class TemplateTypeParmDecl final : public TypeDecl, /// /// Use this instead of getTypeConstraint for concepts APIs that /// accept an ArrayRef of constraint expressions. - void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { + void getAssociatedConstraints( + llvm::SmallVectorImpl<AssociatedConstraint> &AC) const { if (HasTypeConstraint) - AC.push_back(getTypeConstraint()->getImmediatelyDeclaredConstraint()); + AC.emplace_back(getTypeConstraint()->getImmediatelyDeclaredConstraint(), + getTypeConstraint()->getArgumentPackSubstitutionIndex()); } SourceRange getSourceRange() const override LLVM_READONLY; @@ -1574,9 +1579,10 @@ class NonTypeTemplateParmDecl final /// /// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for /// concepts APIs that accept an ArrayRef of constraint expressions. - void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { + void getAssociatedConstraints( + llvm::SmallVectorImpl<AssociatedConstraint> &AC) const { if (Expr *E = getPlaceholderTypeConstraint()) - AC.push_back(E); + AC.emplace_back(E, /*ArgumentPackSubstitutionIndex=*/-1); } // Implement isa/cast/dyncast/etc. @@ -2169,7 +2175,8 @@ class ClassTemplatePartialSpecializationDecl /// /// The constraints in the resulting list are to be treated as if in a /// conjunction ("and"). - void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { + void getAssociatedConstraints( + llvm::SmallVectorImpl<AssociatedConstraint> &AC) const { TemplateParams->getAssociatedConstraints(AC); } @@ -2943,7 +2950,8 @@ class VarTemplatePartialSpecializationDecl /// /// The constraints in the resulting list are to be treated as if in a /// conjunction ("and"). - void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { + void getAssociatedConstraints( + llvm::SmallVectorImpl<AssociatedConstraint> &AC) const { TemplateParams->getAssociatedConstraints(AC); } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 373738f5f723c..c98eea1c05060 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14550,13 +14550,14 @@ class Sema final : public SemaBase { /// \returns true if an error occurred and satisfaction could not be checked, /// false otherwise. bool CheckConstraintSatisfaction( - const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + const NamedDecl *Template, + ArrayRef<AssociatedConstraint> AssociatedConstraints, const MultiLevelTemplateArgumentList &TemplateArgLists, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { llvm::SmallVector<Expr *, 4> Converted; - return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted, - TemplateArgLists, TemplateIDRange, - Satisfaction); + return CheckConstraintSatisfaction(Template, AssociatedConstraints, + Converted, TemplateArgLists, + TemplateIDRange, Satisfaction); } /// \brief Check whether the given list of constraint expressions are @@ -14582,7 +14583,8 @@ class Sema final : public SemaBase { /// \returns true if an error occurred and satisfaction could not be checked, /// false otherwise. bool CheckConstraintSatisfaction( - const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + const NamedDecl *Template, + ArrayRef<AssociatedConstraint> AssociatedConstraints, llvm::SmallVectorImpl<Expr *> &ConvertedConstraints, const MultiLevelTemplateArgumentList &TemplateArgList, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); @@ -14659,7 +14661,8 @@ class Sema final : public SemaBase { bool First = true); const NormalizedConstraint *getNormalizedAssociatedConstraints( - NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints); + NamedDecl *ConstrainedDecl, + ArrayRef<AssociatedConstraint> AssociatedConstraints); /// \brief Check whether the given declaration's associated constraints are /// at least as constrained than another declaration's according to the @@ -14669,8 +14672,10 @@ class Sema final : public SemaBase { /// at least constrained than D2, and false otherwise. /// /// \returns true if an error occurred, false otherwise. - bool IsAtLeastAsConstrained(NamedDecl *D1, MutableArrayRef<const Expr *> AC1, - NamedDecl *D2, MutableArrayRef<const Expr *> AC2, + bool IsAtLeastAsConstrained(NamedDecl *D1, + MutableArrayRef<AssociatedConstraint> AC1, + NamedDecl *D2, + MutableArrayRef<AssociatedConstraint> AC2, bool &Result); /// If D1 was not at least as constrained as D2, but would've been if a pair @@ -14678,8 +14683,8 @@ class Sema final : public SemaBase { /// repeated in two separate places in code. /// \returns true if such a diagnostic was emitted, false otherwise. bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic( - NamedDecl *D1, ArrayRef<const Expr *> AC1, NamedDecl *D2, - ArrayRef<const Expr *> AC2); + NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1, NamedDecl *D2, + ArrayRef<AssociatedConstraint> AC2); private: /// Caches pairs of template-like decls whose associated constraints were diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h index 5c599a70532f6..fe27a03df4863 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -29,12 +29,12 @@ class Sema; enum { ConstraintAlignment = 8 }; struct alignas(ConstraintAlignment) AtomicConstraint { - const Expr *ConstraintExpr; + AssociatedConstraint AC; NamedDecl *ConstraintDecl; std::optional<ArrayRef<TemplateArgumentLoc>> ParameterMapping; - AtomicConstraint(const Expr *ConstraintExpr, NamedDecl *ConstraintDecl) - : ConstraintExpr(ConstraintExpr), ConstraintDecl(ConstraintDecl) {}; + AtomicConstraint(const AssociatedConstraint &AC, NamedDecl *ConstraintDecl) + : AC(AC), ConstraintDecl(ConstraintDecl) {}; bool hasMatchingParameterMapping(ASTContext &C, const AtomicConstraint &Other) const { @@ -70,7 +70,14 @@ struct alignas(ConstraintAlignment) AtomicConstraint { // We do not actually substitute the parameter mappings into the // constraint expressions, therefore the constraint expressions are // the originals, and comparing them will suffice. - if (ConstraintExpr != Other.ConstraintExpr) + if (AC.ConstraintExpr != Other.AC.ConstraintExpr) + return false; + + // FIXME: As the normalization cache doesn't take + // ArgumentPackSubstitutionIndex into account, + // this won't have an effect. + if (AC.ArgumentPackSubstitutionIndex != + Other.AC.ArgumentPackSubstitutionIndex) return false; // Check that the parameter lists are identical @@ -152,9 +159,11 @@ struct NormalizedConstraint { private: static std::optional<NormalizedConstraint> - fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E); + fromConstraintAssociatedConstraints(Sema &S, NamedDecl *D, + ArrayRef<AssociatedConstraint> ACs); static std::optional<NormalizedConstraint> - fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E); + fromConstraintAssociatedConstraint(Sema &S, NamedDecl *D, + AssociatedConstraint AC); }; struct alignas(ConstraintAlignment) NormalizedConstraintPair { @@ -180,7 +189,7 @@ struct alignas(ConstraintAlignment) FoldExpandedConstraint { const NormalizedConstraint *getNormalizedAssociatedConstraints( Sema &S, NamedDecl *ConstrainedDecl, - ArrayRef<const Expr *> AssociatedConstraints); + ArrayRef<AssociatedConstraint> AssociatedConstraints); template <typename AtomicSubsumptionEvaluator> bool subsumes(const NormalForm &PDNF, const NormalForm &QCNF, @@ -226,8 +235,8 @@ bool subsumes(const NormalForm &PDNF, const NormalForm &QCNF, } template <typename AtomicSubsumptionEvaluator> -bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P, NamedDecl *DQ, - ArrayRef<const Expr *> Q, bool &Subsumes, +bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<AssociatedConstraint> P, + NamedDecl *DQ, ArrayRef<AssociatedConstraint> Q, bool &Subsumes, const AtomicSubsumptionEvaluator &E) { // C++ [temp.constr.order] p2 // In order to determine if a constraint P subsumes a constraint Q, P is diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index b63e4da4896ff..d397c9285ed76 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -5983,7 +5983,8 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { if (Err) return std::move(Err); - ToD->setTypeConstraint(ToConceptRef, ToIDC); + ToD->setTypeConstraint(ToConceptRef, ToIDC, + TC->getArgumentPackSubstitutionIndex()); } if (Error Err = importTemplateParameterDefaultArgument(D, ToD)) diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index c0f5be51db5f3..ff1c3028f89ba 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -223,20 +223,21 @@ static bool AdoptTemplateParameterList(TemplateParameterList *Params, return Invalid; } -void TemplateParameterList:: -getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { +void TemplateParameterList::getAssociatedConstraints( + llvm::SmallVectorImpl<AssociatedConstraint> &ACs) const { if (HasConstrainedParameters) for (const NamedDecl *Param : *this) { if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { if (const auto *TC = TTP->getTypeConstraint()) - AC.push_back(TC->getImmediatelyDeclaredConstraint()); + ACs.emplace_back(TC->getImmediatelyDeclaredConstraint(), + TC->getArgumentPackSubstitutionIndex()); } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { if (const Expr *E = NTTP->getPlaceholderTypeConstraint()) - AC.push_back(E); + ACs.emplace_back(E, /*ArgumentPackSubstitutionIndex=*/-1); } } if (HasRequiresClause) - AC.push_back(getRequiresClause()); + ACs.emplace_back(getRequiresClause(), /*ArgumentPackSubstitutionIndex=*/-1); } bool TemplateParameterList::hasAssociatedConstraints() const { @@ -286,12 +287,12 @@ TemplateDecl::TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, void TemplateDecl::anchor() {} -void TemplateDecl:: -getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { - TemplateParams->getAssociatedConstraints(AC); +void TemplateDecl::getAssociatedConstraints( + llvm::SmallVectorImpl<AssociatedConstraint> &ACs) const { + TemplateParams->getAssociatedConstraints(ACs); if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl())) if (const Expr *TRC = FD->getTrailingRequiresClause()) - AC.push_back(TRC); + ACs.emplace_back(TRC, /*ArgumentPackSubstitutionIndex=*/-1); } bool TemplateDecl::hasAssociatedConstraints() const { @@ -748,14 +749,15 @@ bool TemplateTypeParmDecl::isParameterPack() const { } void TemplateTypeParmDecl::setTypeConstraint( - ConceptReference *Loc, Expr *ImmediatelyDeclaredConstraint) { + ConceptReference *Loc, Expr *ImmediatelyDeclaredConstraint, + int ArgumentPackSubstitutionIndex) { assert(HasTypeConstraint && "HasTypeConstraint=true must be passed at construction in order to " "call setTypeConstraint"); assert(!TypeConstraintInitialized && "TypeConstraint was already initialized!"); - new (getTrailingObjects<TypeConstraint>()) - TypeConstraint(Loc, ImmediatelyDeclaredConstraint); + new (getTrailingObjects<TypeConstraint>()) TypeConstraint( + Loc, ImmediatelyDeclaredConstraint, ArgumentPackSubstitutionIndex); TypeConstraintInitialized = true; } diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 2003701b65654..db4ddfeaccdc2 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5463,8 +5463,9 @@ class ConceptInfo { // that T is attached to in order to gather the relevant constraints. ConceptInfo(const TemplateTypeParmType &BaseType, Scope *S) { auto *TemplatedEntity = getTemplatedEntity(BaseType.getDecl(), S); - for (const Expr *E : constraintsForTemplatedEntity(TemplatedEntity)) - believe(E, &BaseType); + for (const AssociatedConstraint &AC : + constraintsForTemplatedEntity(TemplatedEntity)) + believe(AC.ConstraintExpr, &BaseType); } std::vector<Member> members() { @@ -5696,9 +5697,9 @@ class ConceptInfo { // Gets all the type constraint expressions that might apply to the type // variables associated with DC (as returned by getTemplatedEntity()). - static SmallVector<const Expr *, 1> + static SmallVector<AssociatedConstraint, 1> constraintsForTemplatedEntity(DeclContext *DC) { - SmallVector<const Expr *, 1> Result; + SmallVector<AssociatedConstraint, 1> Result; if (DC == nullptr) return Result; // Primary templates can have constraints. diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 57dc4154a537f..5a70102f992c8 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -566,11 +566,12 @@ static ExprResult calculateConstraintSatisfaction( } static bool CheckConstraintSatisfaction( - Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + Sema &S, const NamedDecl *Template, + ArrayRef<AssociatedConstraint> AssociatedConstraints, llvm::SmallVectorImpl<Expr *> &Converted, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { - if (ConstraintExprs.empty()) { + if (AssociatedConstraints.empty()) { Satisfaction.IsSatisfied = true; return false; } @@ -591,10 +592,12 @@ static bool CheckConstraintSatisfaction( if (Inst.isInvalid()) return true; - for (const Expr *ConstraintExpr : ConstraintExprs) { + for (const AssociatedConstraint &AC : AssociatedConstraints) { + Sema::ArgumentPackSubstitutionIndexRAII _(S, + AC.ArgumentPackSubstitutionIndex); ExprResult Res = calculateConstraintSatisfaction( S, Template, TemplateIDRange.getBegin(), TemplateArgsLists, - ConstraintExpr, Satisfaction); + AC.ConstraintExpr, Satisfaction); if (Res.isInvalid()) return true; @@ -602,7 +605,8 @@ static bool CheckConstraintSatisfaction( if (!Satisfaction.IsSatisfied) { // Backfill the 'converted' list with nulls so we can keep the Converted // and unconverted lists in sync. - Converted.append(ConstraintExprs.size() - Converted.size(), nullptr); + Converted.append(AssociatedConstraints.size() - Converted.size(), + nullptr); // [temp.constr.op] p2 // [...] To determine if a conjunction is satisfied, the satisfaction // of the first operand is checked. If that is not satisfied, the @@ -614,17 +618,18 @@ static bool CheckConstraintSatisfaction( } bool Sema::CheckConstraintSatisfaction( - const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + const NamedDecl *Template, + ArrayRef<AssociatedConstraint> AssociatedConstraints, llvm::SmallVectorImpl<Expr *> &ConvertedConstraints, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) { - if (ConstraintExprs.empty()) { + if (AssociatedConstraints.empty()) { OutSatisfaction.IsSatisfied = true; return false; } if (!Template) { return ::CheckConstraintSatisfaction( - *this, nullptr, ConstraintExprs, ConvertedConstraints, + *this, nullptr, AssociatedConstraints, ConvertedConstraints, TemplateArgsLists, TemplateIDRange, OutSatisfaction); } // Invalid templates could make their way here. Substituting them could result @@ -653,7 +658,7 @@ bool Sema::CheckConstraintSatisfaction( auto Satisfaction = std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs); - if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, + if (::CheckConstraintSatisfaction(*this, Template, AssociatedConstraints, ConvertedConstraints, TemplateArgsLists, TemplateIDRange, *Satisfaction)) { OutSatisfaction = *Satisfaction; @@ -922,8 +927,10 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, ForOverloadResolution); return CheckConstraintSatisfaction( - FD, {FD->getTrailingRequiresClause()}, *MLTAL, - SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), + FD, + AssociatedConstraint(FD->getTrailingRequiresClause(), + ArgumentPackSubstitutionIndex), + *MLTAL, SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), Satisfaction); } @@ -1098,13 +1105,13 @@ bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) { assert(FD->getDescribedFunctionTemplate() && "Non-function templates don't need to be checked"); - SmallVector<const Expr *, 3> ACs; + SmallVector<AssociatedConstraint, 3> ACs; FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs); unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD); - for (const Expr *Constraint : ACs) + for (const AssociatedConstraint &AC : ACs) if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth, - Constraint)) + AC.ConstraintExpr)) return true; return false; @@ -1114,7 +1121,7 @@ bool Sema::EnsureTemplateArgumentListConstraints( TemplateDecl *TD, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange) { ConstraintSatisfaction Satisfaction; - llvm::SmallVector<const Expr *, 3> AssociatedConstraints; + llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints; TD->getAssociatedConstraints(AssociatedConstraints); if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgsLists, TemplateIDRange, Satisfaction)) @@ -1145,7 +1152,7 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( FunctionTemplateDecl *Template = Decl->getPrimaryTemplate(); // Note - code synthesis context for the constraints check is created // inside CheckConstraintsSatisfaction. - SmallVector<const Expr *, 3> TemplateAC; + SmallVector<AssociatedConstraint, 3> TemplateAC; Template->getAssociatedConstraints(TemplateAC); if (TemplateAC.empty()) { Satisfaction.IsSatisfied = true; @@ -1435,19 +1442,20 @@ void Sema::DiagnoseUnsatisfiedConstraint( } } -const NormalizedConstraint * -Sema::getNormalizedAssociatedConstraints( - NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) { +const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints( + NamedDecl *ConstrainedDecl, + ArrayRef<AssociatedConstraint> AssociatedConstraints) { // In case the ConstrainedDecl comes from modules, it is necessary to use // the canonical decl to avoid different atomic constraints with the 'same' // declarations. ConstrainedDecl = cast<NamedDecl>(ConstrainedDecl->getCanonicalDecl()); + // FIXME: The cache should take the AssociatedConstraint's + // ArgumentPackSubstitutionIndex into consideration. auto CacheEntry = NormalizationCache.find(ConstrainedDecl); if (CacheEntry == NormalizationCache.end()) { - auto Normalized = - NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl, - AssociatedConstraints); + auto Normalized = NormalizedConstraint::fromConstraintAssociatedConstraints( + *this, ConstrainedDecl, AssociatedConstraints); CacheEntry = NormalizationCache .try_emplace(ConstrainedDecl, @@ -1462,7 +1470,7 @@ Sema::getNormalizedAssociatedConstraints( const NormalizedConstraint *clang::getNormalizedAssociatedConstraints( Sema &S, NamedDecl *ConstrainedDecl, - ArrayRef<const Expr *> AssociatedConstraints) { + ArrayRef<AssociatedConstraint> AssociatedConstraints) { return S.getNormalizedAssociatedConstraints(ConstrainedDecl, AssociatedConstraints); } @@ -1494,7 +1502,8 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N, TemplateArgumentListInfo SubstArgs; if (!Atomic.ParameterMapping) { llvm::SmallBitVector OccurringIndices(TemplateParams->size()); - S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false, + S.MarkUsedTemplateParameters(Atomic.AC.ConstraintExpr, + /*OnlyDeduced=*/false, /*Depth=*/0, OccurringIndices); TemplateArgumentLoc *TempArgs = new (S.Context) TemplateArgumentLoc[OccurringIndices.count()]; @@ -1591,14 +1600,14 @@ NormalizedConstraint &NormalizedConstraint::getRHS() const { } std::optional<NormalizedConstraint> -NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, - ArrayRef<const Expr *> E) { - assert(E.size() != 0); - auto Conjunction = fromConstraintExpr(S, D, E[0]); +NormalizedConstraint::fromConstraintAssociatedConstraints( + Sema &S, NamedDecl *D, ArrayRef<AssociatedConstraint> ACs) { + assert(ACs.size() != 0); + auto Conjunction = fromConstraintAssociatedConstraint(S, D, ACs[0]); if (!Conjunction) return std::nullopt; - for (unsigned I = 1; I < E.size(); ++I) { - auto Next = fromConstraintExpr(S, D, E[I]); + for (unsigned I = 1; I < ACs.size(); ++I) { + auto Next = fromConstraintAssociatedConstraint(S, D, ACs[I]); if (!Next) return std::nullopt; *Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction), @@ -1608,31 +1617,37 @@ NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, } std::optional<NormalizedConstraint> -NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { - assert(E != nullptr); +NormalizedConstraint::fromConstraintAssociatedConstraint( + Sema &S, NamedDecl *D, AssociatedConstraint AC) { + assert(AC.ConstraintExpr != nullptr); // C++ [temp.constr.normal]p1.1 // [...] // - The normal form of an expression (E) is the normal form of E. // [...] - E = E->IgnoreParenImpCasts(); + AC.ConstraintExpr = AC.ConstraintExpr->IgnoreParenImpCasts(); // C++2a [temp.param]p4: // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). // Fold expression is considered atomic constraints per current wording. // See http://cplusplus.github.io/concepts-ts/ts-active.html#28 - if (LogicalBinOp BO = E) { - auto LHS = fromConstraintExpr(S, D, BO.getLHS()); + if (LogicalBinOp BO = AC.ConstraintExpr) { + auto LHS = fromConstraintAssociatedConstraint( + S, D, + AssociatedConstraint(BO.getLHS(), AC.ArgumentPackSubstitutionIndex)); if (!LHS) return std::nullopt; - auto RHS = fromConstraintExpr(S, D, BO.getRHS()); + auto RHS = fromConstraintAssociatedConstraint( + S, D, + AssociatedConstraint(BO.getRHS(), AC.ArgumentPackSubstitutionIndex)); if (!RHS) return std::nullopt; return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS), BO.isAnd() ? CCK_Conjunction : CCK_Disjunction); - } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) { + } else if (auto *CSE = + dyn_cast<const ConceptSpecializationExpr>(AC.ConstraintExpr)) { const NormalizedConstraint *SubNF; { Sema::InstantiatingTemplate Inst( @@ -1651,8 +1666,9 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { // expression, the program is ill-formed; no diagnostic is required. // [...] ConceptDecl *CD = CSE->getNamedConcept(); - SubNF = S.getNormalizedAssociatedConstraints(CD, - {CD->getConstraintExpr()}); + SubNF = S.getNormalizedAssociatedConstraints( + CD, AssociatedConstraint(CD->getConstraintExpr(), + AC.ArgumentPackSubstitutionIndex)); if (!SubNF) return std::nullopt; } @@ -1664,7 +1680,7 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { return std::nullopt; return New; - } else if (auto *FE = dyn_cast<const CXXFoldExpr>(E); + } else if (auto *FE = dyn_cast<const CXXFoldExpr>(AC.ConstraintExpr); FE && S.getLangOpts().CPlusPlus26 && (FE->getOperator() == BinaryOperatorKind::BO_LAnd || FE->getOperator() == BinaryOperatorKind::BO_LOr)) { @@ -1677,8 +1693,12 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { : FoldExpandedConstraint::FoldOperatorKind::Or; if (FE->getInit()) { - auto LHS = fromConstraintExpr(S, D, FE->getLHS()); - auto RHS = fromConstraintExpr(S, D, FE->getRHS()); + auto LHS = fromConstraintAssociatedConstraint( + S, D, + AssociatedConstraint(FE->getLHS(), AC.ArgumentPackSubstitutionIndex)); + auto RHS = fromConstraintAssociatedConstraint( + S, D, + AssociatedConstraint(FE->getRHS(), AC.ArgumentPackSubstitutionIndex)); if (!LHS || !RHS) return std::nullopt; @@ -1694,14 +1714,17 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction : CCK_Disjunction); } - auto Sub = fromConstraintExpr(S, D, FE->getPattern()); + auto Sub = fromConstraintAssociatedConstraint( + S, D, + AssociatedConstraint(FE->getPattern(), + AC.ArgumentPackSubstitutionIndex)); if (!Sub) return std::nullopt; return NormalizedConstraint{new (S.Context) FoldExpandedConstraint{ Kind, std::move(*Sub), FE->getPattern()}}; } - return NormalizedConstraint{new (S.Context) AtomicConstraint(E, D)}; + return NormalizedConstraint{new (S.Context) AtomicConstraint(AC, D)}; } bool FoldExpandedConstraint::AreCompatibleForSubsumption( @@ -1792,9 +1815,9 @@ NormalForm clang::makeDNF(const NormalizedConstraint &Normalized) { } bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, - MutableArrayRef<const Expr *> AC1, + MutableArrayRef<AssociatedConstraint> AC1, NamedDecl *D2, - MutableArrayRef<const Expr *> AC2, + MutableArrayRef<AssociatedConstraint> AC2, bool &Result) { #ifndef NDEBUG if (const auto *FD1 = dyn_cast<FunctionDecl>(D1)) { @@ -1832,13 +1855,15 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) { if (Depth2 > Depth1) { - AC1[I] = AdjustConstraintDepth(*this, Depth2 - Depth1) - .TransformExpr(const_cast<Expr *>(AC1[I])) - .get(); + AC1[I].ConstraintExpr = + AdjustConstraintDepth(*this, Depth2 - Depth1) + .TransformExpr(const_cast<Expr *>(AC1[I].ConstraintExpr)) + .get(); } else if (Depth1 > Depth2) { - AC2[I] = AdjustConstraintDepth(*this, Depth1 - Depth2) - .TransformExpr(const_cast<Expr *>(AC2[I])) - .get(); + AC2[I].ConstraintExpr = + AdjustConstraintDepth(*this, Depth1 - Depth2) + .TransformExpr(const_cast<Expr *>(AC2[I].ConstraintExpr)) + .get(); } } @@ -1852,8 +1877,9 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, return false; } -bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, - ArrayRef<const Expr *> AC1, NamedDecl *D2, ArrayRef<const Expr *> AC2) { +bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic( + NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1, NamedDecl *D2, + ArrayRef<AssociatedConstraint> AC2) { if (isSFINAEContext()) // No need to work here because our notes would be discarded. return false; @@ -1867,26 +1893,29 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, }; const Expr *AmbiguousAtomic1 = nullptr, *AmbiguousAtomic2 = nullptr; - auto IdenticalExprEvaluator = - [&] (const AtomicConstraint &A, const AtomicConstraint &B) { - if (!A.hasMatchingParameterMapping(Context, B)) - return false; - const Expr *EA = A.ConstraintExpr, *EB = B.ConstraintExpr; - if (EA == EB) - return true; - - // Not the same source level expression - are the expressions - // identical? - llvm::FoldingSetNodeID IDA, IDB; - EA->Profile(IDA, Context, /*Canonical=*/true); - EB->Profile(IDB, Context, /*Canonical=*/true); - if (IDA != IDB) - return false; - - AmbiguousAtomic1 = EA; - AmbiguousAtomic2 = EB; - return true; - }; + auto IdenticalExprEvaluator = [&](const AtomicConstraint &A, + const AtomicConstraint &B) { + if (A.AC.ArgumentPackSubstitutionIndex != + B.AC.ArgumentPackSubstitutionIndex) + return false; + if (!A.hasMatchingParameterMapping(Context, B)) + return false; + const Expr *EA = A.AC.ConstraintExpr, *EB = B.AC.ConstraintExpr; + if (EA == EB) + return true; + + // Not the same source level expression - are the expressions + // identical? + llvm::FoldingSetNodeID IDA, IDB; + EA->Profile(IDA, Context, /*Canonical=*/true); + EB->Profile(IDB, Context, /*Canonical=*/true); + if (IDA != IDB) + return false; + + AmbiguousAtomic1 = EA; + AmbiguousAtomic2 = EB; + return true; + }; { // The subsumption checks might cause diagnostics diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 043e82414c052..16201a749a834 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -19133,8 +19133,11 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record, AnotherMethodIsMoreConstrained = true; break; } - if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, OrigMethod, - {Constraints}, + AssociatedConstraint Other(OtherConstraints, + /*ArgumentPackSubstitutionIndex=*/-1); + AssociatedConstraint Orig(Constraints, + /*ArgumentPackSubstitutionIndex=*/-1); + if (S.IsAtLeastAsConstrained(OtherMethod, {Other}, OrigMethod, {Orig}, AnotherMethodIsMoreConstrained)) { // There was an error with the constraints comparison. Exit the loop // and don't consider this function eligible. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 856b505e92214..e8a8bbd403633 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -9572,8 +9572,11 @@ concepts::NestedRequirement * Sema::BuildNestedRequirement(Expr *Constraint) { ConstraintSatisfaction Satisfaction; if (!Constraint->isInstantiationDependent() && - CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{}, - Constraint->getSourceRange(), Satisfaction)) + CheckConstraintSatisfaction( + nullptr, + AssociatedConstraint(Constraint, + /*ArgumentPackSubstitutionIndex=*/-1), + /*TemplateArgs=*/{}, Constraint->getSourceRange(), Satisfaction)) return nullptr; return new (Context) concepts::NestedRequirement(Context, Constraint, Satisfaction); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 6d8006b35dcf4..1802f8f4e1f91 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -11280,12 +11280,12 @@ MaybeDiagnoseAmbiguousConstraints(Sema &S, ArrayRef<OverloadCandidate> Cands) { // source-level construct. This behavior is quite confusing and we should try // to help the user figure out what happened. - SmallVector<const Expr *, 3> FirstAC, SecondAC; + SmallVector<AssociatedConstraint, 3> FirstAC, SecondAC; FunctionDecl *FirstCand = nullptr, *SecondCand = nullptr; for (auto I = Cands.begin(), E = Cands.end(); I != E; ++I) { if (!I->Function) continue; - SmallVector<const Expr *, 3> AC; + SmallVector<AssociatedConstraint, 3> AC; if (auto *Template = I->Function->getPrimaryTemplate()) Template->getAssociatedConstraints(AC); else diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3c83721a481b7..1211b9e708758 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1221,7 +1221,8 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, /*NamedConcept=*/NamedConcept, /*ArgsWritten=*/ArgsAsWritten); ConstrainedParameter->setTypeConstraint(CL, - ImmediatelyDeclaredConstraint.get()); + ImmediatelyDeclaredConstraint.get(), + /*ArgumentPackSubstitutionIndex=*/-1); return false; } @@ -4060,7 +4061,7 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { } S.NoteTemplateLocation(*Template); - SmallVector<const Expr *, 3> PartialAC, TemplateAC; + SmallVector<AssociatedConstraint, 3> PartialAC, TemplateAC; Template->getAssociatedConstraints(TemplateAC); Partial->getAssociatedConstraints(PartialAC); S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Partial, PartialAC, Template, @@ -4602,7 +4603,10 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, if (!AreArgsDependent && CheckConstraintSatisfaction( - NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL, + NamedConcept, + AssociatedConstraint(NamedConcept->getConstraintExpr(), + /*ArgumentPackSubstitutionIndex=*/-1), + MLTAL, SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(), TemplateArgs->getRAngleLoc()), Satisfaction)) @@ -7429,7 +7433,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, // C++20[temp.func.order]p2 // [...] If both deductions succeed, the partial ordering selects the // more constrained template (if one exists) as determined below. - SmallVector<const Expr *, 3> ParamsAC, TemplateAC; + SmallVector<AssociatedConstraint, 3> ParamsAC, TemplateAC; Params->getAssociatedConstraints(ParamsAC); // C++20[temp.arg.template]p3 // [...] In this comparison, if P is unconstrained, the constraints on A diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 410b5a2c83e8d..91a887f395869 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3245,7 +3245,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> SugaredDeducedArgs, ArrayRef<TemplateArgument> CanonicalDeducedArgs, TemplateDeductionInfo &Info) { - llvm::SmallVector<const Expr *, 3> AssociatedConstraints; + llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); std::optional<ArrayRef<TemplateArgument>> Innermost; @@ -5235,9 +5235,11 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, ImplicitConceptSpecializationDecl::Create( S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(), CTAI.CanonicalConverted)); - if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, - MLTAL, TypeLoc.getLocalSourceRange(), - Satisfaction)) + if (S.CheckConstraintSatisfaction( + Concept, + AssociatedConstraint(Concept->getConstraintExpr(), + /*ArgumentPackSubstitutionIndex=*/-1), + MLTAL, TypeLoc.getLocalSourceRange(), Satisfaction)) return true; if (!Satisfaction.IsSatisfied) { std::string Buf; @@ -6111,7 +6113,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( !Context.hasSameType(FD1->getReturnType(), FD2->getReturnType())) return nullptr; - llvm::SmallVector<const Expr *, 3> AC1, AC2; + llvm::SmallVector<AssociatedConstraint, 3> AC1, AC2; FT1->getAssociatedConstraints(AC1); FT2->getAssociatedConstraints(AC2); bool AtLeastAsConstrained1, AtLeastAsConstrained2; @@ -6216,7 +6218,7 @@ FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1, if (FunctionDecl *P = FD2->getTemplateInstantiationPattern(false)) F2 = P; - llvm::SmallVector<const Expr *, 1> AC1, AC2; + llvm::SmallVector<AssociatedConstraint, 1> AC1, AC2; F1->getAssociatedConstraints(AC1); F2->getAssociatedConstraints(AC2); bool AtLeastAsConstrained1, AtLeastAsConstrained2; @@ -6448,7 +6450,7 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1, if (!TemplateArgumentListAreEqual(S.getASTContext())(P1, P2)) return nullptr; - llvm::SmallVector<const Expr *, 3> AC1, AC2; + llvm::SmallVector<AssociatedConstraint, 3> AC1, AC2; P1->getAssociatedConstraints(AC1); P2->getAssociatedConstraints(AC2); bool AtLeastAsConstrained1, AtLeastAsConstrained2; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index ec9a2fb1e9542..9f5ca9dca8e89 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2876,8 +2876,11 @@ TemplateInstantiator::TransformNestedRequirement( return nullptr; llvm::SmallVector<Expr *> Result; if (!SemaRef.CheckConstraintSatisfaction( - nullptr, {Req->getConstraintExpr()}, Result, TemplateArgs, - Req->getConstraintExpr()->getSourceRange(), Satisfaction) && + nullptr, + AssociatedConstraint(Req->getConstraintExpr(), + SemaRef.ArgumentPackSubstitutionIndex), + Result, TemplateArgs, Req->getConstraintExpr()->getSourceRange(), + Satisfaction) && !Result.empty()) TransConstraint = Result[0]; assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled " @@ -3159,9 +3162,12 @@ bool Sema::SubstTypeConstraint( TC->getTemplateArgsAsWritten(); if (!EvaluateConstraints) { - Inst->setTypeConstraint(TC->getConceptReference(), - TC->getImmediatelyDeclaredConstraint()); - return false; + auto Index = TC->getArgumentPackSubstitutionIndex(); + if (Index == -1) + Index = SemaRef.ArgumentPackSubstitutionIndex; + Inst->setTypeConstraint(TC->getConceptReference(), + TC->getImmediatelyDeclaredConstraint(), Index); + return false; } TemplateArgumentListInfo InstArgs; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index c3341e00bacef..77daeaee5dd1f 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2706,8 +2706,10 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { if (Record.readBool()) CR = Record.readConceptReference(); Expr *ImmediatelyDeclaredConstraint = Record.readExpr(); + int ArgumentPackSubstitutionIndex = Record.readInt(); - D->setTypeConstraint(CR, ImmediatelyDeclaredConstraint); + D->setTypeConstraint(CR, ImmediatelyDeclaredConstraint, + ArgumentPackSubstitutionIndex); if ((D->ExpandedParameterPack = Record.readInt())) D->NumExpanded = Record.readInt(); } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 7014d7d291a5d..558a6bb18e817 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -2036,6 +2036,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { if (CR) Record.AddConceptReference(CR); Record.AddStmt(TC->getImmediatelyDeclaredConstraint()); + Record.push_back(TC->getArgumentPackSubstitutionIndex()); Record.push_back(D->isExpandedParameterPack()); if (D->isExpandedParameterPack()) Record.push_back(D->getNumExpansionParameters()); diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp index 69572bea3664a..2807c29db9aaf 100644 --- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp +++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp @@ -238,4 +238,33 @@ static_assert(bar<int, float>()(123)); // expected-note@#C {{evaluated to false}} // expected-note@#same_as 2{{evaluated to false}} +template <class T, auto U> +concept same_as_v = __is_same(T, decltype(U)); // #same_as_v + +template <auto... Vs> constexpr auto baz() { + return Overloaded{[](same_as_v<Vs> auto value) { return value; }...}; // #baz +} + +static_assert(baz<1, 1.>()(123) == 123); +static_assert(baz<1, 1.>()(2.718) == 2.718); + +static_assert(baz<1, 1.>()('c')); +// expected-error@-1 {{no matching function}} + +// expected-note@#baz {{constraints not satisfied}} +// expected-note@#baz {{'same_as_v<char, 1>' evaluated to false}} +// expected-note@#same_as_v {{evaluated to false}} + +// expected-note@#baz {{constraints not satisfied}} +// expected-note@#baz {{'same_as_v<char, 1.>' evaluated to false}} +// expected-note@#same_as_v {{evaluated to false}} + +template <auto... Ts> constexpr auto bazz() { + return Overloaded{[](same_as_v<Ts> auto value) { return Ts; }...}; // #bazz +} + +static_assert(bazz<1, 2>()(1)); +// expected-error@-1 {{is ambiguous}} +// expected-note@#bazz 2{{candidate function [with value:auto = int]}} + } // namespace GH101754 diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp index daea2d62fe496..5b461d1cf4400 100644 --- a/clang/unittests/AST/SourceLocationTest.cpp +++ b/clang/unittests/AST/SourceLocationTest.cpp @@ -1094,11 +1094,11 @@ class ConceptSpecializationExprConceptReferenceRangeVerifier protected: SourceRange getRange(const VarTemplateDecl &Node) override { assert(Node.hasAssociatedConstraints()); - SmallVector<const Expr *, 3> ACs; + SmallVector<AssociatedConstraint, 3> ACs; Node.getAssociatedConstraints(ACs); - for (const Expr *Constraint : ACs) { + for (const AssociatedConstraint &AC : ACs) { if (const ConceptSpecializationExpr *CSConstraint = - dyn_cast<ConceptSpecializationExpr>(Constraint)) { + dyn_cast<ConceptSpecializationExpr>(AC.ConstraintExpr)) { return CSConstraint->getConceptReference()->getSourceRange(); } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits