[clang] d483730 - Re-apply "Deferred Concept Instantiation Implementation""

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 17 06:25:01 PDT 2022


Author: Erich Keane
Date: 2022-08-17T06:24:40-07:00
New Revision: d483730d8c3fa2e0d4192b2f3c61c761b124e6ad

URL: https://github.com/llvm/llvm-project/commit/d483730d8c3fa2e0d4192b2f3c61c761b124e6ad
DIFF: https://github.com/llvm/llvm-project/commit/d483730d8c3fa2e0d4192b2f3c61c761b124e6ad.diff

LOG: Re-apply "Deferred Concept Instantiation Implementation""

This reverts commit 258c3aee54e11bc5c5d8ac137eb15e8d5bbcc7e4.

This should fix the libc++ issue that caused the revert, by re-designing
slightly how we determined when we should evaluate the constraints.
Additionally, many of the other components to the original patch (the
NFC parts) were committed separately to shrink the size of this patch
for review.

Differential Revision: https://reviews.llvm.org/D126907

Added: 
    clang/test/SemaTemplate/concepts-friends.cpp
    clang/test/SemaTemplate/deferred-concept-inst.cpp
    clang/test/SemaTemplate/trailing-return-short-circuit.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Sema/Sema.h
    clang/include/clang/Sema/Template.h
    clang/lib/Sema/SemaConcept.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/SemaOverload.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/lib/Sema/SemaTemplateInstantiate.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
    clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
    clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
    clang/test/SemaTemplate/concepts.cpp
    clang/test/SemaTemplate/instantiate-requires-clause.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1da6015ad1610..4a6c9deb0c9c2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -144,6 +144,10 @@ C++ Language Changes in Clang
 
 C++20 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
+- Clang now correctly delays the instantiation of function constraints until
+  the time of checking, which should now allow the libstdc++ ranges implementation
+  to work for at least trivial examples.  This fixes
+  `Issue 44178 <https://github.com/llvm/llvm-project/issues/44178>`_.
 
 - Support capturing structured bindings in lambdas
   (`P1091R3 <https://wg21.link/p1091r3>`_ and `P1381R1 <https://wg21.link/P1381R1>`).

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6908eaf8ff954..85641f595d417 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3637,6 +3637,16 @@ class Sema final {
                   bool ConsiderCudaAttrs = true,
                   bool ConsiderRequiresClauses = true);
 
+  // Calculates whether the expression Constraint depends on an enclosing
+  // template, for the purposes of [temp.friend] p9.
+  // TemplateDepth is the 'depth' of the friend function, which is used to
+  // compare whether a declaration reference is referring to a containing
+  // template, or just the current friend function. A 'lower' TemplateDepth in
+  // the AST refers to a 'containing' template. As the constraint is
+  // uninstantiated, this is relative to the 'top' of the TU.
+  bool ConstraintExpressionDependsOnEnclosingTemplate(unsigned TemplateDepth,
+                                                      const Expr *Constraint);
+
   enum class AllowedExplicit {
     /// Allow no explicit functions to be used.
     None,
@@ -7109,6 +7119,21 @@ class Sema final {
       LocalInstantiationScope &Scope,
       const MultiLevelTemplateArgumentList &TemplateArgs);
 
+  /// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in
+  /// the case of lambdas) set up the LocalInstantiationScope of the current
+  /// function.
+  bool SetupConstraintScope(
+      FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
+      MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope);
+
+  /// Used during constraint checking, sets up the constraint template arguemnt
+  /// lists, and calls SetupConstraintScope to set up the
+  /// LocalInstantiationScope to have the proper set of ParVarDecls configured.
+  llvm::Optional<MultiLevelTemplateArgumentList>
+  SetupConstraintCheckingTemplateArgumentsAndScope(
+      FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
+      LocalInstantiationScope &Scope);
+
 public:
   const NormalizedConstraint *
   getNormalizedAssociatedConstraints(
@@ -7151,6 +7176,39 @@ class Sema final {
   bool CheckConstraintSatisfaction(
       const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
       const MultiLevelTemplateArgumentList &TemplateArgLists,
+      SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
+    llvm::SmallVector<Expr *, 4> Converted;
+    return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted,
+                                       TemplateArgLists, TemplateIDRange,
+                                       Satisfaction);
+  }
+
+  /// \brief Check whether the given list of constraint expressions are
+  /// satisfied (as if in a 'conjunction') given template arguments.
+  /// Additionally, takes an empty list of Expressions which is populated with
+  /// the instantiated versions of the ConstraintExprs.
+  /// \param Template the template-like entity that triggered the constraints
+  /// check (either a concept or a constrained entity).
+  /// \param ConstraintExprs a list of constraint expressions, treated as if
+  /// they were 'AND'ed together.
+  /// \param ConvertedConstraints a out parameter that will get populated with
+  /// the instantiated version of the ConstraintExprs if we successfully checked
+  /// satisfaction.
+  /// \param TemplateArgList the multi-level list of template arguments to
+  /// substitute into the constraint expression. This should be relative to the
+  /// top-level (hence multi-level), since we need to instantiate fully at the
+  /// time of checking.
+  /// \param TemplateIDRange The source range of the template id that
+  /// caused the constraints check.
+  /// \param Satisfaction if true is returned, will contain details of the
+  /// satisfaction, with enough information to diagnose an unsatisfied
+  /// expression.
+  /// \returns true if an error occurred and satisfaction could not be checked,
+  /// false otherwise.
+  bool CheckConstraintSatisfaction(
+      const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+      llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
+      const MultiLevelTemplateArgumentList &TemplateArgList,
       SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
 
   /// \brief Check whether the given non-dependent constraint expression is
@@ -7170,8 +7228,8 @@ class Sema final {
   /// \returns true if an error occurred, false otherwise.
   bool CheckFunctionConstraints(const FunctionDecl *FD,
                                 ConstraintSatisfaction &Satisfaction,
-                                SourceLocation UsageLoc = SourceLocation());
-
+                                SourceLocation UsageLoc = SourceLocation(),
+                                bool ForOverloadResolution = false);
 
   /// \brief Ensure that the given template arguments satisfy the constraints
   /// associated with the given template, emitting a diagnostic if they do not.
@@ -8927,7 +8985,8 @@ class Sema final {
 
   MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
       const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr,
-      bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr);
+      bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
+      bool LookBeyondLambda = false, bool IncludeContainingStruct = false);
 
   /// A context in which code is being synthesized (where a source location
   /// alone is not sufficient to identify the context). This covers template
@@ -9635,23 +9694,21 @@ class Sema final {
                             const MultiLevelTemplateArgumentList &TemplateArgs,
                             SourceLocation Loc, DeclarationName Entity);
 
-  TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T,
-                            const MultiLevelTemplateArgumentList &TemplateArgs,
-                                        SourceLocation Loc,
-                                        DeclarationName Entity,
-                                        CXXRecordDecl *ThisContext,
-                                        Qualifiers ThisTypeQuals);
+  TypeSourceInfo *SubstFunctionDeclType(
+      TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs,
+      SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext,
+      Qualifiers ThisTypeQuals, bool EvaluateConstraints = true);
   void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
                           const MultiLevelTemplateArgumentList &Args);
   bool SubstExceptionSpec(SourceLocation Loc,
                           FunctionProtoType::ExceptionSpecInfo &ESI,
                           SmallVectorImpl<QualType> &ExceptionStorage,
                           const MultiLevelTemplateArgumentList &Args);
-  ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
-                            const MultiLevelTemplateArgumentList &TemplateArgs,
-                                int indexAdjustment,
-                                Optional<unsigned> NumExpansions,
-                                bool ExpectParameterPack);
+  ParmVarDecl *
+  SubstParmVarDecl(ParmVarDecl *D,
+                   const MultiLevelTemplateArgumentList &TemplateArgs,
+                   int indexAdjustment, Optional<unsigned> NumExpansions,
+                   bool ExpectParameterPack, bool EvaluateConstraints = true);
   bool SubstParmTypes(SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
                       const FunctionProtoType::ExtParameterInfo *ExtParamInfos,
                       const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -9661,6 +9718,25 @@ class Sema final {
   ExprResult SubstExpr(Expr *E,
                        const MultiLevelTemplateArgumentList &TemplateArgs);
 
+  // A RAII type used by the TemplateDeclInstantiator and TemplateInstantiator
+  // to disable constraint evaluation, then restore the state.
+  template <typename InstTy> struct ConstraintEvalRAII {
+    InstTy &TI;
+    bool OldValue;
+
+    ConstraintEvalRAII(InstTy &TI)
+        : TI(TI), OldValue(TI.getEvaluateConstraints()) {
+      TI.setEvaluateConstraints(false);
+    }
+    ~ConstraintEvalRAII() { TI.setEvaluateConstraints(OldValue); }
+  };
+
+  // Unlike the above, this evaluates constraints, which should only happen at
+  // 'constraint checking' time.
+  ExprResult
+  SubstConstraintExpr(Expr *E,
+                      const MultiLevelTemplateArgumentList &TemplateArgs);
+
   /// Substitute the given template arguments into a list of
   /// expressions, expanding pack expansions if required.
   ///
@@ -9690,7 +9766,6 @@ class Sema final {
                          const MultiLevelTemplateArgumentList &TemplateArgs,
                          TemplateArgumentListInfo &Outputs);
 
-
   Decl *SubstDecl(Decl *D, DeclContext *Owner,
                   const MultiLevelTemplateArgumentList &TemplateArgs);
 
@@ -9781,7 +9856,8 @@ class Sema final {
                     const MultiLevelTemplateArgumentList &TemplateArgs);
 
   bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
-                           const MultiLevelTemplateArgumentList &TemplateArgs);
+                           const MultiLevelTemplateArgumentList &TemplateArgs,
+                           bool EvaluateConstraint);
 
   bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                   ParmVarDecl *Param);

diff  --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 8df92b7000f38..2630853d14380 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -503,6 +503,7 @@ enum class TemplateSubstitutionKind : char {
     const MultiLevelTemplateArgumentList &TemplateArgs;
     Sema::LateInstantiatedAttrVec* LateAttrs = nullptr;
     LocalInstantiationScope *StartingScope = nullptr;
+    bool EvaluateConstraints = true;
 
     /// A list of out-of-line class template partial
     /// specializations that will need to be instantiated after the
@@ -526,6 +527,13 @@ enum class TemplateSubstitutionKind : char {
           SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex),
           Owner(Owner), TemplateArgs(TemplateArgs) {}
 
+    void setEvaluateConstraints(bool B) {
+      EvaluateConstraints = B;
+    }
+    bool getEvaluateConstraints() {
+      return EvaluateConstraints;
+    }
+
 // Define all the decl visitors using DeclNodes.inc
 #define DECL(DERIVED, BASE) \
     Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D);

diff  --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 7545b7974ce49..240c656b953f3 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -18,6 +18,7 @@
 #include "clang/Sema/Template.h"
 #include "clang/Sema/Overload.h"
 #include "clang/Sema/Initialization.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Basic/OperatorPrecedence.h"
