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

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 22 06:29:57 PDT 2022


Author: Erich Keane
Date: 2022-09-22T05:53:59-07:00
New Revision: babdef27c503c0bbbcc017e9f88affddda90ea4e

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

LOG: Re-apply "Deferred Concept Instantiation Implementation"

This reverts commit 95d94a67755620c0a2871ac6f056ca8e9731d5e9.

This implements the deferred concepts instantiation, which should allow
the libstdc++ ranges to properly compile, and for the CRTP to work for
constrained functions.

Since the last attempt, this has fixed the issues from @wlei and
@mordante.

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

Added: 
    clang/test/Modules/concept_serialization.cpp
    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/AST/ASTContext.h
    clang/include/clang/AST/Decl.h
    clang/include/clang/AST/DeclBase.h
    clang/include/clang/Sema/Sema.h
    clang/include/clang/Sema/Template.h
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/ASTImporter.cpp
    clang/lib/AST/Decl.cpp
    clang/lib/Sema/SemaConcept.cpp
    clang/lib/Sema/SemaDecl.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/lib/Serialization/ASTReaderDecl.cpp
    clang/lib/Serialization/ASTReaderStmt.cpp
    clang/lib/Serialization/ASTWriterDecl.cpp
    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/SemaCXX/constrained-special-member-functions.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 d2b3e7d944c95..a208af832c7be 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -345,6 +345,10 @@ C++20 Feature Support
   `Issue 50455 <https://github.com/llvm/llvm-project/issues/50455>`_,
   `Issue 54872 <https://github.com/llvm/llvm-project/issues/54872>`_,
   `Issue 54587 <https://github.com/llvm/llvm-project/issues/54587>`_.
