llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: None (llvmbot) <details> <summary>Changes</summary> Backport adc64c6e1745a14896efa48d23fc541e4efe5a53 Requested by: @<!-- -->zyn0217 --- Full diff: https://github.com/llvm/llvm-project/pull/179153.diff 5 Files Affected: - (modified) clang/include/clang/Sema/Sema.h (+1-11) - (modified) clang/lib/Sema/SemaConcept.cpp (+89-53) - (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+12-30) - (modified) clang/lib/Sema/TreeTransform.h (+1-1) - (modified) clang/test/SemaCXX/cxx2c-fold-exprs.cpp (+16) ``````````diff diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 654bebbaf8ddd..d68ed7c75b86f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -13472,7 +13472,7 @@ class Sema final : public SemaBase { bool SubstTemplateArgumentsInParameterMapping( ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc, const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateArgumentListInfo &Out, bool BuildPackExpansionTypes); + TemplateArgumentListInfo &Out); /// Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. @@ -14888,16 +14888,6 @@ class Sema final : public SemaBase { const ConceptReference *TopLevelConceptId = nullptr, Expr **ConvertedExpr = nullptr); - /// \brief Check whether the given non-dependent constraint expression is - /// satisfied. Returns false and updates Satisfaction with the satisfaction - /// verdict if successful, emits a diagnostic and returns true if an error - /// occurred and satisfaction could not be determined. - /// - /// \returns true if an error occurred, false otherwise. - bool - CheckConstraintSatisfaction(const ConceptSpecializationExpr *ConstraintExpr, - ConstraintSatisfaction &Satisfaction); - /// Check whether the given function decl's trailing requires clause is /// satisfied, if any. Returns false and updates Satisfaction with the /// satisfaction verdict if successful, emits a diagnostic and returns true if diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 2674f0a7b8749..f55f3a9a61ab8 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -213,13 +213,41 @@ CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, } namespace { -class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> { +class AdjustConstraints : public TreeTransform<AdjustConstraints> { unsigned TemplateDepth = 0; + bool RemoveNonPackExpansionPacks = false; + public: - using inherited = TreeTransform<AdjustConstraintDepth>; - AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth) - : inherited(SemaRef), TemplateDepth(TemplateDepth) {} + using inherited = TreeTransform<AdjustConstraints>; + AdjustConstraints(Sema &SemaRef, unsigned TemplateDepth, + bool RemoveNonPackExpansionPacks = false) + : inherited(SemaRef), TemplateDepth(TemplateDepth), + RemoveNonPackExpansionPacks(RemoveNonPackExpansionPacks) {} + + ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, + UnsignedOrNone NumExpansions) { + return inherited::RebuildPackExpansion(Pattern, EllipsisLoc, NumExpansions); + } + + TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern, + SourceLocation EllipsisLoc, + UnsignedOrNone NumExpansions) { + if (!RemoveNonPackExpansionPacks) + return inherited::RebuildPackExpansion(Pattern, EllipsisLoc, + NumExpansions); + return Pattern; + } + + bool PreparePackForExpansion(TemplateArgumentLoc In, bool Uneval, + TemplateArgumentLoc &Out, UnexpandedInfo &Info) { + if (!RemoveNonPackExpansionPacks) + return inherited::PreparePackForExpansion(In, Uneval, Out, Info); + assert(In.getArgument().isPackExpansion()); + Out = In; + Info.Expand = false; + return false; + } using inherited::TransformTemplateTypeParmType; QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, @@ -232,8 +260,8 @@ class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> { TransformDecl(TL.getNameLoc(), OldTTPDecl)); QualType Result = getSema().Context.getTemplateTypeParmType( - T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(), - NewTTPDecl); + T->getDepth() + TemplateDepth, T->getIndex(), + RemoveNonPackExpansionPacks ? false : T->isParameterPack(), NewTTPDecl); TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -288,7 +316,13 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> { TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex()); - if (T->isParameterPack() && SemaRef.ArgPackSubstIndex) { + // In concept parameter mapping for fold expressions, packs that aren't + // expanded in place are treated as having non-pack dependency, so that + // a PackExpansionType won't prevent expanding the packs outside the + // TreeTransform. However we still need to check the pack at this point. + if ((T->isParameterPack() || + (T->getDecl() && T->getDecl()->isTemplateParameterPack())) && + SemaRef.ArgPackSubstIndex) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -506,10 +540,6 @@ StringRef allocateStringFromConceptDiagnostic(const Sema &S, ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint( const Expr *AtomicExpr, const MultiLevelTemplateArgumentList &MLTAL) { - EnterExpressionEvaluationContext ConstantEvaluated( - S, Sema::ExpressionEvaluationContext::ConstantEvaluated, - Sema::ReuseLambdaContextDecl); - llvm::FoldingSetNodeID ID; if (Template && DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, &MLTAL)) { @@ -617,7 +647,7 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( if (S.SubstTemplateArgumentsInParameterMapping( Constraint.getParameterMapping(), Constraint.getBeginLoc(), MLTAL, - SubstArgs, /*BuildPackExpansionTypes=*/true)) { + SubstArgs)) { Satisfaction.IsSatisfied = false; return std::nullopt; } @@ -663,6 +693,9 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( ExprResult ConstraintSatisfactionChecker::EvaluateSlow( const AtomicConstraint &Constraint, const MultiLevelTemplateArgumentList &MLTAL) { + EnterExpressionEvaluationContext ConstantEvaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated, + Sema::ReuseLambdaContextDecl); llvm::SmallVector<TemplateArgument> SubstitutedOutermost; std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs = @@ -706,8 +739,6 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( return SubstitutedAtomicExpr; } - EnterExpressionEvaluationContext ConstantEvaluated( - S, Sema::ExpressionEvaluationContext::ConstantEvaluated); SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; Expr::EvalResult EvalResult; EvalResult.Diag = &EvaluationDiags; @@ -1290,28 +1321,6 @@ SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D, MLTAL); } -bool Sema::CheckConstraintSatisfaction( - const ConceptSpecializationExpr *ConstraintExpr, - ConstraintSatisfaction &Satisfaction) { - - ExprResult Res = SubstituteConceptsInConstraintExpression( - *this, nullptr, ConstraintExpr, ArgPackSubstIndex); - if (!Res.isUsable()) - return true; - - llvm::SmallVector<AssociatedConstraint, 1> Constraints; - Constraints.emplace_back(Res.get()); - - MultiLevelTemplateArgumentList MLTAL(ConstraintExpr->getNamedConcept(), - ConstraintExpr->getTemplateArguments(), - true); - - return CheckConstraintSatisfaction( - ConstraintExpr->getNamedConcept(), Constraints, MLTAL, - ConstraintExpr->getSourceRange(), Satisfaction, - ConstraintExpr->getConceptReference()); -} - bool Sema::SetupConstraintScope( FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, const MultiLevelTemplateArgumentList &MLTAL, @@ -2000,14 +2009,20 @@ class SubstituteParameterMappings { const MultiLevelTemplateArgumentList *MLTAL; const ASTTemplateArgumentListInfo *ArgsAsWritten; - bool InFoldExpr; + // When normalizing a fold constraint, e.g. + // C<Pack1, Pack2...> && ... + // we want the TreeTransform to expand only Pack2 but not Pack1, + // since Pack1 will be expanded during the evaluation of the fold expression. + // This flag helps rewrite any non-PackExpansion packs into "expanded" + // parameters. + bool RemovePacksForFoldExpr; SubstituteParameterMappings(Sema &SemaRef, const MultiLevelTemplateArgumentList *MLTAL, const ASTTemplateArgumentListInfo *ArgsAsWritten, - bool InFoldExpr) + bool RemovePacksForFoldExpr) : SemaRef(SemaRef), MLTAL(MLTAL), ArgsAsWritten(ArgsAsWritten), - InFoldExpr(InFoldExpr) {} + RemovePacksForFoldExpr(RemovePacksForFoldExpr) {} void buildParameterMapping(NormalizedConstraintWithParamMapping &N); @@ -2016,9 +2031,10 @@ class SubstituteParameterMappings { bool substitute(ConceptIdConstraint &CC); public: - SubstituteParameterMappings(Sema &SemaRef, bool InFoldExpr = false) + SubstituteParameterMappings(Sema &SemaRef, + bool RemovePacksForFoldExpr = false) : SemaRef(SemaRef), MLTAL(nullptr), ArgsAsWritten(nullptr), - InFoldExpr(InFoldExpr) {} + RemovePacksForFoldExpr(RemovePacksForFoldExpr) {} bool substitute(NormalizedConstraint &N); }; @@ -2121,8 +2137,7 @@ bool SubstituteParameterMappings::substitute( // which is wrong. TemplateArgumentListInfo SubstArgs; if (SemaRef.SubstTemplateArgumentsInParameterMapping( - N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs, - /*BuildPackExpansionTypes=*/!InFoldExpr)) + N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs)) return true; Sema::CheckTemplateArgumentInfo CTAI; auto *TD = @@ -2192,8 +2207,7 @@ bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) { const ASTTemplateArgumentListInfo *ArgsAsWritten = CSE->getTemplateArgsAsWritten(); if (SemaRef.SubstTemplateArgumentsInParameterMapping( - ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out, - /*BuildPackExpansionTypes=*/!InFoldExpr)) + ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out)) return true; Sema::CheckTemplateArgumentInfo CTAI; if (SemaRef.CheckTemplateArgumentList(CSE->getNamedConcept(), @@ -2206,7 +2220,7 @@ bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) { TemplateArgs.replaceOutermostTemplateArguments(CSE->getNamedConcept(), CTAI.SugaredConverted); return SubstituteParameterMappings(SemaRef, &TemplateArgs, ArgsAsWritten, - InFoldExpr) + RemovePacksForFoldExpr) .substitute(CC.getNormalizedConstraint()); } @@ -2222,13 +2236,13 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) { case NormalizedConstraint::ConstraintKind::FoldExpanded: { auto &FE = static_cast<FoldExpandedConstraint &>(N); if (!MLTAL) { - llvm::SaveAndRestore _1(InFoldExpr, true); + llvm::SaveAndRestore _1(RemovePacksForFoldExpr, true); assert(!ArgsAsWritten); return substitute(FE.getNormalizedPattern()); } Sema::ArgPackSubstIndexRAII _(SemaRef, std::nullopt); substitute(static_cast<NormalizedConstraintWithParamMapping &>(FE)); - return SubstituteParameterMappings(SemaRef, /*InFoldExpr=*/true) + return SubstituteParameterMappings(SemaRef, /*RemovePacksForFoldExpr=*/true) .substitute(FE.getNormalizedPattern()); } case NormalizedConstraint::ConstraintKind::ConceptId: { @@ -2239,16 +2253,38 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) { } assert(!ArgsAsWritten); const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr(); + SmallVector<TemplateArgument> InnerArgs(CSE->getTemplateArguments()); ConceptDecl *Concept = CSE->getNamedConcept(); + if (RemovePacksForFoldExpr) { + TemplateArgumentListInfo OutArgs; + ArrayRef<TemplateArgumentLoc> InputArgLoc = + CSE->getConceptReference()->getTemplateArgsAsWritten()->arguments(); + if (AdjustConstraints(SemaRef, /*TemplateDepth=*/0, + /*RemoveNonPackExpansionPacks=*/true) + .TransformTemplateArguments(InputArgLoc.begin(), + InputArgLoc.end(), OutArgs)) + return true; + Sema::CheckTemplateArgumentInfo CTAI; + // Repack the packs. + if (SemaRef.CheckTemplateArgumentList( + Concept, Concept->getTemplateParameters(), Concept->getBeginLoc(), + OutArgs, + /*DefaultArguments=*/{}, + /*PartialTemplateArgs=*/false, CTAI)) + return true; + InnerArgs = std::move(CTAI.SugaredConverted); + } + MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs( Concept, Concept->getLexicalDeclContext(), - /*Final=*/true, CSE->getTemplateArguments(), + /*Final=*/true, InnerArgs, /*RelativeToPrimary=*/true, /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); - return SubstituteParameterMappings( - SemaRef, &MLTAL, CSE->getTemplateArgsAsWritten(), InFoldExpr) + return SubstituteParameterMappings(SemaRef, &MLTAL, + CSE->getTemplateArgsAsWritten(), + RemovePacksForFoldExpr) .substitute(CC.getNormalizedConstraint()); } case NormalizedConstraint::ConstraintKind::Compound: { @@ -2496,12 +2532,12 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1, for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) { if (Depth2 > Depth1) { AC1[I].ConstraintExpr = - AdjustConstraintDepth(*this, Depth2 - Depth1) + AdjustConstraints(*this, Depth2 - Depth1) .TransformExpr(const_cast<Expr *>(AC1[I].ConstraintExpr)) .get(); } else if (Depth1 > Depth2) { AC2[I].ConstraintExpr = - AdjustConstraintDepth(*this, Depth1 - Depth2) + AdjustConstraints(*this, Depth1 - Depth2) .TransformExpr(const_cast<Expr *>(AC2[I].ConstraintExpr)) .get(); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 35205f40cbcef..50def4e181ab8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1281,11 +1281,6 @@ namespace { // Whether an incomplete substituion should be treated as an error. bool BailOutOnIncomplete; - // Whether to rebuild pack expansion types; We don't do that when - // rebuilding the parameter mapping of a fold expression appearing - // in a constraint expression. - bool BuildPackExpansionTypes = true; - // CWG2770: Function parameters should be instantiated when they are // needed by a satisfaction check of an atomic constraint or // (recursively) by another function parameter. @@ -1313,11 +1308,9 @@ namespace { TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef, SourceLocation Loc, - const MultiLevelTemplateArgumentList &TemplateArgs, - bool BuildPackExpansionTypes) + const MultiLevelTemplateArgumentList &TemplateArgs) : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), - BailOutOnIncomplete(false), - BuildPackExpansionTypes(BuildPackExpansionTypes) {} + BailOutOnIncomplete(false) {} /// Determine whether the given type \p T has already been /// transformed. @@ -1601,24 +1594,6 @@ namespace { return inherited::TransformTemplateArgument(Input, Output, Uneval); } - // This has to be here to allow its overload. - ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, - UnsignedOrNone NumExpansions) { - return inherited::RebuildPackExpansion(Pattern, EllipsisLoc, - NumExpansions); - } - - TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern, - SourceLocation EllipsisLoc, - UnsignedOrNone NumExpansions) { - // We don't rewrite a PackExpansion type when we want to normalize a - // CXXFoldExpr constraint. We'll expand it when evaluating the constraint. - if (BuildPackExpansionTypes) - return inherited::RebuildPackExpansion(Pattern, EllipsisLoc, - NumExpansions); - return Pattern; - } - using TreeTransform::TransformTemplateSpecializationType; QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, @@ -2446,7 +2421,14 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, auto [AssociatedDecl, Final] = TemplateArgs.getAssociatedDecl(T->getDepth()); UnsignedOrNone PackIndex = std::nullopt; - if (T->isParameterPack()) { + if (T->isParameterPack() || + // In concept parameter mapping for fold expressions, packs that aren't + // expanded in place are treated as having non-pack dependency, so that + // a PackExpansionType won't prevent expanding the packs outside the + // TreeTransform. However, we still need to unpack the arguments during + // any template argument substitution, so we check the associated + // declaration instead. + (T->getDecl() && T->getDecl()->isTemplateParameterPack())) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -4340,10 +4322,10 @@ bool Sema::SubstTemplateArguments( bool Sema::SubstTemplateArgumentsInParameterMapping( ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc, const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateArgumentListInfo &Out, bool BuildPackExpansionTypes) { + TemplateArgumentListInfo &Out) { TemplateInstantiator Instantiator( TemplateInstantiator::ForParameterMappingSubstitution, *this, BaseLoc, - TemplateArgs, BuildPackExpansionTypes); + TemplateArgs); return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index bc923c80b7132..5a1e5fedba9da 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -5179,7 +5179,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments( if (In.getArgument().isPackExpansion()) { UnexpandedInfo Info; TemplateArgumentLoc Prepared; - if (PreparePackForExpansion(In, Uneval, Prepared, Info)) + if (getDerived().PreparePackForExpansion(In, Uneval, Prepared, Info)) return true; if (!Info.Expand) { Outputs.addArgument(Prepared); diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp index 289059ea86eb9..89ddcbaf11583 100644 --- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp +++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp @@ -491,4 +491,20 @@ void test() { } +namespace GH177245 { + +template <class _Fun, class... _As> +concept __callable = requires (_Fun __fun, _As...) { __fun(); }; + +template <class... _Args> +struct __mdispatch { + template <class... _Ts> + requires (__callable<_Args, _Ts...> && ...) + void operator()(); +}; + +static_assert(!__callable<__mdispatch<int>>); + +} + } `````````` </details> https://github.com/llvm/llvm-project/pull/179153 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