@@ -30,6 +31,7 @@ using namespace sema;
 
 namespace {
 class LogicalBinOp {
+  SourceLocation Loc;
   OverloadedOperatorKind Op = OO_None;
   const Expr *LHS = nullptr;
   const Expr *RHS = nullptr;
@@ -40,12 +42,14 @@ class LogicalBinOp {
       Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
       LHS = BO->getLHS();
       RHS = BO->getRHS();
+      Loc = BO->getExprLoc();
     } else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
       // If OO is not || or && it might not have exactly 2 arguments.
       if (OO->getNumArgs() == 2) {
         Op = OO->getOperator();
         LHS = OO->getArg(0);
         RHS = OO->getArg(1);
+        Loc = OO->getOperatorLoc();
       }
     }
   }
@@ -56,6 +60,26 @@ class LogicalBinOp {
 
   const Expr *getLHS() const { return LHS; }
   const Expr *getRHS() const { return RHS; }
+
+  ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) const {
+    return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS()));
+  }
+
+  ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS,
+                           ExprResult RHS) const {
+    assert((isAnd() || isOr()) && "Not the right kind of op?");
+    assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?");
+
+    if (!LHS.isUsable() || !RHS.isUsable())
+      return ExprEmpty();
+
+    // We should just be able to 'normalize' these to the builtin Binary
+    // Operator, since that is how they are evaluated in constriant checks.
+    return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(),
+                                  BinaryOperator::getOverloadedOpcode(Op),
+                                  SemaRef.Context.BoolTy, VK_PRValue,
+                                  OK_Ordinary, Loc, FPOptionsOverride{});
+  }
 };
 }
 
@@ -122,16 +146,18 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
 }
 
 template <typename AtomicEvaluator>
-static bool
+static ExprResult
 calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
                                 ConstraintSatisfaction &Satisfaction,
                                 AtomicEvaluator &&Evaluator) {
   ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
 
   if (LogicalBinOp BO = ConstraintExpr) {
-    if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction,
-                                        Evaluator))
-      return true;
+    ExprResult LHSRes = calculateConstraintSatisfaction(
+        S, BO.getLHS(), Satisfaction, Evaluator);
+
+    if (LHSRes.isInvalid())
+      return ExprError();
 
     bool IsLHSSatisfied = Satisfaction.IsSatisfied;
 
@@ -142,7 +168,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
       //    is checked. If that is satisfied, the disjunction is satisfied.
       //    Otherwise, the disjunction is satisfied if and only if the second
       //    operand is satisfied.
-      return false;
+      return BO.recreateBinOp(S, LHSRes);
 
     if (BO.isAnd() && !IsLHSSatisfied)
       // [temp.constr.op] p2
@@ -151,12 +177,21 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
       //    is checked. If that is not satisfied, the conjunction is not
       //    satisfied. Otherwise, the conjunction is satisfied if and only if
       //    the second operand is satisfied.
-      return false;
+      return BO.recreateBinOp(S, LHSRes);
 
-    return calculateConstraintSatisfaction(
+    ExprResult RHSRes = calculateConstraintSatisfaction(
         S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
-  } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
-    return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
+    if (RHSRes.isInvalid())
+      return ExprError();
+
+    return BO.recreateBinOp(S, LHSRes, RHSRes);
+  }
+
+  if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
+    // These aren't evaluated, so we don't care about cleanups, so we can just
+    // evaluate these as if the cleanups didn't exist.
+    return calculateConstraintSatisfaction(
+        S, C->getSubExpr(), Satisfaction,
         std::forward<AtomicEvaluator>(Evaluator));
   }
 
@@ -164,11 +199,11 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
   ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
 
   if (SubstitutedAtomicExpr.isInvalid())
-    return true;
+    return ExprError();
 
   if (!SubstitutedAtomicExpr.isUsable())
     // Evaluator has decided satisfaction without yielding an expression.
-    return false;
+    return ExprEmpty();
 
   EnterExpressionEvaluationContext ConstantEvaluated(
       S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
@@ -185,7 +220,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
         << SubstitutedAtomicExpr.get()->getSourceRange();
     for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
       S.Diag(PDiag.first, PDiag.second);
-    return true;
+    return ExprError();
   }
 
   assert(EvalResult.Val.isInt() &&
@@ -195,10 +230,10 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
     Satisfaction.Details.emplace_back(ConstraintExpr,
                                       SubstitutedAtomicExpr.get());
 
-  return false;
+  return SubstitutedAtomicExpr;
 }
 
-static bool calculateConstraintSatisfaction(
+static ExprResult calculateConstraintSatisfaction(
     Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
     const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
     ConstraintSatisfaction &Satisfaction) {
@@ -219,8 +254,8 @@ static bool calculateConstraintSatisfaction(
             return ExprError();
           // We do not want error diagnostics escaping here.
           Sema::SFINAETrap Trap(S);
-          SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr),
-                                              MLTAL);
+          SubstitutedExpression =
+              S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
           // Substitution might have stripped off a contextual conversion to
           // bool if this is the operand of an '&&' or '||'. For example, we
           // might lose an lvalue-to-rvalue conversion here. If so, put it back
@@ -270,6 +305,7 @@ static bool calculateConstraintSatisfaction(
 
 static bool CheckConstraintSatisfaction(
     Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+    llvm::SmallVectorImpl<Expr *> &Converted,
     const MultiLevelTemplateArgumentList &TemplateArgsLists,
     SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
   if (ConstraintExprs.empty()) {
@@ -294,22 +330,30 @@ static bool CheckConstraintSatisfaction(
     return true;
 
   for (const Expr *ConstraintExpr : ConstraintExprs) {
-    if (calculateConstraintSatisfaction(S, Template, TemplateIDRange.getBegin(),
-                                        TemplateArgsLists, ConstraintExpr,
-                                        Satisfaction))
+    ExprResult Res = calculateConstraintSatisfaction(
+        S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
+        ConstraintExpr, Satisfaction);
+    if (Res.isInvalid())
       return true;
-    if (!Satisfaction.IsSatisfied)
+
+    Converted.push_back(Res.get());
+    if (!Satisfaction.IsSatisfied) {
+      // Backfill the 'converted' list with nulls so we can keep the Converted
+      // and unconverted lists in sync.
+      Converted.append(ConstraintExprs.size() - Converted.size(), nullptr);
       // [temp.constr.op] p2
-      //   [...] To determine if a conjunction is satisfied, the satisfaction
-      //   of the first operand is checked. If that is not satisfied, the
-      //   conjunction is not satisfied. [...]
+      // [...] To determine if a conjunction is satisfied, the satisfaction
+      // of the first operand is checked. If that is not satisfied, the
+      // conjunction is not satisfied. [...]
       return false;
+    }
   }
   return false;
 }
 
 bool Sema::CheckConstraintSatisfaction(
     const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+    llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
     const MultiLevelTemplateArgumentList &TemplateArgsLists,
     SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
   if (ConstraintExprs.empty()) {
@@ -317,9 +361,9 @@ bool Sema::CheckConstraintSatisfaction(
     return false;
   }
   if (!Template) {
-    return ::CheckConstraintSatisfaction(*this, nullptr, ConstraintExprs,
-                                         TemplateArgsLists, TemplateIDRange,
-                                         OutSatisfaction);
+    return ::CheckConstraintSatisfaction(
+        *this, nullptr, ConstraintExprs, ConvertedConstraints,
+        TemplateArgsLists, TemplateIDRange, OutSatisfaction);
   }
 
   // A list of the template argument list flattened in a predictible manner for
@@ -340,8 +384,8 @@ bool Sema::CheckConstraintSatisfaction(
   auto Satisfaction =
       std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs);
   if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
-                                    TemplateArgsLists, TemplateIDRange,
-                                    *Satisfaction)) {
+                                    ConvertedConstraints, TemplateArgsLists,
+                                    TemplateIDRange, *Satisfaction)) {
     return true;
   }
   OutSatisfaction = *Satisfaction;
@@ -355,21 +399,120 @@ bool Sema::CheckConstraintSatisfaction(
 bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
                                        ConstraintSatisfaction &Satisfaction) {
   return calculateConstraintSatisfaction(
-      *this, ConstraintExpr, Satisfaction,
-      [this](const Expr *AtomicExpr) -> ExprResult {
-        // We only do this to immitate lvalue-to-rvalue conversion.
-        return PerformContextuallyConvertToBool(const_cast<Expr *>(AtomicExpr));
-      });
+             *this, ConstraintExpr, Satisfaction,
+             [this](const Expr *AtomicExpr) -> ExprResult {
+               // We only do this to immitate lvalue-to-rvalue conversion.
+               return PerformContextuallyConvertToBool(
+                   const_cast<Expr *>(AtomicExpr));
+             })
+      .isInvalid();
+}
+
+bool Sema::SetupConstraintScope(
+    FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
+    MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) {
+  if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
+    FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
+    InstantiatingTemplate Inst(
+        *this, FD->getPointOfInstantiation(),
+        Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
+        TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+        SourceRange());
+    if (Inst.isInvalid())
+      return true;
+
+    // addInstantiatedParametersToScope creates a map of 'uninstantiated' to
+    // 'instantiated' parameters and adds it to the context. For the case where
+    // this function is a template being instantiated NOW, we also need to add
+    // the list of current template arguments to the list so that they also can
+    // be picked out of the map.
+    if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) {
+      MultiLevelTemplateArgumentList JustTemplArgs(*SpecArgs);
+      if (addInstantiatedParametersToScope(
+              FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs))
+        return true;
+    }
+
+    // If this is a member function, make sure we get the parameters that
+    // reference the original primary template.
+    if (const auto *FromMemTempl =
+            PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
+      if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
+                                           Scope, MLTAL))
+        return true;
+    }
+
+    return false;
+  }
+
+  if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
+      FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) {
+    FunctionDecl *InstantiatedFrom =
+        FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization
+            ? FD->getInstantiatedFromMemberFunction()
+            : FD->getInstantiatedFromDecl();
+
+    InstantiatingTemplate Inst(
+        *this, FD->getPointOfInstantiation(),
+        Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
+        TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+        SourceRange());
+    if (Inst.isInvalid())
+      return true;
+
+    // Case where this was not a template, but instantiated as a
+    // child-function.
+    if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL))
+      return true;
+  }
+
+  return false;
+}
+
+// This function collects all of the template arguments for the purposes of
+// constraint-instantiation and checking.
+llvm::Optional<MultiLevelTemplateArgumentList>
+Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
+    FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
+    LocalInstantiationScope &Scope) {
+  MultiLevelTemplateArgumentList MLTAL;
+
+  // Collect the list of template arguments relative to the 'primary' template.
+  // We need the entire list, since the constraint is completely uninstantiated
+  // at this point.
+  MLTAL = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary*/ true,
+                                       /*Pattern*/ nullptr,
+                                       /*LookBeyondLambda*/ true);
+  if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
+    return {};
+
+  return MLTAL;
 }
 
 bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
                                     ConstraintSatisfaction &Satisfaction,
