@@ -462,6 +462,10 @@ class ConstraintSatisfactionChecker {
462462 ExprResult Evaluate (const FoldExpandedConstraint &Constraint,
463463 const MultiLevelTemplateArgumentList &MLTAL);
464464
465+ ExprResult EvaluateSlow (const ConceptIdConstraint &Constraint,
466+ const MultiLevelTemplateArgumentList &MLTAL,
467+ unsigned int Size);
468+
465469 ExprResult Evaluate (const ConceptIdConstraint &Constraint,
466470 const MultiLevelTemplateArgumentList &MLTAL);
467471
@@ -855,35 +859,12 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
855859 return Out;
856860}
857861
858- ExprResult ConstraintSatisfactionChecker::Evaluate (
862+ ExprResult ConstraintSatisfactionChecker::EvaluateSlow (
859863 const ConceptIdConstraint &Constraint,
860- const MultiLevelTemplateArgumentList &MLTAL) {
861-
864+ const MultiLevelTemplateArgumentList &MLTAL,
865+ unsigned Size) {
862866 const ConceptReference *ConceptId = Constraint.getConceptId ();
863867
864- std::optional<Sema::InstantiatingTemplate> InstTemplate;
865- InstTemplate.emplace (S, ConceptId->getBeginLoc (),
866- Sema::InstantiatingTemplate::ConstraintsCheck{},
867- ConceptId->getNamedConcept (), MLTAL.getInnermost (),
868- Constraint.getSourceRange ());
869-
870- unsigned Size = Satisfaction.Details .size ();
871-
872- ExprResult E = Evaluate (Constraint.getNormalizedConstraint (), MLTAL);
873-
874- if (!E.isUsable ()) {
875- Satisfaction.Details .insert (Satisfaction.Details .begin () + Size, ConceptId);
876- return E;
877- }
878-
879- // ConceptIdConstraint is only relevant for diagnostics,
880- // so if the normalized constraint is satisfied, we should not
881- // substitute into the constraint.
882- if (Satisfaction.IsSatisfied )
883- return E;
884-
885- // TODO: We might want to cache the substitution of concept id constraints
886- // as it can be slow in the SFINAE case.
887868 llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
888869 std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
889870 SubstitutionInTemplateArguments (Constraint, MLTAL, SubstitutedOuterMost);
@@ -903,7 +884,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
903884 const ASTTemplateArgumentListInfo *Ori =
904885 ConceptId->getTemplateArgsAsWritten ();
905886 TemplateDeductionInfo Info (TemplateNameLoc);
906- InstTemplate. emplace (
887+ Sema::InstantiatingTemplate _ (
907888 S, TemplateNameLoc, Sema::InstantiatingTemplate::ConstraintSubstitution{},
908889 const_cast <NamedDecl *>(Template), Info, Constraint.getSourceRange ());
909890
@@ -926,8 +907,8 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
926907 Satisfaction.Details .insert (
927908 Satisfaction.Details .begin () + Size,
928909 new (S.Context ) ConstraintSatisfaction::SubstitutionDiagnostic{
929- SubstDiag.first ,
930- allocateStringFromConceptDiagnostic (S, SubstDiag.second )});
910+ SubstDiag.first ,
911+ allocateStringFromConceptDiagnostic (S, SubstDiag.second )});
931912 return ExprError ();
932913 }
933914
@@ -940,7 +921,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
940921 /* DoCheckConstraintSatisfaction=*/ false );
941922
942923 if (SubstitutedConceptId.isInvalid () || Trap.hasErrorOccurred ())
943- return E ;
924+ return ExprError () ;
944925
945926 if (Size != Satisfaction.Details .size ()) {
946927 Satisfaction.Details .insert (
@@ -952,6 +933,69 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
952933 return SubstitutedConceptId;
953934}
954935
936+ ExprResult ConstraintSatisfactionChecker::Evaluate (
937+ const ConceptIdConstraint &Constraint,
938+ const MultiLevelTemplateArgumentList &MLTAL) {
939+
940+ const ConceptReference *ConceptId = Constraint.getConceptId ();
941+
942+ UnsignedOrNone OuterPackSubstIndex =
943+ Constraint.getPackSubstitutionIndex ()
944+ ? Constraint.getPackSubstitutionIndex ()
945+ : PackSubstitutionIndex;
946+
947+ Sema::InstantiatingTemplate _ (S, ConceptId->getBeginLoc (),
948+ Sema::InstantiatingTemplate::ConstraintsCheck{},
949+ ConceptId->getNamedConcept (), MLTAL.getInnermost (),
950+ Constraint.getSourceRange ());
951+
952+ unsigned Size = Satisfaction.Details .size ();
953+
954+ ExprResult E = Evaluate (Constraint.getNormalizedConstraint (), MLTAL);
955+
956+ if (!E.isUsable ()) {
957+ Satisfaction.Details .insert (Satisfaction.Details .begin () + Size, ConceptId);
958+ return E;
959+ }
960+
961+ // ConceptIdConstraint is only relevant for diagnostics,
962+ // so if the normalized constraint is satisfied, we should not
963+ // substitute into the constraint.
964+ if (Satisfaction.IsSatisfied )
965+ return E;
966+
967+ llvm::FoldingSetNodeID ID;
968+ ID.AddPointer (Constraint.getConceptId ());
969+ ID.AddInteger (OuterPackSubstIndex.toInternalRepresentation ());
970+ ID.AddBoolean (Constraint.hasParameterMapping ());
971+ HashParameterMapping (S, MLTAL, ID, OuterPackSubstIndex)
972+ .VisitConstraint (Constraint);
973+
974+
975+ if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache .find (ID);
976+ Iter != S.UnsubstitutedConstraintSatisfactionCache .end ()) {
977+
978+ auto &Cached = Iter->second .Satisfaction ;
979+ Satisfaction.ContainsErrors = Cached.ContainsErrors ;
980+ Satisfaction.IsSatisfied = Cached.IsSatisfied ;
981+ Satisfaction.Details .insert (Satisfaction.Details .begin () + Size,
982+ Cached.Details .begin (), Cached.Details .end ());
983+ return Iter->second .SubstExpr ;
984+ }
985+
986+ ExprResult CE = EvaluateSlow (Constraint, MLTAL, Size);
987+ if (CE.isInvalid ())
988+ return E;
989+ UnsubstitutedConstraintSatisfactionCacheResult Cache;
990+ Cache.Satisfaction .ContainsErrors = Satisfaction.ContainsErrors ;
991+ Cache.Satisfaction .IsSatisfied = Satisfaction.IsSatisfied ;
992+ std::copy (Satisfaction.Details .begin () + Size, Satisfaction.Details .end (),
993+ std::back_inserter (Cache.Satisfaction .Details ));
994+ Cache.SubstExpr = CE;
995+ S.UnsubstitutedConstraintSatisfactionCache .insert ({ID, std::move (Cache)});
996+ return CE;
997+ }
998+
955999ExprResult ConstraintSatisfactionChecker::Evaluate (
9561000 const CompoundConstraint &Constraint,
9571001 const MultiLevelTemplateArgumentList &MLTAL) {
0 commit comments