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 handleReturnType(const FunctionDecl *Function, if (!TypeText) return {}; - SmallVector ExistingConstraints; + SmallVector 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 ExistingConstraints; + SmallVector 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 c3b64d84a1b1c..c4e82678949ff 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -370,6 +370,9 @@ 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. + (#GH131798) - 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/ASTContext.h b/clang/include/clang/AST/ASTContext.h index f386282890b5a..a24f30815e6b9 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1798,9 +1798,7 @@ class ASTContext : public RefCountedBase { QualType getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional PackIndex, - SubstTemplateTypeParmTypeFlag Flag = - SubstTemplateTypeParmTypeFlag::None) const; + std::optional PackIndex) const; QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, unsigned Index, bool Final, const TemplateArgument &ArgPack); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index efac36e49351e..9e7e93d98c9d1 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; + + explicit AssociatedConstraint(const Expr *ConstraintExpr, + int ArgumentPackSubstitutionIndex = -1) + : 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 &AC) const { + void + getAssociatedConstraints(SmallVectorImpl &AC) const { if (auto *TRC = getTrailingRequiresClause()) - AC.push_back(TRC); + AC.emplace_back(TRC); } /// 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..37fe0acf5d4d5 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 &AC) const; + void getAssociatedConstraints( + llvm::SmallVectorImpl &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 &AC) const; + void getAssociatedConstraints( + llvm::SmallVectorImpl &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 &AC) const { + void getAssociatedConstraints( + llvm::SmallVectorImpl &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 &AC) const { + void getAssociatedConstraints( + llvm::SmallVectorImpl &AC) const { if (Expr *E = getPlaceholderTypeConstraint()) - AC.push_back(E); + AC.emplace_back(E); } // 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 &AC) const { + void getAssociatedConstraints( + llvm::SmallVectorImpl &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 &AC) const { + void getAssociatedConstraints( + llvm::SmallVectorImpl &AC) const { TemplateParams->getAssociatedConstraints(AC); } diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 178308a24e1a0..5171555008ac9 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 988362787a452..cfd417068abb7 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; @@ -6409,8 +6397,7 @@ class SubstTemplateTypeParmType final Decl *AssociatedDecl; SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, - unsigned Index, std::optional PackIndex, - SubstTemplateTypeParmTypeFlag Flag); + unsigned Index, std::optional PackIndex); public: /// Gets the type that was substituted for the template @@ -6439,31 +6426,21 @@ 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(), getSubstitutionFlag()); + getPackIndex()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement, const Decl *AssociatedDecl, unsigned Index, - std::optional PackIndex, - SubstTemplateTypeParmTypeFlag Flag) { + std::optional 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 10eb40dc90ad4..391fd26a086f7 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -842,14 +842,11 @@ 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, SubstitutionFlag); + replacementType, associatedDecl, Index, PackIndex); }]>; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 09168218a9e36..822cae99ddae7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11351,7 +11351,6 @@ class Sema final : public SemaBase { ConceptDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, - QualType ConstrainedType, SourceLocation EllipsisLoc); bool AttachTypeConstraint(AutoTypeLoc TL, @@ -14552,13 +14551,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 ConstraintExprs, + const NamedDecl *Template, + ArrayRef AssociatedConstraints, const MultiLevelTemplateArgumentList &TemplateArgLists, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { llvm::SmallVector 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 @@ -14584,7 +14584,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 ConstraintExprs, + const NamedDecl *Template, + ArrayRef AssociatedConstraints, llvm::SmallVectorImpl &ConvertedConstraints, const MultiLevelTemplateArgumentList &TemplateArgList, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); @@ -14662,7 +14663,7 @@ class Sema final : public SemaBase { const NormalizedConstraint *getNormalizedAssociatedConstraints( const NamedDecl *ConstrainedDecl, - ArrayRef AssociatedConstraints); + ArrayRef AssociatedConstraints); /// \brief Check whether the given declaration's associated constraints are /// at least as constrained than another declaration's according to the @@ -14673,17 +14674,18 @@ class Sema final : public SemaBase { /// /// \returns true if an error occurred, false otherwise. bool IsAtLeastAsConstrained(const NamedDecl *D1, - MutableArrayRef AC1, + MutableArrayRef AC1, const NamedDecl *D2, - MutableArrayRef AC2, bool &Result); + MutableArrayRef AC2, + bool &Result); /// If D1 was not at least as constrained as D2, but would've been if a pair /// of atomic constraints involved had been declared in a concept and not /// repeated in two separate places in code. /// \returns true if such a diagnostic was emitted, false otherwise. bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic( - const NamedDecl *D1, ArrayRef AC1, const NamedDecl *D2, - ArrayRef AC2); + const NamedDecl *D1, ArrayRef AC1, + const NamedDecl *D2, ArrayRef 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 cbb3720c30ee2..648a9c51ae6c1 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -114,7 +114,8 @@ struct NormalizedConstraint { private: static std::optional - fromConstraintExprs(Sema &S, const NamedDecl *D, ArrayRef E); + fromAssociatedConstraints(Sema &S, const NamedDecl *D, + ArrayRef ACs); static std::optional fromConstraintExpr(Sema &S, const NamedDecl *D, const Expr *E); }; @@ -138,7 +139,7 @@ struct alignas(ConstraintAlignment) FoldExpandedConstraint { const NormalizedConstraint *getNormalizedAssociatedConstraints( Sema &S, const NamedDecl *ConstrainedDecl, - ArrayRef AssociatedConstraints); + ArrayRef AssociatedConstraints); /// \brief SubsumptionChecker establishes subsumption /// between two set of constraints. @@ -149,8 +150,10 @@ class SubsumptionChecker { SubsumptionChecker(Sema &SemaRef, SubsumptionCallable Callable = {}); - std::optional Subsumes(const NamedDecl *DP, ArrayRef P, - const NamedDecl *DQ, ArrayRef Q); + std::optional Subsumes(const NamedDecl *DP, + ArrayRef P, + const NamedDecl *DQ, + ArrayRef Q); bool Subsumes(const NormalizedConstraint *P, const NormalizedConstraint *Q); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 089d01839e1cf..552b5823add36 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5447,11 +5447,10 @@ QualType ASTContext::getHLSLAttributedResourceType( /// Retrieve a substitution-result type. QualType ASTContext::getSubstTemplateTypeParmType( QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional PackIndex, - SubstTemplateTypeParmTypeFlag Flag) const { + std::optional PackIndex) const { llvm::FoldingSetNodeID ID; SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index, - PackIndex, Flag); + PackIndex); void *InsertPos = nullptr; SubstTemplateTypeParmType *SubstParm = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -5461,7 +5460,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 9a84e402e3d69..81acb013b0f7d 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( @@ -5975,7 +5975,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..8f6916aeb4bd6 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 &AC) const { +void TemplateParameterList::getAssociatedConstraints( + llvm::SmallVectorImpl &ACs) const { if (HasConstrainedParameters) for (const NamedDecl *Param : *this) { if (const auto *TTP = dyn_cast(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(Param)) { if (const Expr *E = NTTP->getPlaceholderTypeConstraint()) - AC.push_back(E); + ACs.emplace_back(E); } } if (HasRequiresClause) - AC.push_back(getRequiresClause()); + ACs.emplace_back(getRequiresClause()); } bool TemplateParameterList::hasAssociatedConstraints() const { @@ -286,12 +287,12 @@ TemplateDecl::TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, void TemplateDecl::anchor() {} -void TemplateDecl:: -getAssociatedConstraints(llvm::SmallVectorImpl &AC) const { - TemplateParams->getAssociatedConstraints(AC); +void TemplateDecl::getAssociatedConstraints( + llvm::SmallVectorImpl &ACs) const { + TemplateParams->getAssociatedConstraints(ACs); if (auto *FD = dyn_cast_or_null(getTemplatedDecl())) if (const Expr *TRC = FD->getTrailingRequiresClause()) - AC.push_back(TRC); + ACs.emplace_back(TRC); } 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(Loc, ImmediatelyDeclaredConstraint); + new (getTrailingObjects()) TypeConstraint( + Loc, ImmediatelyDeclaredConstraint, ArgumentPackSubstitutionIndex); TypeConstraintInitialized = true; } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 9fda02b430e48..667ffc0e599a6 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4263,7 +4263,7 @@ static const TemplateTypeParmDecl *getReplacedParameter(Decl *D, SubstTemplateTypeParmType::SubstTemplateTypeParmType( QualType Replacement, Decl *AssociatedDecl, unsigned Index, - std::optional PackIndex, SubstTemplateTypeParmTypeFlag Flag) + std::optional PackIndex) : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(), Replacement->getDependence()), AssociatedDecl(AssociatedDecl) { @@ -4274,10 +4274,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/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 54cafc2010f09..44a49a6e3148e 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 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 + static SmallVector constraintsForTemplatedEntity(DeclContext *DC) { - SmallVector Result; + SmallVector 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 ebee5994bfed2..e6117f97ad1f4 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -567,11 +567,12 @@ static ExprResult calculateConstraintSatisfaction( } static bool CheckConstraintSatisfaction( - Sema &S, const NamedDecl *Template, ArrayRef ConstraintExprs, + Sema &S, const NamedDecl *Template, + ArrayRef AssociatedConstraints, llvm::SmallVectorImpl &Converted, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { - if (ConstraintExprs.empty()) { + if (AssociatedConstraints.empty()) { Satisfaction.IsSatisfied = true; return false; } @@ -592,10 +593,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; @@ -603,7 +606,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 @@ -615,17 +619,18 @@ static bool CheckConstraintSatisfaction( } bool Sema::CheckConstraintSatisfaction( - const NamedDecl *Template, ArrayRef ConstraintExprs, + const NamedDecl *Template, + ArrayRef AssociatedConstraints, llvm::SmallVectorImpl &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 @@ -654,7 +659,7 @@ bool Sema::CheckConstraintSatisfaction( auto Satisfaction = std::make_unique(Template, FlattenedArgs); - if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, + if (::CheckConstraintSatisfaction(*this, Template, AssociatedConstraints, ConvertedConstraints, TemplateArgsLists, TemplateIDRange, *Satisfaction)) { OutSatisfaction = *Satisfaction; @@ -923,8 +928,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); } @@ -1099,13 +1106,13 @@ bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) { assert(FD->getDescribedFunctionTemplate() && "Non-function templates don't need to be checked"); - SmallVector ACs; + SmallVector 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; @@ -1115,7 +1122,7 @@ bool Sema::EnsureTemplateArgumentListConstraints( TemplateDecl *TD, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange) { ConstraintSatisfaction Satisfaction; - llvm::SmallVector AssociatedConstraints; + llvm::SmallVector AssociatedConstraints; TD->getAssociatedConstraints(AssociatedConstraints); if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgsLists, TemplateIDRange, Satisfaction)) @@ -1146,7 +1153,7 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( FunctionTemplateDecl *Template = Decl->getPrimaryTemplate(); // Note - code synthesis context for the constraints check is created // inside CheckConstraintsSatisfaction. - SmallVector TemplateAC; + SmallVector TemplateAC; Template->getAssociatedConstraints(TemplateAC); if (TemplateAC.empty()) { Satisfaction.IsSatisfied = true; @@ -1438,7 +1445,7 @@ void Sema::DiagnoseUnsatisfiedConstraint( const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints( const NamedDecl *ConstrainedDecl, - ArrayRef AssociatedConstraints) { + ArrayRef 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. @@ -1446,9 +1453,8 @@ const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints( auto CacheEntry = NormalizationCache.find(ConstrainedDecl); if (CacheEntry == NormalizationCache.end()) { - auto Normalized = - NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl, - AssociatedConstraints); + auto Normalized = NormalizedConstraint::fromAssociatedConstraints( + *this, ConstrainedDecl, AssociatedConstraints); CacheEntry = NormalizationCache .try_emplace(ConstrainedDecl, @@ -1463,7 +1469,7 @@ const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints( const NormalizedConstraint *clang::getNormalizedAssociatedConstraints( Sema &S, const NamedDecl *ConstrainedDecl, - ArrayRef AssociatedConstraints) { + ArrayRef AssociatedConstraints) { return S.getNormalizedAssociatedConstraints(ConstrainedDecl, AssociatedConstraints); } @@ -1593,14 +1599,14 @@ NormalizedConstraint &NormalizedConstraint::getRHS() const { } std::optional -NormalizedConstraint::fromConstraintExprs(Sema &S, const NamedDecl *D, - ArrayRef E) { - assert(E.size() != 0); - auto Conjunction = fromConstraintExpr(S, D, E[0]); +NormalizedConstraint::fromAssociatedConstraints( + Sema &S, const NamedDecl *D, ArrayRef ACs) { + assert(ACs.size() != 0); + auto Conjunction = fromConstraintExpr(S, D, ACs[0].ConstraintExpr); 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 = fromConstraintExpr(S, D, ACs[I].ConstraintExpr); if (!Next) return std::nullopt; *Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction), @@ -1655,8 +1661,8 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, const NamedDecl *D, // 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())); if (!SubNF) return std::nullopt; } @@ -1731,9 +1737,9 @@ bool FoldExpandedConstraint::AreCompatibleForSubsumption( } bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1, - MutableArrayRef AC1, + MutableArrayRef AC1, const NamedDecl *D2, - MutableArrayRef AC2, + MutableArrayRef AC2, bool &Result) { #ifndef NDEBUG if (const auto *FD1 = dyn_cast(D1)) { @@ -1771,13 +1777,15 @@ bool Sema::IsAtLeastAsConstrained(const 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(AC1[I])) - .get(); + AC1[I].ConstraintExpr = + AdjustConstraintDepth(*this, Depth2 - Depth1) + .TransformExpr(const_cast(AC1[I].ConstraintExpr)) + .get(); } else if (Depth1 > Depth2) { - AC2[I] = AdjustConstraintDepth(*this, Depth1 - Depth2) - .TransformExpr(const_cast(AC2[I])) - .get(); + AC2[I].ConstraintExpr = + AdjustConstraintDepth(*this, Depth1 - Depth2) + .TransformExpr(const_cast(AC2[I].ConstraintExpr)) + .get(); } } @@ -1793,9 +1801,8 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1, } bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic( - const NamedDecl *D1, ArrayRef AC1, const NamedDecl *D2, - ArrayRef AC2) { - + const NamedDecl *D1, ArrayRef AC1, + const NamedDecl *D2, ArrayRef AC2) { if (isSFINAEContext()) // No need to work here because our notes would be discarded. return false; @@ -2106,10 +2113,9 @@ void SubsumptionChecker::AddUniqueClauseToFormula(Formula &F, Clause C) { F.push_back(C); } -std::optional SubsumptionChecker::Subsumes(const NamedDecl *DP, - ArrayRef P, - const NamedDecl *DQ, - ArrayRef Q) { +std::optional SubsumptionChecker::Subsumes( + const NamedDecl *DP, ArrayRef P, const NamedDecl *DQ, + ArrayRef Q) { const NormalizedConstraint *PNormalized = getNormalizedAssociatedConstraints(SemaRef, DP, P); if (!PNormalized) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2246f0f1b3121..bbefbbf294dd1 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -19130,8 +19130,9 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record, AnotherMethodIsMoreConstrained = true; break; } - if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, OrigMethod, - {Constraints}, + AssociatedConstraint Other(OtherConstraints); + AssociatedConstraint Orig(Constraints); + 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 19fd51134d160..fa492bc124abd 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -9551,7 +9551,8 @@ concepts::NestedRequirement * Sema::BuildNestedRequirement(Expr *Constraint) { ConstraintSatisfaction Satisfaction; if (!Constraint->isInstantiationDependent() && - CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{}, + CheckConstraintSatisfaction(nullptr, AssociatedConstraint(Constraint), + /*TemplateArgs=*/{}, Constraint->getSourceRange(), Satisfaction)) return nullptr; return new (Context) concepts::NestedRequirement(Context, Constraint, 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 Cands) { // source-level construct. This behavior is quite confusing and we should try // to help the user figure out what happened. - SmallVector FirstAC, SecondAC; + SmallVector FirstAC, SecondAC; FunctionDecl *FirstCand = nullptr, *SecondCand = nullptr; for (auto I = Cands.begin(), E = Cands.end(); I != E; ++I) { if (!I->Function) continue; - SmallVector AC; + SmallVector 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 de2b1fdbc44e2..eace9b87a5bfe 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(USD) : CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, - ConstrainedParameter, Context.getTypeDeclType(ConstrainedParameter), - EllipsisLoc); + ConstrainedParameter, EllipsisLoc); } template @@ -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, 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, @@ -1223,7 +1221,8 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, /*NamedConcept=*/NamedConcept, /*ArgsWritten=*/ArgsAsWritten); ConstrainedParameter->setTypeConstraint(CL, - ImmediatelyDeclaredConstraint.get()); + ImmediatelyDeclaredConstraint.get(), + /*ArgumentPackSubstitutionIndex=*/-1); return false; } @@ -4062,7 +4061,7 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { } S.NoteTemplateLocation(*Template); - SmallVector PartialAC, TemplateAC; + SmallVector PartialAC, TemplateAC; Template->getAssociatedConstraints(TemplateAC); Partial->getAssociatedConstraints(PartialAC); S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Partial, PartialAC, Template, @@ -4604,7 +4603,8 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, if (!AreArgsDependent && CheckConstraintSatisfaction( - NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL, + NamedConcept, AssociatedConstraint(NamedConcept->getConstraintExpr()), + MLTAL, SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(), TemplateArgs->getRAngleLoc()), Satisfaction)) @@ -7432,7 +7432,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 ParamsAC, TemplateAC; + SmallVector 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 b39eb8fd5512e..9969f1762fe36 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3255,7 +3255,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, ArrayRef SugaredDeducedArgs, ArrayRef CanonicalDeducedArgs, TemplateDeductionInfo &Info) { - llvm::SmallVector AssociatedConstraints; + llvm::SmallVector AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); std::optional> Innermost; @@ -5245,9 +5245,9 @@ 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()), MLTAL, + TypeLoc.getLocalSourceRange(), Satisfaction)) return true; if (!Satisfaction.IsSatisfied) { std::string Buf; @@ -6121,7 +6121,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( !Context.hasSameType(FD1->getReturnType(), FD2->getReturnType())) return nullptr; - llvm::SmallVector AC1, AC2; + llvm::SmallVector AC1, AC2; FT1->getAssociatedConstraints(AC1); FT2->getAssociatedConstraints(AC2); bool AtLeastAsConstrained1, AtLeastAsConstrained2; @@ -6226,7 +6226,7 @@ FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1, if (FunctionDecl *P = FD2->getTemplateInstantiationPattern(false)) F2 = P; - llvm::SmallVector AC1, AC2; + llvm::SmallVector AC1, AC2; F1->getAssociatedConstraints(AC1); F2->getAssociatedConstraints(AC2); bool AtLeastAsConstrained1, AtLeastAsConstrained2; @@ -6458,7 +6458,7 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1, if (!TemplateArgumentListAreEqual(S.getASTContext())(P1, P2)) return nullptr; - llvm::SmallVector AC1, AC2; + llvm::SmallVector 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 00dcadb41e8fb..9f5ca9dca8e89 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1717,24 +1717,6 @@ namespace { SubstTemplateTypeParmPackTypeLoc TL, bool SuppressObjCLifetime); - QualType - TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, - SubstTemplateTypeParmTypeLoc TL) { - const SubstTemplateTypeParmType *Type = TL.getTypePtr(); - if (Type->getSubstitutionFlag() != - SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace) - 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()); - - return inherited::TransformSubstTemplateTypeParmType(TLB, TL); - } - CXXRecordDecl::LambdaDependencyKind ComputeLambdaDependency(LambdaScopeInfo *LSI) { if (auto TypeAlias = @@ -2894,8 +2876,11 @@ TemplateInstantiator::TransformNestedRequirement( return nullptr; llvm::SmallVector 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 " @@ -3169,68 +3154,6 @@ namespace { } // namespace -namespace { - -struct ExpandPackedTypeConstraints - : TreeTransform { - - using inherited = TreeTransform; - - const MultiLevelTemplateArgumentList &TemplateArgs; - - ExpandPackedTypeConstraints( - Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs) - : inherited(SemaRef), TemplateArgs(TemplateArgs) {} - - using inherited::TransformTemplateTypeParmType; - - QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL, bool) { - const TemplateTypeParmType *T = TL.getTypePtr(); - if (!T->isParameterPack()) { - TemplateTypeParmTypeLoc NewTL = - TLB.push(TL.getType()); - NewTL.setNameLoc(TL.getNameLoc()); - return TL.getType(); - } - - 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(), PackIndex, - SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace); - SubstTemplateTypeParmTypeLoc NewTL = - TLB.push(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(TL.getType()); - TypeLoc.setNameLoc(TL.getNameLoc()); - return TypeLoc.getType(); - } - return inherited::TransformSubstTemplateTypeParmType(TLB, TL); - } - - bool SubstTemplateArguments(ArrayRef Args, - TemplateArgumentListInfo &Out) { - return inherited::TransformTemplateArguments(Args.begin(), Args.end(), Out); - } -}; - -} // namespace - bool Sema::SubstTypeConstraint( TemplateTypeParmDecl *Inst, const TypeConstraint *TC, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -3239,61 +3162,11 @@ 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 void foo() { - // bar([](C 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. - // - // 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, TemplateArgs) - .SubstTemplateArguments(TemplArgInfo->arguments(), InstArgs)) - return true; - - // The type of the original parameter. - auto *ConstraintExpr = TC->getImmediatelyDeclaredConstraint(); - QualType ConstrainedType; - - if (auto *FE = dyn_cast(ConstraintExpr)) { - assert(FE->getLHS()); - ConstraintExpr = FE->getLHS(); - } - auto *CSE = cast(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(TC->getImmediatelyDeclaredConstraint()) - ->getEllipsisLoc() - : SourceLocation()); - } + auto Index = TC->getArgumentPackSubstitutionIndex(); + if (Index == -1) + Index = SemaRef.ArgumentPackSubstitutionIndex; Inst->setTypeConstraint(TC->getConceptReference(), - TC->getImmediatelyDeclaredConstraint()); + TC->getImmediatelyDeclaredConstraint(), Index); return false; } @@ -3310,7 +3183,6 @@ bool Sema::SubstTypeConstraint( TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), TC->getNamedConcept(), /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, Inst, - Context.getTypeDeclType(Inst), Inst->isParameterPack() ? cast(TC->getImmediatelyDeclaredConstraint()) ->getEllipsisLoc() diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 776d6e55acc18..2df961a48c7c3 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3052,9 +3052,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 @@ -3091,9 +3089,7 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, /*FoundDecl=*/ USD ? cast(USD) : CD, TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, - InventedTemplateParam, - S.Context.getTypeDeclType(InventedTemplateParam), - D.getEllipsisLoc()); + InventedTemplateParam, D.getEllipsisLoc()); } } } 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 f377c145a4204..b896a04a0b14b 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/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; - + template using B = A; }; diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp index 69572bea3664a..106da7d0e2663 100644 --- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp +++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp @@ -238,4 +238,51 @@ static_assert(bar()(123)); // expected-note@#C {{evaluated to false}} // expected-note@#same_as 2{{evaluated to false}} +template +concept same_as_v = __is_same(T, decltype(U)); // #same_as_v + +template constexpr auto baz() { + return Overloaded{[](same_as_v 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' evaluated to false}} +// expected-note@#same_as_v {{evaluated to false}} + +// expected-note@#baz {{constraints not satisfied}} +// expected-note@#baz {{'same_as_v' evaluated to false}} +// expected-note@#same_as_v {{evaluated to false}} + +template constexpr auto bazz() { + return Overloaded{[](same_as_v 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 + +namespace GH131798 { + template + struct tuple { T0 elem0; }; + + template + concept C = true; + + template + struct Foo {}; + + template + constexpr tuple fs{[] (C> auto) {}...}; + + int main() { + fs<0>.elem0(1); + } +} // namspace GH131798 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 ACs; + SmallVector ACs; Node.getAssociatedConstraints(ACs); - for (const Expr *Constraint : ACs) { + for (const AssociatedConstraint &AC : ACs) { if (const ConceptSpecializationExpr *CSConstraint = - dyn_cast(Constraint)) { + dyn_cast(AC.ConstraintExpr)) { return CSConstraint->getConceptReference()->getSourceRange(); } }