-                                    SourceLocation UsageLoc) {
-  const Expr *RC = FD->getTrailingRequiresClause();
-  if (RC->isInstantiationDependent()) {
+                                    SourceLocation UsageLoc,
+                                    bool ForOverloadResolution) {
+  // Don't check constraints if the function is dependent. Also don't check if
+  // this is a function template specialization, as the call to
+  // CheckinstantiatedFunctionTemplateConstraints after this will check it
+  // better.
+  if (FD->isDependentContext() ||
+      FD->getTemplatedKind() ==
+          FunctionDecl::TK_FunctionTemplateSpecialization) {
     Satisfaction.IsSatisfied = true;
     return false;
   }
+
+  ContextRAII SavedContext{
+      *this, cast<DeclContext>(
+                 const_cast<FunctionDecl *>(FD)->getNonClosureContext())};
+  LocalInstantiationScope Scope(*this, !ForOverloadResolution ||
+                                           isLambdaCallOperator(FD));
+  llvm::Optional<MultiLevelTemplateArgumentList> MLTAL =
+      SetupConstraintCheckingTemplateArgumentsAndScope(
+          const_cast<FunctionDecl *>(FD), {}, Scope);
+
   Qualifiers ThisQuals;
   CXXRecordDecl *Record = nullptr;
   if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
@@ -380,10 +523,23 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
   // We substitute with empty arguments in order to rebuild the atomic
   // constraint in a constant-evaluated context.
   // FIXME: Should this be a dedicated TreeTransform?
-  return CheckConstraintSatisfaction(
-      FD, {RC}, /*TemplateArgs=*/{},
-      SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
-      Satisfaction);
+  const Expr *RC = FD->getTrailingRequiresClause();
+  llvm::SmallVector<Expr *, 1> Converted;
+
+  if (CheckConstraintSatisfaction(
+          FD, {RC}, Converted, *MLTAL,
+          SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
+          Satisfaction))
+    return true;
+
+  // FIXME: we need to do this for the function constraints for
+  // comparison of constraints to work, but do we also need to do it for
+  // CheckInstantiatedFunctionConstraints?  That one is more 
diff icult, but we
+  // seem to always just pick up the constraints from the primary template.
+  assert(Converted.size() <= 1 && "Got more expressions converted?");
+  if (!Converted.empty() && Converted[0] != nullptr)
+    const_cast<FunctionDecl *>(FD)->setTrailingRequiresClause(Converted[0]);
+  return false;
 }
 
 bool Sema::EnsureTemplateArgumentListConstraints(
@@ -432,26 +588,14 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
   // PushDeclContext because we don't have a scope.
   Sema::ContextRAII savedContext(*this, Decl);
   LocalInstantiationScope Scope(*this);
-  MultiLevelTemplateArgumentList MLTAL;
-  // FIXME: This will be replaced with some logic to get all the template
-  // arguments when we switch to deferred template instantiation.
-  MLTAL.addOuterTemplateArguments(TemplateArgs);
-
-  // If this is not an explicit specialization - we need to get the instantiated
-  // version of the template arguments and add them to scope for the
-  // substitution.
-  if (Decl->isTemplateInstantiation()) {
-    InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
-        InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
-        TemplateArgs, SourceRange());
-    if (Inst.isInvalid())
-      return true;
-    MultiLevelTemplateArgumentList MLTAL(
-        *Decl->getTemplateSpecializationArgs());
-    if (addInstantiatedParametersToScope(
-            Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL))
-      return true;
-  }
+
+  Optional<MultiLevelTemplateArgumentList> MLTAL =
+      SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
+                                                       Scope);
+
+  if (!MLTAL)
+    return true;
+
   Qualifiers ThisQuals;
   CXXRecordDecl *Record = nullptr;
   if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
@@ -459,7 +603,8 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
     Record = Method->getParent();
   }
   CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
-  return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
+  llvm::SmallVector<Expr *, 1> Converted;
+  return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
                                      PointOfInstantiation, Satisfaction);
 }
 
@@ -734,22 +879,22 @@ Sema::getNormalizedAssociatedConstraints(
   return CacheEntry->second;
 }
 
-static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
-    ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs,
-    const ASTTemplateArgumentListInfo *ArgsAsWritten) {
+static bool
+substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+                            ConceptDecl *Concept,
+                            const MultiLevelTemplateArgumentList &MLTAL,
+                            const ASTTemplateArgumentListInfo *ArgsAsWritten) {
   if (!N.isAtomic()) {
-    if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs,
+    if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL,
                                     ArgsAsWritten))
       return true;
-    return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs,
+    return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL,
                                        ArgsAsWritten);
   }
   TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
 
   AtomicConstraint &Atomic = *N.getAtomicConstraint();
   TemplateArgumentListInfo SubstArgs;
-  MultiLevelTemplateArgumentList MLTAL;
-  MLTAL.addOuterTemplateArguments(TemplateArgs);
   if (!Atomic.ParameterMapping) {
     llvm::SmallBitVector OccurringIndices(TemplateParams->size());
     S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
@@ -790,6 +935,20 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
   return false;
 }
 
+static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+                                        const ConceptSpecializationExpr *CSE) {
+  TemplateArgumentList TAL{TemplateArgumentList::OnStack,
+                           CSE->getTemplateArguments()};
+  MultiLevelTemplateArgumentList MLTAL =
+      S.getTemplateInstantiationArgs(CSE->getNamedConcept(), &TAL,
+                                     /*RelativeToPrimary*/ true,
+                                     /*Pattern*/ nullptr,
+                                     /*LookBeyondLambda*/ true);
+
+  return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
+                                     CSE->getTemplateArgsAsWritten());
+}
+
 Optional<NormalizedConstraint>
 NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
                                           ArrayRef<const Expr *> E) {
@@ -852,9 +1011,7 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
     Optional<NormalizedConstraint> New;
     New.emplace(S.Context, *SubNF);
 
-    if (substituteParameterMappings(
-            S, *New, CSE->getNamedConcept(),
-            CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten()))
+    if (substituteParameterMappings(S, *New, CSE))
       return None;
 
     return New;

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a2a2e1ed85fc3..48a00f9de671c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -283,7 +283,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
     // definition.
     if (FD->getTrailingRequiresClause()) {
       ConstraintSatisfaction Satisfaction;
-      if (CheckFunctionConstraints(FD, Satisfaction, Loc))
+      if (CheckFunctionConstraints(FD, Satisfaction, Loc,
+                                   /*ForOverloadResolution*/ true))
         // A diagnostic will have already been generated (non-constant
         // constraint expression, for example)
         return true;

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 91e308d0d0fee..623bd288e5023 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -992,6 +992,78 @@ static bool checkArgPlaceholdersForOverload(Sema &S, MultiExprArg Args,
   return false;
 }
 
+// Figure out the to-translation-unit depth for this function declaration for
+// the purpose of seeing if they 
diff er by constraints. This isn't the same as
+// getTemplateDepth, because it includes already instantiated parents.
+static unsigned CalculateTemplateDepthForConstraints(Sema &S,
+                                                     FunctionDecl *FD) {
+  MultiLevelTemplateArgumentList MLTAL =
+      S.getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary*/ true,
+                                     /*Pattern*/ nullptr,
+                                     /*LookBeyondLambda*/ true);
+  return MLTAL.getNumSubstitutedLevels();
+}
+
+// Friend definitions can appear identical but be 
diff erent declarations based
+// on the last sentence of the rule below (others included for clarification):
+// C++20 [temp.friend] p9: A non-template friend declaration
+// with a requires-clause shall be a definition.  A friend function template
+// with a constraint that depends on a template parameter from an enclosing
+// template shall be a definition.  Such a constrained friend function or
+// function template declaration does not declare the same function or function
+// template as a declaration in any other scope.
+static bool FriendsDifferByConstraints(Sema &S, DeclContext *CurContext,
+                                       FunctionDecl *Old, FunctionDecl *New,
+                                       Scope *Scope) {
+  // If these aren't friends, than they aren't friends that 
diff ere by
+  // constraints.
+  if (!Old->getFriendObjectKind() || !New->getFriendObjectKind())
+    return false;
+
+  // If the the two functions share lexical declaration context, they are not in
+  // separate instantations, and thus in the same scope.
+  if (New->getLexicalDeclContext() == Old->getLexicalDeclContext())
+    return false;
+
+  if (!Old->getDescribedFunctionTemplate()) {
+    assert(!New->getDescribedFunctionTemplate() &&
+           "How would these be the same if they aren't both templates?");
+
+    // If these friends don't have constraints, they aren't constrained, and
+    // thus don't fall under temp.friend p9. Else the simple presence of a
+    // constraint makes them unique.
+    return Old->getTrailingRequiresClause();
+  }
+
+  SmallVector<const Expr *, 3> OldAC;
+  Old->getDescribedFunctionTemplate()->getAssociatedConstraints(OldAC);
+
+#ifndef NDEBUG
+  SmallVector<const Expr *, 3> NewAC;
+  New->getDescribedFunctionTemplate()->getAssociatedConstraints(NewAC);
+  assert(OldAC.size() == NewAC.size() &&
+         "Difference should have been noticed earlier if sizes of constraints "
+         "aren't the same");
+#endif
+  // If there are no constraints, these are not constrained friend function or
+  // friend function templates.
+  if (OldAC.size() == 0)
+    return false;
+
+  unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(S, Old);
+
+  // At this point, if the constrained function template declaration depends on
+  // a template parameter from an enclosing template, they are not the same
+  // function.  Since these were deemed identical before we got here, we only
+  // have to look into 1 side to see if they refer to a containing template.
+  for (const Expr *Constraint : OldAC)
+    if (S.ConstraintExpressionDependsOnEnclosingTemplate(OldTemplateDepth,
+                                                         Constraint))
+      return true;
+
+  return false;
+}
+
 /// Determine whether the given New declaration is an overload of the
 /// declarations in Old. This routine returns Ovl_Match or Ovl_NonFunction if
 /// New and Old cannot be overloaded, e.g., if New has the same signature as
@@ -1068,6 +1140,15 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
             !shouldLinkPossiblyHiddenDecl(*I, New))
           continue;
 
+        // C++20 [temp.friend] p9: A non-template friend declaration with a
+        // requires-clause shall be a definition.  A friend function template
+        // with a constraint that depends on a template parameter from an
+        // enclosing template shall be a definition.  Such a constrained friend
+        // function or function template declaration does not declare the same
+        // function or function template as a declaration in any other scope.
+        if (FriendsDifferByConstraints(*this, CurContext, OldF, New, S))
+          continue;
+
         Match = *I;
         return Ovl_Match;
       }