+- 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>`_.
 
 C++2b Feature Support
 ^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 399724159a289..fb68842a34be4 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2669,6 +2669,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// template.
   bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
 
+  /// Determine whether two Friend functions are 
diff erent because constraints
+  /// that refer to an enclosing template, according to [temp.friend] p9.
+  bool FriendsDifferByConstraints(const FunctionDecl *X,
+                                  const FunctionDecl *Y) const;
+
   /// Determine whether the two declarations refer to the same entity.
   bool isSameEntity(const NamedDecl *X, const NamedDecl *Y) const;
 

diff  --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 4a33b939aba51..3ff2e2633f4d5 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2474,6 +2474,19 @@ class FunctionDecl : public DeclaratorDecl,
     getCanonicalDecl()->FunctionDeclBits.IsMultiVersion = V;
   }
 
+  // Sets that this is a constrained friend where the constraint refers to an
+  // enclosing template.
+  void setFriendConstraintRefersToEnclosingTemplate(bool V = true) {
+    getCanonicalDecl()
+        ->FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate = V;
+  }
+  // Indicates this function is a constrained friend, where the constraint
+  // refers to an enclosing template for hte purposes of [temp.friend]p9.
+  bool FriendConstraintRefersToEnclosingTemplate() const {
+    return getCanonicalDecl()
+        ->FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate;
+  }
+
   /// Gets the kind of multiversioning attribute this declaration has. Note that
   /// this can return a value even if the function is not multiversion, such as
   /// the case of 'target'.

diff  --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 328d28c08bcce..ffc360fa65868 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -1664,10 +1664,14 @@ class DeclContext {
 
     /// Indicates if the function uses Floating Point Constrained Intrinsics
     uint64_t UsesFPIntrin : 1;
+
+    // Indicates this function is a constrained friend, where the constraint
+    // refers to an enclosing template for hte purposes of [temp.friend]p9.
+    uint64_t FriendConstraintRefersToEnclosingTemplate : 1;
   };
 
   /// Number of non-inherited bits in FunctionDeclBitfields.
-  enum { NumFunctionDeclBits = 28 };
+  enum { NumFunctionDeclBits = 29 };
 
   /// Stores the bits used by CXXConstructorDecl. If modified
   /// NumCXXConstructorDeclBits and the accessor
@@ -1679,12 +1683,12 @@ class DeclContext {
     /// For the bits in FunctionDeclBitfields.
     uint64_t : NumFunctionDeclBits;
 
-    /// 23 bits to fit in the remaining available space.
+    /// 22 bits to fit in the remaining available space.
     /// Note that this makes CXXConstructorDeclBitfields take
     /// exactly 64 bits and thus the width of NumCtorInitializers
     /// will need to be shrunk if some bit is added to NumDeclContextBitfields,
     /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields.
-    uint64_t NumCtorInitializers : 20;
+    uint64_t NumCtorInitializers : 19;
     uint64_t IsInheritingConstructor : 1;
 
     /// Whether this constructor has a trail-allocated explicit specifier.

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 870fe5e88ed3d..8628ed48481f2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3673,6 +3673,31 @@ 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);
+
+  // Calculates whether the friend function depends on an enclosing template for
+  // the purposes of [temp.friend] p9.
+  bool FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD);
+
+  // Calculates whether two constraint expressions are equal irrespective of a
+  // 
diff erence in 'depth'. This takes a pair of optional 'NamedDecl's 'Old' and
+  // 'New', which are the "source" of the constraint, since this is necessary
+  // for figuring out the relative 'depth' of the constraint. The depth of the
+  // 'primary template' and the 'instantiated from' templates aren't necessarily
+  // the same, such as a case when one is a 'friend' defined in a class.
+  bool AreConstraintExpressionsEqual(const NamedDecl *Old,
+                                     const Expr *OldConstr,
+                                     const NamedDecl *New,
+                                     const Expr *NewConstr);
+
   enum class AllowedExplicit {
     /// Allow no explicit functions to be used.
     None,
@@ -7152,6 +7177,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(
@@ -7194,6 +7234,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
@@ -7213,8 +7286,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.
@@ -8222,12 +8295,19 @@ class Sema final {
     TPL_TemplateTemplateArgumentMatch
   };
 
-  bool TemplateParameterListsAreEqual(TemplateParameterList *New,
-                                      TemplateParameterList *Old,
-                                      bool Complain,
-                                      TemplateParameterListEqualKind Kind,
-                                      SourceLocation TemplateArgLoc
-                                        = SourceLocation());
+  bool TemplateParameterListsAreEqual(
+      const NamedDecl *NewInstFrom, TemplateParameterList *New,
+      const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+      TemplateParameterListEqualKind Kind,
+      SourceLocation TemplateArgLoc = SourceLocation());
+
+  bool TemplateParameterListsAreEqual(
+      TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
+      TemplateParameterListEqualKind Kind,
+      SourceLocation TemplateArgLoc = SourceLocation()) {
+    return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain,
+                                          Kind, TemplateArgLoc);
+  }
 
   bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams);
 
@@ -8962,7 +9042,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
@@ -9670,23 +9751,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,
@@ -9696,6 +9775,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.
   ///
@@ -9725,7 +9823,6 @@ class Sema final {
                          const MultiLevelTemplateArgumentList &TemplateArgs,
                          TemplateArgumentListInfo &Outputs);
 
-
   Decl *SubstDecl(Decl *D, DeclContext *Owner,
                   const MultiLevelTemplateArgumentList &TemplateArgs);
 
@@ -9816,7 +9913,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/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index d9811ce19eb6c..1a15292c12d3e 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6452,6 +6452,31 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
   return true;
 }
 
+bool ASTContext::FriendsDifferByConstraints(const FunctionDecl *X,
+                                            const FunctionDecl *Y) const {
+  // If these aren't friends, then they aren't friends that 
diff er by
+  // constraints.
+  if (!X->getFriendObjectKind() || !Y->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 (X->getLexicalDeclContext() == Y->getLexicalDeclContext())
+    return false;
+
+  if (!X->getDescribedFunctionTemplate()) {
+    assert(!Y->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 X->getTrailingRequiresClause();
+  }
+
+  return X->FriendConstraintRefersToEnclosingTemplate();
+}
+
 bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
   if (X == Y)
     return true;
@@ -6532,6 +6557,10 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
                               FuncY->getTrailingRequiresClause()))
       return false;
 
+    // Constrained friends are 
diff erent in certain cases, see: [temp.friend]p9.
+    if (FriendsDifferByConstraints(FuncX, FuncY))
+      return false;
+
     auto GetTypeAsWritten = [](const FunctionDecl *FD) {
       // Map to the first declaration that we've already merged into this one.
       // The TSI of redeclarations might not match (due to calling conventions

diff  --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index f0ba8c91db446..31a2efdc24003 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3701,6 +3701,8 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
   ToFunction->setDefaulted(D->isDefaulted());
   ToFunction->setExplicitlyDefaulted(D->isExplicitlyDefaulted());
   ToFunction->setDeletedAsWritten(D->isDeletedAsWritten());
+  ToFunction->setFriendConstraintRefersToEnclosingTemplate(
+      D->FriendConstraintRefersToEnclosingTemplate());
   ToFunction->setRangeEnd(ToEndLoc);
 
   // Set the parameters.

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 47da043b0ad99..4236c39401ef4 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2970,6 +2970,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
   FunctionDeclBits.IsMultiVersion = false;
   FunctionDeclBits.IsCopyDeductionCandidate = false;
   FunctionDeclBits.HasODRHash = false;
+  FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate = false;
   if (TrailingRequiresClause)
     setTrailingRequiresClause(TrailingRequiresClause);
 }

diff  --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 7545b7974ce49..614c9b8b05aa3 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "TreeTransform.h"
 #include "clang/Sema/SemaConcept.h"
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaInternal.h"
@@ -18,6 +19,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 +32,7 @@ using namespace sema;
 
 namespace {
 class LogicalBinOp {
+  SourceLocation Loc;
   OverloadedOperatorKind Op = OO_None;
   const Expr *LHS = nullptr;
   const Expr *RHS = nullptr;
@@ -40,12 +43,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 +61,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 +147,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 +169,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 +178,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 +200,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 +221,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 +231,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 +255,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 +306,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 +331,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 +362,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 +385,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 +400,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 +524,112 @@ 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;
+}
+
+
+// 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,
+                                                     const NamedDecl *ND) {
+  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+      ND, nullptr, /*RelativeToPrimary*/ true,
+      /*Pattern*/ nullptr,
+      /*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
+  return MLTAL.getNumSubstitutedLevels();
+}
+
+namespace {
+  class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
+  unsigned TemplateDepth = 0;
+  public:
+  using inherited = TreeTransform<AdjustConstraintDepth>;
+  AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
+      : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
+  QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+                                         TemplateTypeParmTypeLoc TL) {
+    const TemplateTypeParmType *T = TL.getTypePtr();
+
+    TemplateTypeParmDecl *NewTTPDecl = nullptr;
+    if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
+      NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
+          TransformDecl(TL.getNameLoc(), OldTTPDecl));
+
+    QualType Result = getSema().Context.getTemplateTypeParmType(
+        T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
+        NewTTPDecl);
+    TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+    NewTL.setNameLoc(TL.getNameLoc());
+    return Result;
+  }
+  };
+} // namespace
+
+bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
+                                         const Expr *OldConstr,
+                                         const NamedDecl *New,
+                                         const Expr *NewConstr) {
+  if (Old && New && Old != New) {
+    unsigned Depth1 = CalculateTemplateDepthForConstraints(
+        *this, Old);
+    unsigned Depth2 = CalculateTemplateDepthForConstraints(
+        *this, New);
+
+    // Adjust the 'shallowest' verison of this to increase the depth to match
+    // the 'other'.
+    if (Depth2 > Depth1) {
+      OldConstr = AdjustConstraintDepth(*this, Depth2 - Depth1)
+                      .TransformExpr(const_cast<Expr *>(OldConstr))
+                      .get();
+    } else if (Depth1 > Depth2) {
+      NewConstr = AdjustConstraintDepth(*this, Depth1 - Depth2)
+                      .TransformExpr(const_cast<Expr *>(NewConstr))
+                      .get();
+    }
+  }
+
+  llvm::FoldingSetNodeID ID1, ID2;
+  OldConstr->Profile(ID1, Context, /*Canonical=*/true);
+  NewConstr->Profile(ID2, Context, /*Canonical=*/true);
+  return ID1 == ID2;
+}
+
+bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
+  assert(FD->getFriendObjectKind() && "Must be a friend!");
+
+  // The logic for non-templates is handled in ASTContext::isSameEntity, so we
+  // don't have to bother checking 'DependsOnEnclosingTemplate' for a
+  // non-function-template.
+  assert(FD->getDescribedFunctionTemplate() &&
+         "Non-function templates don't need to be checked");
+
+  SmallVector<const Expr *, 3> ACs;
+  FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
+
+  unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
+  for (const Expr *Constraint : ACs)
+    if (ConstraintExpressionDependsOnEnclosingTemplate(OldTemplateDepth,
+                                                       Constraint))
+      return true;
+
+  return false;
 }
 
 bool Sema::EnsureTemplateArgumentListConstraints(
@@ -432,26 +678,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 +693,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 +969,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 +1025,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 +1101,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/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 85b2bca535809..7aadd61e56982 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10480,6 +10480,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   }
 
   if (getLangOpts().CPlusPlus) {
+    // Precalculate whether this is a friend function template with a constraint
+    // that depends on an enclosing template, per [temp.friend]p9.
+    if (isFriend && FunctionTemplate &&
+        FriendConstraintsDependOnEnclosingTemplate(NewFD))
+      NewFD->setFriendConstraintRefersToEnclosingTemplate(true);
+
     if (FunctionTemplate) {
       if (NewFD->isInvalidDecl())
         FunctionTemplate->setInvalidDecl();

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7f70cf331c7f9..0f25801c9a2d7 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 9aea1569f9b32..32ece5cc47918 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1074,6 +1074,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 (Context.FriendsDifferByConstraints(OldF, New))
+          continue;
+
         Match = *I;
         return Ovl_Match;
       }
@@ -6521,7 +6530,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;
@@ -7027,7 +7037,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 5818300cbff2d..68af353e2cc5c 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1687,6 +1687,61 @@ 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 if (isa<NamedDecl>(D)) {
+      // No direct types to visit here I believe.
+    } 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.
@@ -2288,7 +2343,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,
@@ -6014,10 +6070,30 @@ 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);
+    // Setup the context/ThisScope for the case where we are needing to
+    // re-instantiate constraints outside of normal instantiation.
+    DeclContext *NewContext = Template->getDeclContext();
+
+    // If this template is in a template, make sure we extract the templated
+    // decl.
+    if (auto *TD = dyn_cast<TemplateDecl>(NewContext))
+      NewContext = Decl::castToDeclContext(TD->getTemplatedDecl());
+    auto *RD = dyn_cast<CXXRecordDecl>(NewContext);
+
+    Qualifiers ThisQuals;
+    if (const auto *Method =
+            dyn_cast_or_null<CXXMethodDecl>(Template->getTemplatedDecl()))
+      ThisQuals = Method->getMethodQualifiers();
+
+    ContextRAII Context(*this, NewContext);
+    CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);
+
+    MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
+        Template, &StackTemplateArgs, /*RelativeToPrimary*/ true,
+        /*Pattern*/ nullptr,
+        /*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
     if (EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
             SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
@@ -7564,7 +7640,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))
@@ -7760,10 +7838,10 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
 }
 
 /// Match two template parameters within template parameter lists.
-static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
-                                       bool Complain,
-                                     Sema::TemplateParameterListEqualKind Kind,
-                                       SourceLocation TemplateArgLoc) {
+static bool MatchTemplateParameterKind(
+    Sema &S, NamedDecl *New, const NamedDecl *NewInstFrom, NamedDecl *Old,
+    const NamedDecl *OldInstFrom, bool Complain,
+    Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
   // Check the actual kind (type, non-type, template).
   if (Old->getKind() != New->getKind()) {
     if (Complain) {
@@ -7845,13 +7923,13 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
   else if (TemplateTemplateParmDecl *OldTTP
                                     = dyn_cast<TemplateTemplateParmDecl>(Old)) {
     TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
-    if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
-                                          OldTTP->getTemplateParameters(),
-                                          Complain,
-                                        (Kind == Sema::TPL_TemplateMatch
-                                           ? Sema::TPL_TemplateTemplateParmMatch
-                                           : Kind),
-                                          TemplateArgLoc))
+    if (!S.TemplateParameterListsAreEqual(
+            NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
+            OldTTP->getTemplateParameters(), Complain,
+            (Kind == Sema::TPL_TemplateMatch
+                 ? Sema::TPL_TemplateTemplateParmMatch
+                 : Kind),
+            TemplateArgLoc))
       return false;
   } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
     const Expr *NewC = nullptr, *OldC = nullptr;
@@ -7874,10 +7952,8 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
     }
 
     if (NewC) {
-      llvm::FoldingSetNodeID OldCID, NewCID;
-      OldC->Profile(OldCID, S.Context, /*Canonical=*/true);
-      NewC->Profile(NewCID, S.Context, /*Canonical=*/true);
-      if (OldCID != NewCID) {
+      if (!S.AreConstraintExpressionsEqual(OldInstFrom, OldC, NewInstFrom,
+                                           NewC)) {
         if (Complain)
           Diagnose();
         return false;
@@ -7933,12 +8009,10 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
 ///
 /// \returns True if the template parameter lists are equal, false
 /// otherwise.
-bool
-Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
-                                     TemplateParameterList *Old,
-                                     bool Complain,
-                                     TemplateParameterListEqualKind Kind,
-                                     SourceLocation TemplateArgLoc) {
+bool Sema::TemplateParameterListsAreEqual(
+    const NamedDecl *NewInstFrom, TemplateParameterList *New,
+    const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+    TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
   if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) {
     if (Complain)
       DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
@@ -7968,8 +8042,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
         return false;
       }
 
-      if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
-                                      Kind, TemplateArgLoc))
+      if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+                                      OldInstFrom, Complain, Kind,
+                                      TemplateArgLoc))
         return false;
 
       ++NewParm;
@@ -7984,8 +8059,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
     //   template parameter pack in P (ignoring whether those template
     //   parameters are template parameter packs).
     for (; NewParm != NewParmEnd; ++NewParm) {
-      if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
-                                      Kind, TemplateArgLoc))
+      if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+                                      OldInstFrom, Complain, Kind,
+                                      TemplateArgLoc))
         return false;
     }
   }
@@ -8017,10 +8093,8 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
     }
 
     if (NewRC) {
-      llvm::FoldingSetNodeID OldRCID, NewRCID;
-      OldRC->Profile(OldRCID, Context, /*Canonical=*/true);
-      NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
-      if (OldRCID != NewRCID) {
+      if (!AreConstraintExpressionsEqual(OldInstFrom, OldRC, NewInstFrom,
+                                         NewRC)) {
         if (Complain)
           Diagnose();
         return false;

diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 5e0f5f22a13b9..9f1942a3a041b 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2848,6 +2848,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
@@ -2856,13 +2870,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 09f01790a30fb..499343d27fe14 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,28 @@ 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());
+        }
+      }
+      bool IsFriend = Rec->getFriendObjectKind() ||
+                      (Rec->getDescribedClassTemplate() &&
+                       Rec->getDescribedClassTemplate()->getFriendObjectKind());
+      if (IncludeContainingStructArgs && IsFriend &&
+          Rec->getNonTransparentDeclContext()->isFileContext() &&
+          (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
+        Ctx = Rec->getLexicalDeclContext();
+        RelativeToPrimary = false;
+        continue;
       }
     }
 
@@ -930,16 +959,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 +1182,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 +1229,7 @@ namespace {
       DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
       TemplateDeclInstantiator  DeclInstantiator(getSema(),
                         /* DeclContext *Owner */ Owner, TemplateArgs);
+      DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
       return DeclInstantiator.SubstTemplateParams(OrigTPL);
     }
 
@@ -1766,9 +1805,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;
@@ -1988,8 +2027,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) {
@@ -2199,7 +2237,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");
@@ -2208,6 +2247,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
     return T;
 
   TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
+  Instantiator.setEvaluateConstraints(EvaluateConstraints);
 
   TypeLocBuilder TLB;
 
@@ -2352,9 +2392,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) {
@@ -2373,11 +2423,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;
 
@@ -2435,9 +2485,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;
       }
     }
@@ -2746,6 +2794,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
     Instantiation->setInvalidDecl();
 
   TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
+  Instantiator.setEvaluateConstraints(false);
   SmallVector<Decl*, 4> Fields;
   // Delay instantiation of late parsed attributes.
   LateInstantiatedAttrVec LateAttrs;
@@ -3524,11 +3573,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
@@ -3542,11 +3589,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 4ffc23f643416..9fcc165e8dc7e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1635,12 +1635,16 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
     }
 
     if (PrevClassTemplate) {
-      TemplateParameterList *PrevParams
-        = PrevClassTemplate->getMostRecentDecl()->getTemplateParameters();
+      const ClassTemplateDecl *MostRecentPrevCT =
+          PrevClassTemplate->getMostRecentDecl();
+      TemplateParameterList *PrevParams =
+          MostRecentPrevCT->getTemplateParameters();
 
       // Make sure the parameter lists match.
-      if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, true,
-                                                  Sema::TPL_TemplateMatch))
+      if (!SemaRef.TemplateParameterListsAreEqual(
+              D->getTemplatedDecl(), InstParams,
+              MostRecentPrevCT->getTemplatedDecl(), PrevParams, true,
+              Sema::TPL_TemplateMatch))
         return nullptr;
 
       // Do some additional validation, then merge default arguments
@@ -1830,6 +1834,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);
@@ -2069,19 +2074,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
@@ -2121,6 +2114,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
         D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(),
         D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(),
         TrailingRequiresClause);
+    Function->setFriendConstraintRefersToEnclosingTemplate(
+        D->FriendConstraintRefersToEnclosingTemplate());
     Function->setRangeEnd(D->getSourceRange().getEnd());
   }
 
@@ -2432,23 +2427,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) {
@@ -2466,6 +2444,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     if (!DC) return nullptr;
   }
 
+  CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+  Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+
   DeclarationNameInfo NameInfo
     = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
 
@@ -2473,7 +2454,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();
@@ -2783,13 +2763,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;
     }
   }
@@ -4033,18 +4011,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(),
@@ -4338,11 +4305,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 196cf94d1fc29..feb31a806b8f0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13077,13 +13077,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
@@ -13118,7 +13111,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/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 0b51b4ed8863b..5ada9f66f2028 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -930,6 +930,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
   FD->setHasSkippedBody(Record.readInt());
   FD->setIsMultiVersion(Record.readInt());
   FD->setLateTemplateParsed(Record.readInt());
+  FD->setFriendConstraintRefersToEnclosingTemplate(Record.readInt());
 
   FD->setCachedLinkage(static_cast<Linkage>(Record.readInt()));
   FD->EndRangeLoc = readSourceLocation();

diff  --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index e0ae019bf803e..f41b247c306f5 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -802,7 +802,7 @@ void ASTStmtReader::VisitConceptSpecializationExpr(
   E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
   llvm::SmallVector<TemplateArgument, 4> Args;
   for (unsigned I = 0; I < NumTemplateArgs; ++I)
-    Args.push_back(Record.readTemplateArgument());
+    Args.push_back(Record.readTemplateArgument(/*Canonicalize*/ true));
   E->setTemplateArguments(Args);
   E->Satisfaction = E->isValueDependent() ? nullptr :
       ASTConstraintSatisfaction::Create(Record.getContext(),

diff  --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 802b00884633f..6d9d0ed8dc1d7 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -563,6 +563,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
   Record.push_back(D->hasSkippedBody());
   Record.push_back(D->isMultiVersion());
   Record.push_back(D->isLateTemplateParsed());
+  Record.push_back(D->FriendConstraintRefersToEnclosingTemplate());
   Record.push_back(D->getLinkageInternal());
   Record.AddSourceLocation(D->getEndLoc());
 
@@ -2285,6 +2286,7 @@ void ASTWriter::WriteDeclAbbrevs() {
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // MultiVersion
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FriendConstraintRefersToEnclosingTemplate
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));   // LocEnd
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // ODRHash

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/Modules/concept_serialization.cpp b/clang/test/Modules/concept_serialization.cpp
new file mode 100644
index 0000000000000..eb02578dbef19
--- /dev/null
+++ b/clang/test/Modules/concept_serialization.cpp
@@ -0,0 +1,27 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -std=c++20 -fmodules-cache-path=%t -x c++ %s -verify
+// expected-no-diagnostics
+#pragma clang module build std
+module std [system] { module concepts [system] {} }
+#pragma clang module contents
+
+#pragma clang module begin std.concepts
+template <class T>
+T declval();
+template<class T, class U>
+concept common_reference_with = T::val;
+template<class T>
+concept input_or_output_iterator = true;
+template <class T>
+concept input_iterator = input_or_output_iterator<T> &&
+                         common_reference_with<decltype(declval<T&>)&&, T&>;
+#pragma clang module end /*std.concepts*/
+#pragma clang module endbuild /*std*/
+
+#pragma clang module import std.concepts
+template<input_or_output_iterator>
+struct iter_value_or_void{};
+// ensure that we don't assert on a subsumption check due to improper
+// deserialization.
+template<input_iterator I>
+struct iter_value_or_void<I>{};

diff  --git a/clang/test/SemaCXX/constrained-special-member-functions.cpp b/clang/test/SemaCXX/constrained-special-member-functions.cpp
index b3eb2c0eaf5f4..33ed4050553b8 100644
--- a/clang/test/SemaCXX/constrained-special-member-functions.cpp
+++ b/clang/test/SemaCXX/constrained-special-member-functions.cpp
@@ -196,17 +196,13 @@ static_assert(!__is_trivial(ComplexConstraints<int>), "");
 
 // This is evaluated at the completion of CRTPBase, while `T` is not yet completed.
 // This is probably correct behavior.
-// FIXME: We should not throw an error, instead SFINAE should make the constraint
-// silently unsatisfied. See [temp.constr.constr]p5
 template <class T>
 struct CRTPBase {
-  CRTPBase() requires (sizeof(T) > 0); // expected-error {{to an incomplete type}}
+  CRTPBase() requires (sizeof(T) > 0);
   CRTPBase() = default;
 };
 
 struct Child : CRTPBase<Child> { int x; };
-// expected-note at -1 {{definition of 'Child' is not complete until}}
-// expected-note at -2 {{in instantiation of template class 'CRTPBase<Child>' requested here}}
 static Child c;
 
 

diff  --git a/clang/test/SemaTemplate/concepts-friends.cpp b/clang/test/SemaTemplate/concepts-friends.cpp
new file mode 100644
index 0000000000000..3db12b5605887
--- /dev/null
+++ b/clang/test/SemaTemplate/concepts-friends.cpp
@@ -0,0 +1,396 @@
+// 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
+
+namespace NamedDeclRefs {
+  namespace my_std {
+    template<typename T, typename U>
+      concept Outer = true;
+    template<typename T>
+      using Inner = T;
+  }
+  template<typename T>
+    struct Proxy {
+      template<class U>
+        friend constexpr void RefOuter()
+        requires my_std::Outer<my_std::Inner<T>, my_std::Inner<U>>{}
+      template<class U>
+        friend constexpr void NoRefOuter() // #NOREFOUTER
+        requires my_std::Outer<my_std::Inner<U>, my_std::Inner<U>>{}
+    };
+  void use() {
+    Proxy<int> p;
+    Proxy<float> p2;
+    // expected-error@#NOREFOUTER {{redefinition of 'NoRefOuter'}}
+    // expected-note at -2{{in instantiation of template class}}
+    // expected-note@#NOREFOUTER{{previous definition is here}}
+  }
+} // namespace NamedDeclRefs

diff  --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index 332eed56c5634..5163fc8e01471 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -262,3 +262,449 @@ template<class, template <class> class> concept C = true;
 template <class> struct S {};
 void f(C<GH55567::S> auto);
 } // namespace GH55567
+
+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
+
+namespace ClassTemplateInstantiation {
+struct Type;
+template < typename A, typename B, typename C>
+  concept ConstraintF = false; // #ConstraintF
+template < typename A, typename B, typename C>
+  concept ConstraintT = true;
+
+template < typename T > struct Parent {
+  template < typename U, ConstraintT<T, U> > struct ChildT{};
+  ChildT<Type, Type> CauseInstT;
+  template < typename U, ConstraintF<T, U> > struct ChildF{};// #ChildF
+  ChildF<Type, Type> CauseInstF; //#CauseInstF
+};
+
+// expected-error@#CauseInstF{{constraints not satisfied for class template}}
+// expected-note at +3{{in instantiation of template class}}
+// expected-note@#ChildF{{evaluated to false}}
+// expected-note@#ConstraintF{{because 'false' evaluated to false}}
+Parent<int> Inst;
+} // namespace ClassTemplateInstantiation
+
+namespace SelfFriend {
+  template<class T>
+  concept Constraint = requires (T i) { (*i); };
+  template<class T>
+  concept Constraint2 = requires (T i) { (*i); };
+
+  template<Constraint T>
+  struct Iterator {
+    template <Constraint>
+    friend class Iterator;
+    void operator*();
+  };
+
+  template<Constraint T> // #ITER_BAD
+  struct IteratorBad {
+    template <Constraint2>//#ITER_BAD_FRIEND
+    friend class IteratorBad;
+    void operator*();
+  };
+
+  Iterator<int*> I;
+  Iterator<char*> I2;
+  IteratorBad<int*> I3; // expected-error@#ITER_BAD_FRIEND{{constraint 
diff ers}}
+                        // expected-note at -1{{in instantiation of template class}}
+                        // expected-note@#ITER_BAD{{previous template declaration}}
+} // namespace SelfFriend
+
+
+namespace ConstrainedMemberVarTemplate {
+template <long Size> struct Container {
+  static constexpr long arity = Size;
+  template <typename U>
+  requires(sizeof(U) == arity) // #CMVT_REQ
+  using var_templ = int;
+};
+Container<4>::var_templ<int> inst;
+Container<5>::var_templ<int> inst_fail;
+// expected-error at -1{{constraints not satisfied for alias template 'var_templ'}}
+// expected-note@#CMVT_REQ{{because 'sizeof(int) == arity' (4 == 5) evaluated to false}}
+} // namespace ConstrainedMemberVarTemplate 
+

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