diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index cef93e25f1e7d..a4ca1e7be59c1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -642,6 +642,7 @@ Bug Fixes to C++ Support - Concepts appearing in the require-clause of a member function no longer have access to non-public members of that class, or to a current class object. (#GH115838) (#GH194803) (#GH197067) - We no longer caches invalid variable specializations. (#GH132592) +- Fix a regression in the checking of constraints involving fold expressions. (#GH199569) - Fixed an incorrect template argument deduction when matching packs of template template parameters when one of its parameters is also a pack. (#GH181166) - Clang no longer errors on overloads with different ref-qualifiers and constraints. (#GH120812) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e71794b2d92c9..aadbac9a51026 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -13570,7 +13570,7 @@ class Sema final : public SemaBase { bool SubstTemplateArgumentsInParameterMapping( ArrayRef Args, SourceLocation BaseLoc, const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateArgumentListInfo &Out); + TemplateArgumentListInfo &Out, UnsignedOrNone ExpandedIndex); /// Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index ea03c3f408986..9fc8a3f3350c7 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -481,6 +481,7 @@ class ConstraintSatisfactionChecker { UnsignedOrNone PackSubstitutionIndex; ConstraintSatisfaction &Satisfaction; bool BuildExpression; + bool RemovePacksForFoldExpr = false; // The closest concept declaration when evaluating atomic constraints. ConceptDecl *ParentConcept = nullptr; @@ -538,10 +539,12 @@ class ConstraintSatisfactionChecker { SourceLocation TemplateNameLoc, UnsignedOrNone PackSubstitutionIndex, ConstraintSatisfaction &Satisfaction, - bool BuildExpression) + bool BuildExpression, + bool RemovePacksForFoldExpr) : S(SemaRef), Template(Template), TemplateNameLoc(TemplateNameLoc), PackSubstitutionIndex(PackSubstitutionIndex), - Satisfaction(Satisfaction), BuildExpression(BuildExpression) {} + Satisfaction(Satisfaction), BuildExpression(BuildExpression), + RemovePacksForFoldExpr(RemovePacksForFoldExpr) {} ExprResult Evaluate(const NormalizedConstraint &Constraint, const MultiLevelTemplateArgumentList &MLTAL); @@ -669,7 +672,8 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( if (S.SubstTemplateArgumentsInParameterMapping( Constraint.getParameterMapping(), Constraint.getBeginLoc(), MLTAL, - SubstArgs)) { + SubstArgs, + RemovePacksForFoldExpr ? PackSubstitutionIndex : std::nullopt)) { Satisfaction.IsSatisfied = false; return std::nullopt; } @@ -897,13 +901,15 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( } for (unsigned I = 0; I < *NumExpansions; I++) { - Sema::ArgPackSubstIndexRAII SubstIndex(S, I); + Satisfaction.IsSatisfied = false; Satisfaction.ContainsErrors = false; + ExprResult Expr = ConstraintSatisfactionChecker(S, Template, TemplateNameLoc, UnsignedOrNone(I), Satisfaction, - /*BuildExpression=*/false) + /*BuildExpression=*/false, + /*RemovePacksForFoldExpr=*/true) .Evaluate(Constraint.getNormalizedPattern(), *SubstitutedArgs); if (BuildExpression) { if (Out.isUnset() || !Expr.isUsable()) @@ -1230,7 +1236,8 @@ static bool CheckConstraintSatisfaction( ExprResult Res = ConstraintSatisfactionChecker( S, Template, TemplateIDRange.getBegin(), S.ArgPackSubstIndex, Satisfaction, - /*BuildExpression=*/ConvertedExpr != nullptr) + /*BuildExpression=*/ConvertedExpr != nullptr, + /*RemovePacksForFoldExpr=*/false) .Evaluate(*C, TemplateArgsLists); if (Res.isInvalid()) @@ -2186,8 +2193,9 @@ bool SubstituteParameterMappings::substitute( TemplateArgumentListInfo SubstArgs; llvm::SaveAndRestore DoNotCacheDependentArgs(SemaRef.CurrentCachedTemplateArgs, nullptr); - if (SemaRef.SubstTemplateArgumentsInParameterMapping( - N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs)) + if (SemaRef.SubstTemplateArgumentsInParameterMapping(N.getParameterMapping(), + N.getBeginLoc(), *MLTAL, + SubstArgs, std::nullopt)) return true; Sema::CheckTemplateArgumentInfo CTAI; auto *TD = @@ -2259,7 +2267,8 @@ bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) { const ASTTemplateArgumentListInfo *ArgsAsWritten = CSE->getTemplateArgsAsWritten(); if (SemaRef.SubstTemplateArgumentsInParameterMapping( - ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out)) + ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out, + std::nullopt)) return true; Sema::CheckTemplateArgumentInfo CTAI; if (SemaRef.CheckTemplateArgumentList(CSE->getNamedConcept(), diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 1544fd56b82ae..c98eadbeb8e76 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5173,8 +5173,8 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, EnterExpressionEvaluationContext EECtx( S, Sema::ExpressionEvaluationContext::Unevaluated, ImplicitConceptSpecializationDecl::Create( - S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(), - CTAI.SugaredConverted)); + S.getASTContext(), Concept->getDeclContext(), + TypeLoc.getConceptNameLoc(), CTAI.SugaredConverted)); if (S.CheckConstraintSatisfaction( Concept, AssociatedConstraint(Concept->getConstraintExpr()), MLTAL, TypeLoc.getLocalSourceRange(), Satisfaction)) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index f168c99d1ac1a..cc2260d51a601 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -4397,11 +4397,12 @@ bool Sema::SubstTemplateArguments( bool Sema::SubstTemplateArgumentsInParameterMapping( ArrayRef Args, SourceLocation BaseLoc, const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateArgumentListInfo &Out) { + TemplateArgumentListInfo &Out, UnsignedOrNone ExpandedIndex) { TemplateInstantiator Instantiator( TemplateInstantiator::ForParameterMappingSubstitution, *this, BaseLoc, TemplateArgs); - return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out); + return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out, + /*Uneval=*/false); } ExprResult diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index c3bf71dbf10df..41754574efa3a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -672,10 +672,10 @@ class TreeTransform { /// routine. /// /// Returns true if an error occurred. - bool TransformTemplateArguments(const TemplateArgumentLoc *Inputs, - unsigned NumInputs, - TemplateArgumentListInfo &Outputs, - bool Uneval = false) { + bool TransformTemplateArguments( + const TemplateArgumentLoc *Inputs, unsigned NumInputs, + TemplateArgumentListInfo &Outputs, bool Uneval = false, + UnsignedOrNone ExpansionIndex = std::nullopt) { return TransformTemplateArguments(Inputs, Inputs + NumInputs, Outputs, Uneval); } @@ -694,11 +694,11 @@ class TreeTransform { /// routine. /// /// Returns true if an error occurred. - template - bool TransformTemplateArguments(InputIterator First, - InputIterator Last, + template + bool TransformTemplateArguments(InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs, - bool Uneval = false); + bool Uneval = false, + UnsignedOrNone ExpansionIndex = std::nullopt); template bool TransformConceptTemplateArguments(InputIterator First, @@ -5174,11 +5174,11 @@ class TemplateArgumentLocInventIterator { } }; -template -template +template +template bool TreeTransform::TransformTemplateArguments( InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs, - bool Uneval) { + bool Uneval, UnsignedOrNone ExpansionIndex) { for (TemplateArgumentLoc In : llvm::make_range(First, Last)) { TemplateArgumentLoc Out; if (In.getArgument().getKind() == TemplateArgument::Pack) { @@ -5218,7 +5218,17 @@ bool TreeTransform::TransformTemplateArguments( std::optional ForgetSubst; if (Info.ExpandUnderForgetSubstitions) ForgetSubst.emplace(getDerived()); - for (unsigned I = 0; I != *Info.NumExpansions; ++I) { + + unsigned Start, End; + if (ExpansionIndex.has_value()) { + Start = *ExpansionIndex; + End = Start + 1; + } else { + Start = 0U; + End = *Info.NumExpansions; + } + + for (unsigned I = Start; I != End; ++I) { Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), I); TemplateArgumentLoc Out; diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp index 0312022912dca..b081771cd0cc2 100644 --- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp +++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp @@ -598,3 +598,26 @@ static_assert(MutabilityAlias); static_assert(MutabilityAlias); } + + +namespace GH199569 { + +template +concept callable = requires(F f, A... a) { + f(a...); +}; + +struct S { + void operator()(auto); +}; + +template struct B {}; + +template requires(... and callable>) +struct X {}; + +static_assert(callable>); +static_assert(callable>); + +X<0> x; +}