@@ -6515,7 +6596,8 @@ void Sema::AddOverloadCandidate(
 
   if (Function->getTrailingRequiresClause()) {
     ConstraintSatisfaction Satisfaction;
-    if (CheckFunctionConstraints(Function, Satisfaction) ||
+    if (CheckFunctionConstraints(Function, Satisfaction, /*Loc*/ {},
+                                 /*ForOverloadResolution*/ true) ||
         !Satisfaction.IsSatisfied) {
       Candidate.Viable = false;
       Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -7021,7 +7103,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
 
   if (Method->getTrailingRequiresClause()) {
     ConstraintSatisfaction Satisfaction;
-    if (CheckFunctionConstraints(Method, Satisfaction) ||
+    if (CheckFunctionConstraints(Method, Satisfaction, /*Loc*/ {},
+                                 /*ForOverloadResolution*/ true) ||
         !Satisfaction.IsSatisfied) {
       Candidate.Viable = false;
       Candidate.FailureKind = ovl_fail_constraints_not_satisfied;

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1d9c364771927..6bc1a35ee946d 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1686,6 +1686,59 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
   return Param;
 }
 
+namespace {
+class ConstraintRefersToContainingTemplateChecker
+    : public TreeTransform<ConstraintRefersToContainingTemplateChecker> {
+  bool Result = false;
+  unsigned TemplateDepth = 0;
+
+public:
+  using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>;
+
+  ConstraintRefersToContainingTemplateChecker(Sema &SemaRef,
+                                              unsigned TemplateDepth)
+      : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
+  bool getResult() const { return Result; }
+
+  // This should be the only template parm type that we have to deal with.
+  // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and
+  // FunctionParmPackExpr are all partially substituted, which cannot happen
+  // with concepts at this point in translation.
+  QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+                                         TemplateTypeParmTypeLoc TL) {
+    assert(TL.getDecl()->getDepth() <= TemplateDepth &&
+           "Nothing should reference a value below the actual template depth, "
+           "depth is likely wrong");
+    if (TL.getDecl()->getDepth() != TemplateDepth)
+      Result = true;
+    return inherited::TransformTemplateTypeParmType(TLB, TL);
+  }
+
+  Decl *TransformDecl(SourceLocation Loc, Decl *D) {
+    // FIXME : This is possibly an incomplete list, but it is unclear what other
+    // Decl kinds could be used to refer to the template parameters.  This is a
+    // best guess so far based on examples currently available, but the
+    // unreachable should catch future instances/cases.
+    if (auto *TD = dyn_cast<TypedefNameDecl>(D))
+      TransformType(TD->getUnderlyingType());
+    else if (auto *VD = dyn_cast<ValueDecl>(D))
+      TransformType(VD->getType());
+    else if (auto *TD = dyn_cast<TemplateDecl>(D))
+      TransformTemplateParameterList(TD->getTemplateParameters());
+    else
+      llvm_unreachable("Don't know how to handle this declaration type yet");
+    return D;
+  }
+};
+} // namespace
+
+bool Sema::ConstraintExpressionDependsOnEnclosingTemplate(
+    unsigned TemplateDepth, const Expr *Constraint) {
+  ConstraintRefersToContainingTemplateChecker Checker(*this, TemplateDepth);
+  Checker.TransformExpr(const_cast<Expr *>(Constraint));
+  return Checker.getResult();
+}
+
 /// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally
 /// constrained by RequiresClause, that contains the template parameters in
 /// Params.
@@ -2287,7 +2340,8 @@ struct ConvertConstructorToDeductionGuideTransform {
           TTP->isExpandedParameterPack() ?
           llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
       if (const auto *TC = TTP->getTypeConstraint())
-        SemaRef.SubstTypeConstraint(NewTTP, TC, Args);
+        SemaRef.SubstTypeConstraint(NewTTP, TC, Args,
+                                    /*EvaluateConstraint*/ true);
       if (TTP->hasDefaultArgument()) {
         TypeSourceInfo *InstantiatedDefaultArg =
             SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
@@ -5973,10 +6027,12 @@ bool Sema::CheckTemplateArgumentList(
     TemplateArgs = std::move(NewArgs);
 
   if (!PartialTemplateArgs) {
-    // FIXME: This will be changed a bit once deferred concept instantiation is
-    // implemented.
-    MultiLevelTemplateArgumentList MLTAL;
-    MLTAL.addOuterTemplateArguments(Converted);
+    TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
+                                           Converted);
+    MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
+        Template, &StackTemplateArgs, /*RelativeToPrimary*/ true,
+        /*Pattern*/ nullptr,
+        /*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
     if (EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
             SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
@@ -7513,7 +7569,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
       //   are not considered.
       if (ParamsAC.empty())
         return false;
+
       Template->getAssociatedConstraints(TemplateAC);
+
       bool IsParamAtLeastAsConstrained;
       if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
                                  IsParamAtLeastAsConstrained))

diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 99119bcb2e4e6..bddf2c0f69664 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2827,6 +2827,20 @@ template<>
 struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
   static constexpr bool value = true;
 };
+template <typename TemplateDeclT>
+static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
+  return false;
+}
+template <>
+bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>(
+    VarTemplatePartialSpecializationDecl *Spec) {
+  return !Spec->isClassScopeExplicitSpecialization();
+}
+template <>
+bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
+    ClassTemplatePartialSpecializationDecl *Spec) {
+  return !Spec->isClassScopeExplicitSpecialization();
+}
 
 template<typename TemplateDeclT>
 static Sema::TemplateDeductionResult
@@ -2835,13 +2849,25 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
                                 TemplateDeductionInfo& Info) {
   llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
   Template->getAssociatedConstraints(AssociatedConstraints);
-  // FIXME: This will change quite a bit once deferred concept instantiation is
-  // implemented.
   MultiLevelTemplateArgumentList MLTAL;
-  MLTAL.addOuterTemplateArguments(DeducedArgs);
 
-  if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
-                                    MLTAL, Info.getLocation(),
+  bool NeedsReplacement = DeducedArgsNeedReplacement(Template);
+  TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack, DeducedArgs};
+
+  MLTAL = S.getTemplateInstantiationArgs(
+      Template, /*InnerMost*/ NeedsReplacement ? nullptr : &DeducedTAL,
+      /*RelativeToPrimary*/ true, /*Pattern*/
+      nullptr, /*LookBeyondLambda*/ true);
+
+  // getTemplateInstantiationArgs picks up the non-deduced version of the
+  // template args when this is a variable template partial specialization and
+  // not class-scope explicit specialization, so replace with Deduced Args
+  // instead of adding to inner-most.
+  if (NeedsReplacement)
+    MLTAL.replaceInnermostTemplateArguments(DeducedArgs);
+
+  if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
+                                    Info.getLocation(),
                                     Info.AssociatedConstraintsSatisfaction) ||
       !Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
     Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));

diff  --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 1dd4baf901827..44c714c592173 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -57,9 +57,18 @@ using namespace sema;
 /// instantiating the definition of the given declaration, \p D. This is
 /// used to determine the proper set of template instantiation arguments for
 /// friend function template specializations.
+///
+/// \param LookBeyondLambda Indicates that this collection of arguments should
+/// continue looking when it encounters a lambda generic call operator.
+///
+/// \param IncludeContainingStructArgs Indicates that this collection of
+/// arguments should include arguments for any class template that this
+/// declaration is included inside of.
+
 MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
     const NamedDecl *D, const TemplateArgumentList *Innermost,
-    bool RelativeToPrimary, const FunctionDecl *Pattern) {
+    bool RelativeToPrimary, const FunctionDecl *Pattern, bool LookBeyondLambda,
+    bool IncludeContainingStructArgs) {
   // Accumulate the set of template argument lists in this structure.
   MultiLevelTemplateArgumentList Result;
 
@@ -155,11 +164,13 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
           break;
 
         // If this function is a generic lambda specialization, we are done.
-        if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
+        if (!LookBeyondLambda &&
+            isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
           break;
 
       } else if (Function->getDescribedFunctionTemplate()) {
-        assert(Result.getNumSubstitutedLevels() == 0 &&
+        assert((IncludeContainingStructArgs ||
+                Result.getNumSubstitutedLevels() == 0) &&
                "Outer template not instantiated?");
       }
 
@@ -176,10 +187,18 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
       }
     } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
       if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
-        assert(Result.getNumSubstitutedLevels() == 0 &&
+        assert((IncludeContainingStructArgs ||
+                Result.getNumSubstitutedLevels() == 0) &&
                "Outer template not instantiated?");
         if (ClassTemplate->isMemberSpecialization())
           break;
+        if (IncludeContainingStructArgs) {
+          QualType RecordType = Context.getTypeDeclType(Rec);
+          QualType Injected = cast<InjectedClassNameType>(RecordType)
+                                  ->getInjectedSpecializationType();
+          const auto *InjectedType = cast<TemplateSpecializationType>(Injected);
+          Result.addOuterTemplateArguments(InjectedType->template_arguments());
+        }
       }
     }
 
@@ -930,16 +949,23 @@ namespace {
     const MultiLevelTemplateArgumentList &TemplateArgs;
     SourceLocation Loc;
     DeclarationName Entity;
+    bool EvaluateConstraints = true;
 
   public:
     typedef TreeTransform<TemplateInstantiator> inherited;
 
     TemplateInstantiator(Sema &SemaRef,
                          const MultiLevelTemplateArgumentList &TemplateArgs,
-                         SourceLocation Loc,
-                         DeclarationName Entity)
-      : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
-        Entity(Entity) { }
+                         SourceLocation Loc, DeclarationName Entity)
+        : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+          Entity(Entity) {}
+
+    void setEvaluateConstraints(bool B) {
+      EvaluateConstraints = B;
+    }
+    bool getEvaluateConstraints() {
+      return EvaluateConstraints;
+    }
 
     /// Determine whether the given type \p T has already been
     /// transformed.
@@ -1146,7 +1172,9 @@ namespace {
 
     ExprResult TransformLambdaExpr(LambdaExpr *E) {
       LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
-      return inherited::TransformLambdaExpr(E);
+      Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
+      ExprResult Res = inherited::TransformLambdaExpr(E);
+      return Res;
     }
 
     ExprResult TransformRequiresExpr(RequiresExpr *E) {
@@ -1191,6 +1219,7 @@ namespace {
       DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
       TemplateDeclInstantiator  DeclInstantiator(getSema(),
                         /* DeclContext *Owner */ Owner, TemplateArgs);
+      DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
       return DeclInstantiator.SubstTemplateParams(OrigTPL);
     }
 
@@ -1766,9 +1795,9 @@ TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
                                                  int indexAdjustment,
                                                Optional<unsigned> NumExpansions,
                                                  bool ExpectParameterPack) {
-  auto NewParm =
-      SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
-                               NumExpansions, ExpectParameterPack);
+  auto NewParm = SemaRef.SubstParmVarDecl(
+      OldParm, TemplateArgs, indexAdjustment, NumExpansions,
+      ExpectParameterPack, EvaluateConstraints);
   if (NewParm && SemaRef.getLangOpts().OpenCL)
     SemaRef.deduceOpenCLAddressSpace(NewParm);
   return NewParm;
@@ -1986,8 +2015,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
                                         Req, Info, OrigTPL->getSourceRange());
     if (TPLInst.isInvalid())
       return nullptr;
-    TemplateParameterList *TPL =
-        TransformTemplateParameterList(OrigTPL);
+    TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL);
     if (!TPL)
       TransRetReq.emplace(createSubstDiag(SemaRef, Info,
           [&] (llvm::raw_ostream& OS) {
@@ -2197,7 +2225,8 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
                                 SourceLocation Loc,
                                 DeclarationName Entity,
                                 CXXRecordDecl *ThisContext,
-                                Qualifiers ThisTypeQuals) {
+                                Qualifiers ThisTypeQuals,
+                                bool EvaluateConstraints) {
   assert(!CodeSynthesisContexts.empty() &&
          "Cannot perform an instantiation without some context on the "
          "instantiation stack");
@@ -2206,6 +2235,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
     return T;
 
   TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
+  Instantiator.setEvaluateConstraints(EvaluateConstraints);
 
   TypeLocBuilder TLB;
 
@@ -2350,9 +2380,19 @@ namespace {
 
 bool Sema::SubstTypeConstraint(
     TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
-    const MultiLevelTemplateArgumentList &TemplateArgs) {
+    const MultiLevelTemplateArgumentList &TemplateArgs,
+    bool EvaluateConstraints) {
   const ASTTemplateArgumentListInfo *TemplArgInfo =
       TC->getTemplateArgsAsWritten();
+
+  if (!EvaluateConstraints) {
+    Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(),
+                            TC->getConceptNameInfo(), TC->getNamedConcept(),
+                            TC->getNamedConcept(), TemplArgInfo,
+                            TC->getImmediatelyDeclaredConstraint());
+    return false;
+  }
+
   TemplateArgumentListInfo InstArgs;
 
   if (TemplArgInfo) {
@@ -2371,11 +2411,11 @@ bool Sema::SubstTypeConstraint(
           : SourceLocation());
 }
 
-ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
-                            const MultiLevelTemplateArgumentList &TemplateArgs,
-                                    int indexAdjustment,
-                                    Optional<unsigned> NumExpansions,
-                                    bool ExpectParameterPack) {
+ParmVarDecl *
+Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
+                       const MultiLevelTemplateArgumentList &TemplateArgs,
+                       int indexAdjustment, Optional<unsigned> NumExpansions,
+                       bool ExpectParameterPack, bool EvaluateConstraint) {
   TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
   TypeSourceInfo *NewDI = nullptr;
 
@@ -2433,9 +2473,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
       // template's described function, but we might also get here later.
       // Make sure we do not instantiate the TypeConstraint more than once.
       if (Inst && !Inst->getTypeConstraint()) {
-        // TODO: Concepts: do not instantiate the constraint (delayed constraint
-        // substitution)
-        if (SubstTypeConstraint(Inst, TC, TemplateArgs))
+        if (SubstTypeConstraint(Inst, TC, TemplateArgs, EvaluateConstraint))
           return nullptr;
       }
     }
@@ -3522,11 +3560,9 @@ bool Sema::SubstTemplateArguments(
     ArrayRef<TemplateArgumentLoc> Args,
     const MultiLevelTemplateArgumentList &TemplateArgs,
     TemplateArgumentListInfo &Out) {
-  TemplateInstantiator Instantiator(*this, TemplateArgs,
-                                    SourceLocation(),
+  TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
                                     DeclarationName());
-  return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(),
-                                                 Out);
+  return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out);
 }
 
 ExprResult
@@ -3540,11 +3576,23 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
   return Instantiator.TransformExpr(E);
 }
 
+ExprResult
+Sema::SubstConstraintExpr(Expr *E,
+                          const MultiLevelTemplateArgumentList &TemplateArgs) {
+  if (!E)
+    return E;
+
+  // This is where we need to make sure we 'know' constraint checking needs to
+  // happen.
+  TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+                                    DeclarationName());
+  return Instantiator.TransformExpr(E);
+}
+
 ExprResult Sema::SubstInitializer(Expr *Init,
                           const MultiLevelTemplateArgumentList &TemplateArgs,
                           bool CXXDirectInit) {
-  TemplateInstantiator Instantiator(*this, TemplateArgs,
-                                    SourceLocation(),
+  TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
                                     DeclarationName());
   return Instantiator.TransformInitializer(Init, CXXDirectInit);
 }

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 140844ca4e811..7c43aa79ea144 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1823,6 +1823,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
   // merged with the local instantiation scope for the function template
   // itself.
   LocalInstantiationScope Scope(SemaRef);
