================
@@ -543,30 +672,330 @@ static ExprResult calculateConstraintSatisfaction(
     return ExprError();
   }
 
-  assert(EvalResult.Val.isInt() &&
-         "evaluating bool expression didn't produce int");
-  Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
-  if (!Satisfaction.IsSatisfied)
-    Satisfaction.Details.emplace_back(SubstitutedAtomicExpr.get());
+  assert(EvalResult.Val.isInt() &&
+         "evaluating bool expression didn't produce int");
+  Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+  if (!Satisfaction.IsSatisfied)
+    Satisfaction.Details.emplace_back(SubstitutedAtomicExpr.get());
+
+  return SubstitutedAtomicExpr;
+}
+
+ExprResult CalculateConstraintSatisfaction::Calculate(
+    const AtomicConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+
+  unsigned Size = Satisfaction.Details.size();
+  llvm::FoldingSetNodeID ID;
+  UnsignedOrNone OuterPackSubstIndex =
+      Constraint.getPackSubstitutionIndex()
+          ? Constraint.getPackSubstitutionIndex()
+          : PackSubstitutionIndex;
+  // Constraint.getConstraintExpr()->Profile(ID, S.Context, /*Canonical=*/true,
+  //                                         /*ProfileLambdaExpr=*/true);
+  auto *Previous = Constraint.getConstraintExpr();
+  ID.AddPointer(Constraint.getConstraintExpr());
+  ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
+  ID.AddBoolean(Constraint.hasParameterMapping());
+  HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
+      .VisitConstraint(Constraint);
+
+  if (auto Iter = S.ConceptIdSatisfactionCache.find(ID);
+      Iter != S.ConceptIdSatisfactionCache.end()) {
+
+    auto &Cached = Iter->second.Satisfaction;
+    Satisfaction.ContainsErrors = Cached.ContainsErrors;
+    Satisfaction.IsSatisfied = Cached.IsSatisfied;
+    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
+                                Cached.Details.begin(), Cached.Details.end());
+    return Iter->second.SubstExpr;
+  }
+
+  ExprResult E = CalculateSlow(Constraint, MLTAL);
+
+  assert(Constraint.getConstraintExpr() == Previous);
+
+  CachedConceptIdConstraint Cache;
+  Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
+  Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
+  std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
+            std::back_inserter(Cache.Satisfaction.Details));
+  Cache.SubstExpr = E;
+  Cache.E = Constraint.getConstraintExpr();
+  S.ConceptIdSatisfactionCache.insert({ID, std::move(Cache)});
+
+  return E;
+}
+
+UnsignedOrNone
+CalculateConstraintSatisfaction::EvaluateFoldExpandedConstraintSize(
+    const FoldExpandedConstraint &FE,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+
+  // We should ignore errors in the presence of packs of different size.
+  Sema::SFINAETrap Trap(S);
+
+  Expr *Pattern = const_cast<Expr *>(FE.getPattern());
+
+  SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+  S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+  assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+  bool Expand = true;
+  bool RetainExpansion = false;
+  UnsignedOrNone NumExpansions(std::nullopt);
+  if (S.CheckParameterPacksForExpansion(
+          Pattern->getExprLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
+          /*FailOnPackProducingTemplates=*/false, Expand, RetainExpansion,
+          NumExpansions) ||
+      !Expand || RetainExpansion)
+    return std::nullopt;
+
+  if (NumExpansions && S.getLangOpts().BracketDepth < *NumExpansions) {
+    S.Diag(Pattern->getExprLoc(),
+           clang::diag::err_fold_expression_limit_exceeded)
+        << *NumExpansions << S.getLangOpts().BracketDepth
+        << Pattern->getSourceRange();
+    S.Diag(Pattern->getExprLoc(), diag::note_bracket_depth);
+    return std::nullopt;
+  }
+  return NumExpansions;
+}
+
+ExprResult CalculateConstraintSatisfaction::Calculate(
+    const FoldExpandedConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+  bool Conjunction = Constraint.getFoldOperator() ==
+                     FoldExpandedConstraint::FoldOperatorKind::And;
+  unsigned EffectiveDetailEndIndex = Satisfaction.Details.size();
+
+  llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
+  // FIXME: Is PackSubstitutionIndex correct?
+  llvm::SaveAndRestore _(PackSubstitutionIndex, S.ArgPackSubstIndex);
+  std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
+      SubstitutionInTemplateArguments(
+          static_cast<const NormalizedConstraintWithParamMapping 
&>(Constraint),
+          MLTAL, SubstitutedOuterMost);
+  if (!SubstitutedArgs) {
+    Satisfaction.IsSatisfied = false;
+    return ExprError();
+  }
+
+  ExprResult Out;
+  UnsignedOrNone NumExpansions =
+      EvaluateFoldExpandedConstraintSize(Constraint, *SubstitutedArgs);
+  if (!NumExpansions)
+    return ExprEmpty();
+
+  if (*NumExpansions == 0) {
+    Satisfaction.IsSatisfied = Conjunction;
+    return ExprEmpty();
+  }
+
+  for (unsigned I = 0; I < *NumExpansions; I++) {
+    Sema::ArgPackSubstIndexRAII SubstIndex(S, I);
+    Satisfaction.IsSatisfied = false;
+    Satisfaction.ContainsErrors = false;
+    ExprResult Expr =
+        CalculateConstraintSatisfaction(S, Template, TemplateNameLoc,
+                                        UnsignedOrNone(I), Satisfaction)
+            .Calculate(Constraint.getNormalizedPattern(), *SubstitutedArgs);
+    if (Expr.isUsable()) {
+      if (Out.isUnset())
+        Out = Expr;
+      else
+        Out = BinaryOperator::Create(S.Context, Out.get(), Expr.get(),
+                                     Conjunction ? BinaryOperatorKind::BO_LAnd
+                                                 : BinaryOperatorKind::BO_LOr,
+                                     S.Context.BoolTy, VK_PRValue, OK_Ordinary,
+                                     Constraint.getBeginLoc(),
+                                     FPOptionsOverride{});
+    } else {
+      assert(!Satisfaction.IsSatisfied);
+    }
+    if (!Conjunction && Satisfaction.IsSatisfied) {
+      Satisfaction.Details.erase(Satisfaction.Details.begin() +
+                                     EffectiveDetailEndIndex,
+                                 Satisfaction.Details.end());
+      break;
+    }
+    if (Satisfaction.IsSatisfied != Conjunction)
+      return Out;
+  }
+
+  return Out;
+}
+
+ExprResult CalculateConstraintSatisfaction::Calculate(
+    const ConceptIdConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+
+  std::optional<Sema::InstantiatingTemplate> InstTemplate;
+  InstTemplate.emplace(S, Constraint.getConceptId()->getBeginLoc(),
+                       Sema::InstantiatingTemplate::ConstraintsCheck{},
+                       Constraint.getConceptId()->getNamedConcept(),
+                       MLTAL.getInnermost(), Constraint.getSourceRange());
+
+  unsigned Size = Satisfaction.Details.size();
+
+  ExprResult E = Calculate(Constraint.getNormalizedConstraint(), MLTAL);
+
+  if (!E.isUsable()) {
+    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
+                                Constraint.getConceptId());
+    return E;
+  }
+
+  if (Satisfaction.IsSatisfied)
+    return E;
+
+  llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
+  std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
+      SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
+
+  if (!SubstitutedArgs) {
+    Satisfaction.IsSatisfied = false;
+    // FIXME: diagnostics?
+    return ExprError();
+  }
+
+  Sema::SFINAETrap Trap(S);
+  Sema::ArgPackSubstIndexRAII SubstIndex(
+      S, Constraint.getPackSubstitutionIndex()
+             ? Constraint.getPackSubstitutionIndex()
+             : PackSubstitutionIndex);
+
+  const ASTTemplateArgumentListInfo *Ori =
+      Constraint.getConceptId()->getTemplateArgsAsWritten();
+  TemplateDeductionInfo Info(TemplateNameLoc);
+  InstTemplate.emplace(
+      S, TemplateNameLoc, 
Sema::InstantiatingTemplate::ConstraintSubstitution{},
+      const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
+
+  TemplateArgumentListInfo OutArgs(Ori->LAngleLoc, Ori->RAngleLoc);
+  if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs, OutArgs) ||
+      Trap.hasErrorOccurred()) {
+    Satisfaction.IsSatisfied = false;
+    if (!Trap.hasErrorOccurred())
+      return ExprError();
+
+    PartialDiagnosticAt SubstDiag{SourceLocation(),
+                                  PartialDiagnostic::NullDiagnostic()};
+    Info.takeSFINAEDiagnostic(SubstDiag);
+    // FIXME: Concepts: This is an unfortunate consequence of there
+    //  being no serialization code for PartialDiagnostics and the fact
+    //  that serializing them would likely take a lot more storage than
+    //  just storing them as strings. We would still like, in the
+    //  future, to serialize the proper PartialDiagnostic as serializing
+    //  it as a string defeats the purpose of the diagnostic mechanism.
+    SmallString<128> DiagString;
+    DiagString = ": ";
+    SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
+    unsigned MessageSize = DiagString.size();
+    char *Mem = new (S.Context) char[MessageSize];
+    memcpy(Mem, DiagString.c_str(), MessageSize);
+    Satisfaction.Details.insert(
+        Satisfaction.Details.begin() + Size,
+        new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+            SubstDiag.first, StringRef(Mem, MessageSize)});
+    return ExprError();
+  }
+
+  CXXScopeSpec SS;
+  SS.Adopt(Constraint.getConceptId()->getNestedNameSpecifierLoc());
 
-  return SubstitutedAtomicExpr;
+  ExprResult SubstitutedConceptId = S.CheckConceptTemplateId(
+      SS, Constraint.getConceptId()->getTemplateKWLoc(),
----------------
zyn0217 wrote:

Maybe we don't need to rebuild a ConceptSpecializationDecl - again I forgot to 
clean it up

https://github.com/llvm/llvm-project/pull/141776
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to