Repository: llvm/llvm-project
File: clang/lib/Sema/SemaConcept.cpp (C++)

Code before:
  if (Offset < SubstitutedOutermost.size())
    SubstitutedOutermost.erase(SubstitutedOutermost.begin() + Offset);

  MultiLevelTemplateArgumentList SubstitutedTemplateArgs;
  SubstitutedTemplateArgs.addOuterTemplateArguments(TD, SubstitutedOutermost,
                                                    /*Final=*/false);
  return std::move(SubstitutedTemplateArgs);
}

ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
    const AtomicConstraint &Constraint,
    const MultiLevelTemplateArgumentList &MLTAL) {
  std::optional<EnterExpressionEvaluationContext> EvaluationContext;
  EvaluationContext.emplace(
      S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
      Sema::ReuseLambdaContextDecl);

  llvm::SmallVector<TemplateArgument> SubstitutedOutermost;
  std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
      SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOutermost);
  if (!SubstitutedArgs) {
    Satisfaction.IsSatisfied = false;
    return ExprEmpty();
  }

  // This is dumb: generic lambdas inside requires body require a lambda context
  // decl from which to fetch correct template arguments. But we don't have any
  // proper decls because the constraints are already normalized.
  if (ParentConcept && SubstitutedArgs->getNumSubstitutedLevels()) {
    auto *CD = ParentConcept->getNamedConcept();
    // FIXME: the evaluation context should learn to track template arguments
    // separately from a Decl.
    EvaluationContext.emplace(
        S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
        /*LambdaContextDecl=*/
        ImplicitConceptSpecializationDecl::Create(
            S.Context, CD->getDeclContext(), CD->getBeginLoc(),
            SubstitutedArgs->getOutermost()));
  }

  Sema::ArgPackSubstIndexRAII SubstIndex(S, PackSubstitutionIndex);
  ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
      Constraint.getConstraintExpr(), *SubstitutedArgs);

  if (SubstitutedAtomicExpr.isInvalid())
    return ExprError();

  if (SubstitutedAtomicExpr.isUnset())
    // Evaluator has decided satisfaction without yielding an expression.
    return ExprEmpty();


Review comment (suggestion):
```suggestion
  // FIXME: generic lambdas inside requires body require a lambda context
```

Code after:
      Offset = I + 1;
    } else {
      SubstitutedOutermost.push_back(Arg);
      Offset = SubstitutedOutermost.size();
    }
  }
  if (Offset < SubstitutedOutermost.size())
    SubstitutedOutermost.erase(SubstitutedOutermost.begin() + Offset);

  MultiLevelTemplateArgumentList SubstitutedTemplateArgs;
  SubstitutedTemplateArgs.addOuterTemplateArguments(TD, SubstitutedOutermost,
                                                    /*Final=*/false);
  return std::move(SubstitutedTemplateArgs);
}

ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
    const AtomicConstraint &Constraint,
    const MultiLevelTemplateArgumentList &MLTAL) {
  std::optional<EnterExpressionEvaluationContext> EvaluationContext;
  EvaluationContext.emplace(
      S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
      Sema::ReuseLambdaContextDecl);

  llvm::SmallVector<TemplateArgument> SubstitutedOutermost;
  std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
      SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOutermost);
  if (!SubstitutedArgs) {
    Satisfaction.IsSatisfied = false;
    return ExprEmpty();
  }

  // Note that generic lambdas inside requires body require a lambda context
  // decl from which to fetch correct template arguments. But we don't have any
  // proper decls because the constraints are already normalized.
  if (ParentConcept) {
    // FIXME: the evaluation context should learn to track template arguments
    // separately from a Decl.
    EvaluationContext.emplace(
        S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
        /*LambdaContextDecl=*/
        ImplicitConceptSpecializationDecl::Create(
            S.Context, ParentConcept->getDeclContext(),
            ParentConcept->getBeginLoc(), SubstitutedOutermost));
  }

  Sema::ArgPackSubstIndexRAII SubstIndex(S, PackSubstitutionIndex);
  ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
      Constraint.getConstraintExpr(), *SubstitutedArgs);

  if (SubstitutedAtomicExpr.isInvalid())
    return ExprError();