+  Sema::ConstraintEvalRAII<TemplateDeclInstantiator> RAII(*this);
 
   TemplateParameterList *TempParams = D->getTemplateParameters();
   TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
@@ -2062,19 +2063,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
       return nullptr;
   }
 
-  // FIXME: Concepts: Do not substitute into constraint expressions
   Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
-  if (TrailingRequiresClause) {
-    EnterExpressionEvaluationContext ConstantEvaluated(
-        SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
-    ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
-                                           TemplateArgs);
-    if (SubstRC.isInvalid())
-      return nullptr;
-    TrailingRequiresClause = SubstRC.get();
-    if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
-      return nullptr;
-  }
 
   // If we're instantiating a local function declaration, put the result
   // in the enclosing namespace; otherwise we need to find the instantiated
@@ -2425,23 +2414,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
       return nullptr;
   }
 
-  // FIXME: Concepts: Do not substitute into constraint expressions
-  Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
-  if (TrailingRequiresClause) {
-    EnterExpressionEvaluationContext ConstantEvaluated(
-        SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
-    auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
-    Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext,
-                                     D->getMethodQualifiers(), ThisContext);
-    ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
-                                           TemplateArgs);
-    if (SubstRC.isInvalid())
-      return nullptr;
-    TrailingRequiresClause = SubstRC.get();
-    if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
-      return nullptr;
-  }
-
   DeclContext *DC = Owner;
   if (isFriend) {
     if (QualifierLoc) {
@@ -2459,6 +2431,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     if (!DC) return nullptr;
   }
 
+  CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+  Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+
   DeclarationNameInfo NameInfo
     = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
 
@@ -2466,7 +2441,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
 
   // Build the instantiated method declaration.
-  CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
   CXXMethodDecl *Method = nullptr;
 
   SourceLocation StartLoc = D->getInnerLocStart();
@@ -2771,13 +2745,11 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
   Inst->setImplicit(D->isImplicit());
   if (auto *TC = D->getTypeConstraint()) {
     if (!D->isImplicit()) {
-      // Invented template parameter type constraints will be instantiated with
-      // the corresponding auto-typed parameter as it might reference other
-      // parameters.
-
-      // TODO: Concepts: do not instantiate the constraint (delayed constraint
-      // substitution)
-      if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs))
+      // Invented template parameter type constraints will be instantiated
+      // with the corresponding auto-typed parameter as it might reference
+      // other parameters.
+      if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs,
+                                      EvaluateConstraints))
         return nullptr;
     }
   }
@@ -4021,18 +3993,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
   if (Invalid)
     return nullptr;
 
-  // FIXME: Concepts: Substitution into requires clause should only happen when
-  // checking satisfaction.
-  Expr *InstRequiresClause = nullptr;
-  if (Expr *E = L->getRequiresClause()) {
-    EnterExpressionEvaluationContext ConstantEvaluated(
-        SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
-    ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);
-    if (Res.isInvalid() || !Res.isUsable()) {
-      return nullptr;
-    }
-    InstRequiresClause = Res.get();
-  }
+  Expr *InstRequiresClause = L->getRequiresClause();
 
   TemplateParameterList *InstL
     = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
@@ -4326,11 +4287,9 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
     ThisTypeQuals = Method->getMethodQualifiers();
   }
 
-  TypeSourceInfo *NewTInfo
-    = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs,
-                                    D->getTypeSpecStartLoc(),
-                                    D->getDeclName(),
-                                    ThisContext, ThisTypeQuals);
+  TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType(
+      OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName(),
+      ThisContext, ThisTypeQuals, EvaluateConstraints);
   if (!NewTInfo)
     return nullptr;
 

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index dd684d42665b2..fa7f34c415dc3 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13081,13 +13081,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
                                                         NewCallOpType);
   }
 
-  // Transform the trailing requires clause
-  ExprResult NewTrailingRequiresClause;
-  if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
-    // FIXME: Concepts: Substitution into requires clause should only happen
-    //                  when checking satisfaction.
-    NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
-
   // Create the local class that will describe the lambda.
 
   // FIXME: DependencyKind below is wrong when substituting inside a templated
@@ -13122,7 +13115,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
       E->getCallOperator()->getEndLoc(),
       NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
       E->getCallOperator()->getConstexprKind(),
-      NewTrailingRequiresClause.get());
+      E->getCallOperator()->getTrailingRequiresClause());
 
   LSI->CallOperator = NewCallOperator;
 

diff  --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
index dd6bfe8011ddf..15e00e4481e75 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
@@ -90,3 +90,24 @@ struct D { };
 
 static_assert(C<int>{}); // expected-note{{while checking constraint satisfaction for template 'C<int>' required here}}
 static_assert(D<int>{}); // expected-note{{while checking constraint satisfaction for template 'D<int>' required here}}
+
+// Test the delayed instantiation, the 'foo' implementation shouldn't cause the
+// constraint failure(or crash!) until the use to create 'y'.
+namespace DelayedInst {
+template <unsigned I>
+struct AAA {
+  template <typename T>
+    requires(sizeof(T) == I) // expected-note {{because 'sizeof(int) == 5U' (4 == 5) evaluated to false}}
+  struct B {
+    static constexpr int a = 0;
+  };
+
+  static constexpr auto foo() {
+    return B<int>::a; // expected-error{{constraints not satisfied for class template 'B' [with T = int]}}
+  }
+};
+
+constexpr auto x = AAA<4>::foo();
+constexpr auto y = AAA<5>::foo(); // expected-note {{in instantiation of member function 'DelayedInst::AAA<5>::foo' requested here}}
+
+} // namespace DelayedInst

diff  --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
index ceb5af87b8f02..7772eecc69be8 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
@@ -52,6 +52,30 @@ static_assert(F<unsigned>::value == 2);
 static_assert(F<char[10]>::value == 3);
 static_assert(F<char>::value == 1);
 
+template <unsigned I>
+struct S {
+  template <typename T>
+  struct F {
+    enum { value = 1 };
+  };
+
+  template <typename T>
+    requires C1<T> && C2<T>
+  struct F<T> {
+    enum { value = 2 };
+  };
+
+  template <typename T>
+    requires C1<T> || C2<T>
+  struct F<T> {
+    enum { value = 3 };
+  };
+};
+
+static_assert(S<1>::F<unsigned>::value == 2);
+static_assert(S<1>::F<char[10]>::value == 3);
+static_assert(S<1>::F<char>::value == 1);
+
 // Make sure atomic constraints subsume each other only if their parameter
 // mappings are identical.
 

diff  --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
index 98bfaead773aa..972a4fd0c5c82 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
@@ -51,5 +51,20 @@ static_assert(f<unsigned> == 2);
 static_assert(f<char[10]> == 3);
 static_assert(f<char> == 1);
 
-
-
+template <int I>
+struct S {
+  template <typename T>
+  static constexpr int f = 1;
+
+  template <typename T>
+    requires C1<T> && C2<T>
+  static constexpr int f<T> = 2;
+
+  template <typename T>
+    requires C1<T> || C2<T>
+  static constexpr int f<T> = 3;
+};
+
+static_assert(S<1>::f<unsigned> == 2);
+static_assert(S<1>::f<char[10]> == 3);
+static_assert(S<1>::f<char> == 1);

diff  --git a/clang/test/SemaTemplate/concepts-friends.cpp b/clang/test/SemaTemplate/concepts-friends.cpp
new file mode 100644
index 0000000000000..650376732339e
--- /dev/null
+++ b/clang/test/SemaTemplate/concepts-friends.cpp
@@ -0,0 +1,371 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+template <typename T>
+concept constraint = false;
+namespace temp_friend_9 {
+// A non-template friend declaration with a requires-clause shall be a
+// definition. ...Such a constrained friend function ... does not declare the
+// same function or function template as a declaration in any other scope.
+template <typename T>
+struct NonTemplateFriend {
+  friend void foo()
+    requires true
+  {}
+};
+
+// A friend function template with a constraint that depends on a template
+// parameter from an enclosing template shall be a definition.  Such a ...
+// function template declaration does not declare the same function or
+// function template as a declaration in any other scope.
+template <typename T>
+struct TemplateFromEnclosing {
+  template <typename U>
+  friend void foo()
+    requires constraint<T>
+  {}
+
+  T variable;
+  template <typename U>
+  friend void foo2()
+    requires constraint<decltype(variable)>
+  {}
+
+  template <typename U>
+  friend void foo3(T parmvar)
+    requires constraint<decltype(parmvar)>
+  {}
+
+  template <typename U>
+  friend void foo4()
+    requires requires(T &req) { (void)req; }
+  {}
+
+  using Alias = T;
+  template <typename U>
+  friend void foo5()
+    requires constraint<Alias>
+  {}
+
+  // All of these refer to a parent, so these are not duplicate definitions.
+  struct ChildOfEnclosing {
+    template <typename U>
+    friend void foo6()
+      requires constraint<T>
+    {}
+    template <typename U>
+    friend void foo7()
+      requires constraint<decltype(variable)>
+    {}
+    template <typename U>
+    friend void foo8(T parmvar)
+      requires constraint<decltype(parmvar)>
+    {}
+    // This is NOT a duplicate since it itself is not a template.
+    friend void foo9()
+      requires true
+    {}
+  };
+  template <typename T2>
+  struct TemplChildOfEnclosing {
+    template <typename U>
+    friend void foo10()
+      requires constraint<T>
+    {}
+  };
+};
+
+// Doesn't meet either of the requirements in the above as they don't refer to
+// an enclosing scope.
+template <typename T>
+struct Redefinition {
+  template <typename U>
+  friend void foo() // #REDEF
+    requires constraint<U>
+  {}
+
+  struct ChildOfRedef {
+    template <typename U>
+    friend void foo2() // #REDEF2
+      requires constraint<U>
+    {}
+  };
+  template <typename T2>
+  struct ChildOfRedef2 {
+    template <typename U>
+    friend void foo3() // #REDEF3
+      requires constraint<U>
+    {}
+  };
+};
+
+void bar() {
+  NonTemplateFriend<int> S1;
+  NonTemplateFriend<float> S2;
+  TemplateFromEnclosing<int> S3;
+  TemplateFromEnclosing<int>::ChildOfEnclosing S3b;
+  TemplateFromEnclosing<float> S4;
+  TemplateFromEnclosing<float>::ChildOfEnclosing S4b;
+  Redefinition<int> S5;
+  Redefinition<float> S6;
+  // expected-error@#REDEF {{redefinition of 'foo'}}
+  // expected-note at -2{{in instantiation of template class }}
+  // expected-note@#REDEF {{previous definition is here}}
+  Redefinition<int>::ChildOfRedef S7;
+  Redefinition<float>::ChildOfRedef S8;
+  // expected-error@#REDEF2 {{redefinition of 'foo2'}}
+  // expected-note at -2{{in instantiation of member class }}
+  // expected-note@#REDEF2 {{previous definition is here}}
+
+  Redefinition<int>::ChildOfRedef2<int> S9;
+  Redefinition<float>::ChildOfRedef2<float> S10;
+  // expected-error@#REDEF3 {{redefinition of 'foo3'}}
+  // expected-note at -2{{in instantiation of template class }}
+  // expected-note@#REDEF3 {{previous definition is here}}
+}
+} // namespace temp_friend_9
+
+namespace SameScopeRedefs {
+template <typename T>
+struct NonTemplateFriend {
+  friend void foo() // #NTF1
+    requires true
+  {}
+  friend void foo() // #NTF2
+    requires true
+  {}
+};
+
+template <typename T>
+struct TemplateFromEnclosing {
+  template <typename U>
+  friend void foo() // #TFE1
+    requires constraint<T>
+  {}
+  template <typename U>
+  friend void foo() // #TFE2
+    requires constraint<T>
+  {}
+};
+// Same as above, but doesn't require an instantiation pair to cause.
+template <typename T>
+struct Redefinition {
+  template <typename U>
+  friend void foo() // #RD1
+    requires constraint<U>
+  {}
+  template <typename U>
+  friend void foo() // #RD2
+    requires constraint<U>
+  {}
+};
+void bar() {
+  NonTemplateFriend<int> S1;
+  // expected-error@#NTF2 {{redefinition of 'foo'}}
+  // expected-note at -2{{in instantiation of template class}}
+  // expected-note@#NTF1 {{previous definition is here}}
+
+  TemplateFromEnclosing<int> S2;
+  // expected-error@#TFE2 {{redefinition of 'foo'}}
+  // expected-note at -2{{in instantiation of template class}}
+  // expected-note@#TFE1 {{previous definition is here}}
+
+  Redefinition<int> S3;
+  // expected-error@#RD2 {{redefinition of 'foo'}}
+  // expected-note at -2{{in instantiation of template class}}
+  // expected-note@#RD1 {{previous definition is here}}
+}
+} // namespace SameScopeRedefs
+
+namespace LibCXXOperatorRedef {
+template <typename T, typename U> struct is_same {
+  static constexpr bool value = false;
+};
+template <typename T> struct is_same<T, T> {
+  static constexpr bool value = false;
+};
+
+template <typename T, typename U>
+concept same_as = is_same<T, U>::value;
+
+// An issue found from libcxx when trying to commit the deferred concepts patch.
+// This caused an error of 'redefinition of funcN'.
+template <class _Tp> struct __range_adaptor_closure {
+  template <typename _View, typename _Closure>
+    requires same_as<_Tp, _Closure>
+  friend constexpr decltype(auto) R1func1(_View &&__view,
+                                          _Closure &&__closure){};
+  template <typename _View, typename _Closure>
+  friend constexpr decltype(auto) R1func2(_View &&__view,
+                                          _Closure &&__closure)
+    requires same_as<_Tp, _Closure>
+  {};
+  template <same_as<_Tp> _View, typename _Closure>
+  friend constexpr decltype(auto) R1func3(_View &&__view,
+                                          _Closure &&__closure){};
+};
+
+struct A : __range_adaptor_closure<A> {};
+struct B : __range_adaptor_closure<B> {};
+
+// These three fail because after the 1st pass of instantiation, they are still
+// identical.
+template <class _Tp> struct __range_adaptor_closure2 {
+  template <typename _View, typename _Closure>
+    requires same_as<_View, _Closure>
+  friend constexpr decltype(auto) R2func1(_View &&__view, // #FUNC1
+                                          _Closure &&__closure){};
+  template <typename _View, typename _Closure>
+  friend constexpr decltype(auto) R2func2(_View &&__view, // #FUNC2
+                                          _Closure &&__closure)
+    requires same_as<_View, _Closure>
+  {};
+  template <typename _View, same_as<_View> _Closure>
+  friend constexpr decltype(auto) R2func3(_View &&__view, // #FUNC3
+                                          _Closure &&__closure){};
+};
+
+struct A2 : __range_adaptor_closure2<A2> {};
+struct B2 : __range_adaptor_closure2<B2> {};
+// expected-error@#FUNC1{{redefinition of 'R2func1'}}
+// expected-note at -2{{in instantiation of template class}}
+// expected-note@#FUNC1{{previous definition is here}}
+// expected-error@#FUNC2{{redefinition of 'R2func2'}}
+// expected-note@#FUNC2{{previous definition is here}}
+// expected-error@#FUNC3{{redefinition of 'R2func3'}}
+// expected-note@#FUNC3{{previous definition is here}}
+
+// These three are fine, they all depend on the parent template parameter, so
+// are 
diff erent despite ::type not being valid.
+template <class _Tp> struct __range_adaptor_closure3 {
+  template <typename _View, typename _Closure>
+    requires same_as<typename _Tp::type, _Closure>
+  friend constexpr decltype(auto) R3func1(_View &&__view,
+                                          _Closure &&__closure){};
+  template <typename _View, typename _Closure>
+  friend constexpr decltype(auto) R3func2(_View &&__view,
+                                          _Closure &&__closure)
+    requires same_as<typename _Tp::type, _Closure>
+  {};
+  template <same_as<typename _Tp::type> _View, typename _Closure>
+  friend constexpr decltype(auto) R3func3(_View &&__view,
+                                          _Closure &&__closure){};
+};
+
+struct A3 : __range_adaptor_closure3<A3> {};
+struct B3 : __range_adaptor_closure3<B3> {};
+
+template <class _Tp> struct __range_adaptor_closure4 {
+  template <typename _View, typename _Closure>
+    requires same_as<_Tp, _View>
+  // expected-note at +1{{previous definition is here}}
+  void foo1(_View &&, _Closure &&) {}
+  template <typename _View, typename _Closure>
+    requires same_as<_Tp, _View>
+  // expected-error at +1{{class member cannot be redeclared}}
+  void foo1(_View &&, _Closure &&) {}
+
+  template <typename _View, typename _Closure>
+  // expected-note at +1{{previous definition is here}}
+  void foo2(_View &&, _Closure &&)
+    requires same_as<_Tp, _View>
+  {}
+  template <typename _View, typename _Closure>
+  // expected-error at +1{{class member cannot be redeclared}}
+  void foo2(_View &&, _Closure &&)
+    requires same_as<_Tp, _View>
+  {}
+
+  template <same_as<_Tp> _View, typename _Closure>
+  // expected-note at +1{{previous definition is here}}
+  void foo3(_View &&, _Closure &&) {}
+  template <same_as<_Tp> _View, typename _Closure>
+  // expected-error at +1{{class member cannot be redeclared}}
+  void foo3(_View &&, _Closure &&) {}
+};
+
+// Requires instantiation to fail, so no errors here.
+template <class _Tp> struct __range_adaptor_closure5 {
+  template <same_as<_Tp> U>
+  friend void foo() {}
+  template <same_as<_Tp> U>
+  friend void foo() {}
+};
+
+template <class _Tp> struct __range_adaptor_closure6 {
+  template <same_as<_Tp> U>
+  friend void foo() {} // #RAC6FOO1
+  template <same_as<_Tp> U>
+  friend void foo() {} // #RAC6FOO2
+};
+struct A6 : __range_adaptor_closure6<A6> {};
+// expected-error@#RAC6FOO2{{redefinition of 'foo'}}
+// expected-note at -2{{in instantiation of template class}}
+// expected-note@#RAC6FOO1{{previous definition is here}}
+
+template <class T> struct S1 {
+  template <typename U>
+  friend void dupe() {} // #S1DUPE
+
+  template <typename U>
+    requires same_as<U, U>
+  friend void dupe2() {} // #S1DUPE2
+};
+template <class T> struct S2 {
+  template <typename U>
+  friend void dupe() {} // #S2DUPE
+
+  template <typename U>
+    requires same_as<U, U>
+  friend void dupe2() {} // #S2DUPE2
+};
+
+template <class T> struct S3 {
+  template <typename U>
+    requires same_as<T, U>
+  friend void dupe() {}
+};
+template <class T> struct S4 {
+  template <typename U>
+    requires same_as<T, U>
+  friend void dupe() {}
+};
+
+// Same as S3 and S4, but aren't instantiated with the same T.
+template <class T> struct S5 {
+  template <typename U>
+    requires same_as<T, U>
+  friend void not_dupe() {}
+};
+template <class T> struct S6 {
+  template <typename U>
+    requires same_as<T, U>
+  friend void not_dupe() {}
+};
+
+template <class T> struct S7 {
+  void not_dupe()
+    requires same_as<T, T>
+  {}
+};
+
+void useS() {
+  S1<int> s1;
+  S2<double> s2;
+  // expected-error@#S2DUPE{{redefinition}}
+  // expected-note at -2{{in instantiation of template class}}
+  // expected-note@#S1DUPE{{previous definition is here}}
+  // expected-error@#S2DUPE2{{redefinition}}
+  // expected-note@#S1DUPE2{{previous definition is here}}
+
+  // OK, they have 
diff erent 'scopes'.
+  S3<int> s3;
+  S4<int> s4;
+
+  // OK, because only instantiated with 
diff erent T.
+  S5<int> s5;
+  S6<double> s6;
+
+  S7<int> s7;
+}
+
+} // namespace LibCXXOperatorRedef

diff  --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index 23c79421bb6f8..836ab6f5e0dca 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -256,3 +256,387 @@ C auto **j1 = g();   // expected-error {{deduced type 'int' does not satisfy 'C'
 C auto **&j2 = g();  // expected-error {{deduced type 'int' does not satisfy 'C'}}
 C auto **&&j3 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}}
 }
+
+namespace SubConstraintChecks {
+template <typename T>
+concept TrueConstraint = true;
+template <typename T>
+concept FalseConstraint = false;
+
+template <typename T, typename... Us>
+class ContainsConstrainedFuncTrue {
+public:
+  template <typename V, TrueConstraint Constrained>
+  static void func(V &&, Constrained &&C);
+};
+template <typename T, typename... Us>
+class ContainsConstrainedFuncFalse {
+public:
+  template <typename V, FalseConstraint Constrained>
+  static void func(V &&, Constrained &&C);
+};
+
+template <typename... Us>
+concept TrueConstraint2 =
+    requires(float &&t) {
+      ContainsConstrainedFuncTrue<float, Us...>::func(5, 0.0);
+    };
+template <typename... Us>
+concept FalseConstraint2 =
+    requires(float &&t) {
+      ContainsConstrainedFuncFalse<float, Us...>::func(5, 0.0); // #FC2_CONSTR
+    };
+
+template <typename T>
+void useTrue(int F)
+  requires TrueConstraint2<int>
+{}
+
+template <typename T>
+void useFalse(int F)             // #USE_FALSE
+  requires FalseConstraint2<int> // #USE_FALSE_CONSTR
+{}
+
+// Should only diagnose 'false' once instantiated.
+void UseUse() {
+  useTrue<int>(5);
+  useFalse<int>(5);
+  // expected-error at -1{{no matching function for call to 'useFalse'}}
+  // expected-note@#USE_FALSE{{constraints not satisfied}}
+  // expected-note@#USE_FALSE_CONSTR{{because 'int' does not satisfy 'FalseConstraint2'}}
+  // expected-note@#FC2_CONSTR {{would be invalid: no matching function for call to 'func'}}
+}
+} // namespace SubConstraintChecks
+
+namespace DeducedTemplateArgs {
+template <typename Itr> struct ItrTraits {
+  template <typename PtrItr> struct Ptr {
+  };
+  template <typename PtrItr>
+    requires requires { typename PtrItr::pointer; }
+  struct Ptr<PtrItr> {
+    using type = typename Itr::pointer;
+  };
+  using pointer = typename Ptr<Itr>::type; // #TRAITS_PTR
+};
+
+struct complete_itr {
+  using pointer = int;
+};
+
+template <typename T> class Complete {
+  using ItrType = ItrTraits<complete_itr>;
+  ItrType begin() noexcept { return ItrType(); }
+};
+
+// This version doesn't have 'pointer', so error confirms we are in the first
+// verison of 'Ptr'.
+struct not_complete_itr {
+};
+
+template <typename T> class NotComplete {
+  using ItrType = ItrTraits<not_complete_itr>;
+  ItrType begin() noexcept { return ItrType(); }
+  // expected-error@#TRAITS_PTR{{no type named 'type' in }}
+  // expected-note at -2{{in instantiation of template class }}
+};
+} // namespace DeducedTemplateArgs
+
+namespace DeferredInstantiationInstScope {
+template <typename T>
+struct remove_ref {
+  using type = T;
+};
+template <typename T>
+struct remove_ref<T &> {
+  using type = T;
+};
+template <typename T>
+struct remove_ref<T &&> {
+  using type = T;
+};
+
+template <typename T>
+constexpr bool IsInt = PR54443::is_same<typename remove_ref<T>::type,
+                                        int>::value;
+
+template <typename U>
+void SingleDepthReferencesTop(U &&u) {
+  struct lc {
+    void operator()()             // #SDRT_OP
+      requires IsInt<decltype(u)> // #SDRT_REQ
+    {}
+  };
+  lc lv;
+  lv(); // #SDRT_CALL
+}
+
+template <typename U>
+void SingleDepthReferencesTopNotCalled(U &&u) {
+  struct lc {
+    void operator()()
+      requires IsInt<typename decltype(u)::FOO>
+    {}
+  };
+  lc lv;
+}
+
+template <typename U>
+void SingleDepthReferencesTopCalled(U &&u) {
+  struct lc {
+    void operator()()                           // #CALLOP
+      requires IsInt<typename decltype(u)::FOO> // #CONSTR
+    {}
+  };
+  lc lv;
+  lv();
+  // expected-error at -1{{no matching function for call to object of type 'lc'}}
+  // expected-note@#SDRTC{{in instantiation of function template}}
+  // expected-note@#CALLOP{{constraints not satisfied}}
+  // expected-note@#CONSTR{{substituted constraint expression is ill-formed}}
+}
+
+template <typename U>
+void SingleDepthReferencesTopLambda(U &&u) {
+  []()
+    requires IsInt<decltype(u)>
+  {}();
+}
+
+template <typename U>
+void DoubleDepthReferencesTop(U &&u) {
+  struct lc { // #DDRT_STRCT
+    void operator()() {
+      struct lc2 {
+        void operator()()             // #DDRT_OP
+          requires IsInt<decltype(u)> // #DDRT_REQ
+        {}
+      };
+      lc2 lv2;
+      lv2(); // #DDRT_CALL
+    }
+  };
+  lc lv;
+  lv();
+}
+
+template <typename U>
+void DoubleDepthReferencesTopLambda(U &&u) {
+  []() { []()
+           requires IsInt<decltype(u)>
+         {}(); }();
+}
+
+template <typename U>
+void DoubleDepthReferencesAll(U &&u) {
+  struct lc { // #DDRA_STRCT
+    void operator()(U &&u2) {
+      struct lc2 {
+        void operator()(U &&u3)          // #DDRA_OP
+          requires IsInt<decltype(u)> && // #DDRA_REQ
+                   IsInt<decltype(u2)> && IsInt<decltype(u3)>
+        {}
+      };
+      lc2 lv2;
+      lv2(u2); // #DDRA_CALL
+    }
+  };
+  lc lv;
+  lv(u);
+}
+
+template <typename U>
+void DoubleDepthReferencesAllLambda(U &&u) {
+  [](U &&u2) {
+    [](U && u3)
+      requires IsInt<decltype(u)> &&
+               IsInt<decltype(u2)> && IsInt<decltype(u3)>
+    {}(u2);
+  }(u);
+}
+
+template <typename U>
+struct CausesFriendConstraint {
+  template <typename V>
+  friend void FriendFunc(CausesFriendConstraint, V) // #FF_DECL
+    requires IsInt<U> &&
+             IsInt<V> // #FF_REQ
+  {}
+};
+// FIXME: Re-enable this test when constraints are allowed to refer to captures.
+// template<typename T>
+// void ChecksCapture(T x) {
+//   [y = x]() requires(IsInt<decltype(y)>){}();
+// }
+
+template <typename T>
+void ChecksLocalVar(T x) {
+  T Local;
+  []()
+    requires(IsInt<decltype(Local)>)
+  {}();
+}
+
+template <typename T>
+void LocalStructMemberVar(T x) {
+  struct S {
+    T local;
+    void foo()
+      requires(IsInt<decltype(local)>) // #LSMV_REQ
+    {}
+  } s;
+  s.foo(); // #LSMV_CALL
+};
+
+template <typename T>
+struct ChecksMemberVar {
+  T t;
+  void foo()
+    requires(IsInt<decltype(t)>) // #CMV_FOO
+  {}
+  template <typename U>
+  void foo2()                    // #CMV_FOO2
+    requires(IsInt<decltype(t)>) // #CMV_FOO2_REQ
+  {}
+};
+
+void test_dependent() {
+  int v = 0;
+  float will_fail;
+  SingleDepthReferencesTop(v);
+  SingleDepthReferencesTop(will_fail);
+  // expected-error@#SDRT_CALL{{no matching function for call to object of type 'lc'}}
+  // expected-note at -2{{in instantiation of function template specialization}}
+  // expected-note@#SDRT_OP{{candidate function not viable}}
+  // expected-note@#SDRT_REQ{{'IsInt<decltype(u)>' evaluated to false}}
+
+  SingleDepthReferencesTopNotCalled(v);
+  // Won't error unless we try to call it.
+  SingleDepthReferencesTopNotCalled(will_fail);
+  SingleDepthReferencesTopCalled(v); // #SDRTC
+  SingleDepthReferencesTopLambda(v);
+  // FIXME: This should error on constraint failure! (Lambda!)
+  SingleDepthReferencesTopLambda(will_fail);
+  DoubleDepthReferencesTop(v);
+  DoubleDepthReferencesTop(will_fail);
+  // expected-error@#DDRT_CALL{{no matching function for call to object of type 'lc2'}}
+  // expected-note at -2{{in instantiation of function template specialization}}
+  // expected-note@#DDRT_STRCT{{in instantiation of member function}}
+  // expected-note@#DDRT_OP{{candidate function not viable}}
+  // expected-note@#DDRT_REQ{{'IsInt<decltype(u)>' evaluated to false}}
+
+  DoubleDepthReferencesTopLambda(v);
+  // FIXME: This should error on constraint failure! (Lambda!)
+  DoubleDepthReferencesTopLambda(will_fail);
+  DoubleDepthReferencesAll(v);
+  DoubleDepthReferencesAll(will_fail);
+  // expected-error@#DDRA_CALL{{no matching function for call to object of type 'lc2'}}
+  // expected-note at -2{{in instantiation of function template specialization}}
+  // expected-note@#DDRA_STRCT{{in instantiation of member function}}
+  // expected-note@#DDRA_OP{{candidate function not viable}}
+  // expected-note@#DDRA_REQ{{'IsInt<decltype(u)>' evaluated to false}}
+
+  DoubleDepthReferencesAllLambda(v);
+  // FIXME: This should error on constraint failure! (Lambda!)
+  DoubleDepthReferencesAllLambda(will_fail);
+
+  CausesFriendConstraint<int> CFC;
+  FriendFunc(CFC, 1);
+  FriendFunc(CFC, 1.0);
+  // expected-error at -1{{no matching function for call to 'FriendFunc'}}
+  // expected-note@#FF_DECL{{constraints not satisfied}}
+  // expected-note@#FF_REQ{{because 'IsInt<double>' evaluated to false}}
+
+  // FIXME: Re-enable this test when constraints are allowed to refer to captures.
+  // ChecksCapture(v);
+
+  ChecksLocalVar(v);
+  // FIXME: This should error on constraint failure! (Lambda!)
+  ChecksLocalVar(will_fail);
+
+  LocalStructMemberVar(v);
+  LocalStructMemberVar(will_fail);
+  // expected-error@#LSMV_CALL{{invalid reference to function 'foo'}}
+  // expected-note at -2{{in instantiation of function template specialization}}
+  // expected-note@#LSMV_REQ{{because 'IsInt<decltype(this->local)>' evaluated to false}}
+
+  ChecksMemberVar<int> CMV;
+  CMV.foo();
+  CMV.foo2<int>();
+
+  ChecksMemberVar<float> CMV2;
+  CMV2.foo();
+  // expected-error at -1{{invalid reference to function 'foo'}}
+  // expected-note@#CMV_FOO{{because 'IsInt<decltype(this->t)>' evaluated to false}}
+  CMV2.foo2<float>();
+  // expected-error at -1{{no matching member function for call to 'foo2'}}
+  // expected-note@#CMV_FOO2{{constraints not satisfied}}
+  // expected-note@#CMV_FOO2_REQ{{because 'IsInt<decltype(this->t)>' evaluated to false}}
+}
+} // namespace DeferredInstantiationInstScope
+
+// Ane example of evaluating a concept at two 
diff erent depths in the same
+// evaluation.  No diagnostic is expected.
+namespace SameConceptDifferentDepth {
+template <class _Ip>
+concept sentinel_for =
+    requires(_Ip __i) {
+      __i++;
+    };
+
+template <class _Ip>
+concept bidirectional_iterator =
+    sentinel_for<_Ip>;
+
+template <class _Iter>
+class move_iterator {
+public:
+  auto operator++(int)
+    requires sentinel_for<_Iter>{}
+};
+
+static_assert(bidirectional_iterator<move_iterator<int>>);
+} // namespace SameConceptDifferentDepth
+
+namespace VarInit {
+template <class _Tp>
+concept __can_reference = true;
+
+template <class _Iter>
+class common_iterator {
+public:
+  common_iterator() {
+    constexpr auto x = requires(_Iter & __i) { { __i } -> __can_reference; };
+  }
+};
+
+void test() {
+  auto commonIter1 = common_iterator<int>();
+}
+} // namespace VarInit
+
+
+namespace InlineFriendOperator {
+template <typename T>
+concept C = true;
+template <class _Iter>
+class counted_iterator {
+  _Iter I;
+public:
+  constexpr counted_iterator() = default;
+  friend constexpr auto operator+( // expected-note {{candidate function not viable}}
+      int __n, const counted_iterator &__x)
+    requires C<decltype(I)>
+  {
+    return __x + __n; // expected-error{{invalid operands to binary expression}}
+  }
+};
+
+constexpr bool test() {
+  counted_iterator<int> iter;
+  auto x = 2 + iter; // expected-note{{in instantiation of member function 'InlineFriendOperator::operator+'}}
+
+  return true;
+}
+} // namespace InlineFriendOperator
+

diff  --git a/clang/test/SemaTemplate/deferred-concept-inst.cpp b/clang/test/SemaTemplate/deferred-concept-inst.cpp
new file mode 100644
index 0000000000000..dd9a4086a42ed
--- /dev/null
+++ b/clang/test/SemaTemplate/deferred-concept-inst.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify -fsyntax-only -Wno-unused-value
+// expected-no-diagnostics
+
+namespace GithubBug44178 {
+template <typename D>
+struct CRTP {
+  void call_foo()
+    requires requires(D &v) { v.foo(); }
+  {
+    static_cast<D *>(this)->foo();
+  }
+};
+
+struct Test : public CRTP<Test> {
+  void foo() {}
+};
+
+int main() {
+  Test t;
+  t.call_foo();
+  return 0;
+}
+} // namespace GithubBug44178

diff  --git a/clang/test/SemaTemplate/instantiate-requires-clause.cpp b/clang/test/SemaTemplate/instantiate-requires-clause.cpp
index 73dd20d27d226..3f438d8885a20 100644
--- a/clang/test/SemaTemplate/instantiate-requires-clause.cpp
+++ b/clang/test/SemaTemplate/instantiate-requires-clause.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
+// RUN: %clang_cc1 -std=c++2a -x c++ %s -Wno-unused-value -verify
 
 template <typename... Args> requires ((sizeof(Args) == 1), ...)
 // expected-note at -1 {{because '(sizeof(int) == 1) , (sizeof(char) == 1) , (sizeof(int) == 1)' evaluated to false}}
@@ -40,6 +40,20 @@ struct S {
 
 static_assert(S<void>::f(1));
 
+// Similar to the 'S' test, but tries to use 'U' in the requires clause.
+template <typename T2>
+struct S1 {
+  // expected-note at +3 {{candidate template ignored: constraints not satisfied [with U = int]}}
+  // expected-note at +3 {{because substituted constraint expression is ill-formed: type 'int' cannot be used prior to '::' because it has no members}}
+  template <typename U>
+  static constexpr auto f(U const index)
+    requires(U::foo)
+  { return true; }
+};
+
+// expected-error at +1 {{no matching function for call to 'f'}}
+static_assert(S1<void>::f(1));
+
 constexpr auto value = 0;
 
 template<typename T>

diff  --git a/clang/test/SemaTemplate/trailing-return-short-circuit.cpp b/clang/test/SemaTemplate/trailing-return-short-circuit.cpp
new file mode 100644
index 0000000000000..0d1c9b52b0e85
--- /dev/null
+++ b/clang/test/SemaTemplate/trailing-return-short-circuit.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+template <class T>
+  requires(sizeof(T) > 2) || T::value // #FOO_REQ
+void Foo(T){};                        // #FOO
+
+template <class T>
+void TrailingReturn(T)       // #TRAILING
+  requires(sizeof(T) > 2) || // #TRAILING_REQ
+          T::value           // #TRAILING_REQ_VAL
+{};
+template <bool B>
+struct HasValue {
+  static constexpr bool value = B;
+};
+static_assert(sizeof(HasValue<true>) <= 2);
+
+template <bool B>
+struct HasValueLarge {
+  static constexpr bool value = B;
+  int I;
+};
+static_assert(sizeof(HasValueLarge<true>) > 2);
+
+void usage() {
+  // Passes the 1st check, short-circuit so the 2nd ::value is not evaluated.
+  Foo(1.0);
+  TrailingReturn(1.0);
+
+  // Fails the 1st check, but has a ::value, so the check happens correctly.
+  Foo(HasValue<true>{});
+  TrailingReturn(HasValue<true>{});
+
+  // Passes the 1st check, but would have passed the 2nd one.
+  Foo(HasValueLarge<true>{});
+  TrailingReturn(HasValueLarge<true>{});
+
+  // Fails the 1st check, fails 2nd because there is no ::value.
+  Foo(true);
+  // expected-error at -1{{no matching function for call to 'Foo'}}
+  // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = bool]}}
+  // expected-note@#FOO_REQ{{because 'sizeof(_Bool) > 2' (1 > 2) evaluated to false}}
+  // expected-note@#FOO_REQ{{because substituted constraint expression is ill-formed: type 'bool' cannot be used prior to '::' because it has no members}}
+
+  TrailingReturn(true);
+  // expected-error at -1{{no matching function for call to 'TrailingReturn'}}
+  // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = bool]}}
+  // expected-note@#TRAILING_REQ{{because 'sizeof(_Bool) > 2' (1 > 2) evaluated to false}}
+  // expected-note@#TRAILING_REQ_VAL{{because substituted constraint expression is ill-formed: type 'bool' cannot be used prior to '::' because it has no members}}
+
+  // Fails the 1st check, fails 2nd because ::value is false.
+  Foo(HasValue<false>{});
+  // expected-error at -1 {{no matching function for call to 'Foo'}}
+  // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = HasValue<false>]}}
+  // expected-note@#FOO_REQ{{because 'sizeof(HasValue<false>) > 2' (1 > 2) evaluated to false}}
+  // expected-note@#FOO_REQ{{and 'HasValue<false>::value' evaluated to false}}
+  TrailingReturn(HasValue<false>{});
+  // expected-error at -1 {{no matching function for call to 'TrailingReturn'}}
+  // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = HasValue<false>]}}
+  // expected-note@#TRAILING_REQ{{because 'sizeof(HasValue<false>) > 2' (1 > 2) evaluated to false}}
+  // expected-note@#TRAILING_REQ_VAL{{and 'HasValue<false>::value' evaluated to false}}
+}


        


More information about the cfe-commits mailing list