erichkeane updated this revision to Diff 425275.
erichkeane added a comment.

Update the concepts-test, remove some extra commented out code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119544/new/

https://reviews.llvm.org/D119544

Files:
  clang/docs/ReleaseNotes.rst
  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/ASTImporter.cpp
  clang/lib/AST/Decl.cpp
  clang/lib/AST/DeclBase.cpp
  clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
  clang/lib/Sema/SemaConcept.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/ASTWriterDecl.cpp
  clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
  clang/test/SemaTemplate/concepts.cpp
  clang/test/SemaTemplate/deferred-concept-inst.cpp
  clang/test/SemaTemplate/instantiate-requires-clause.cpp
  clang/test/SemaTemplate/trailing-return-short-circuit.cpp

Index: clang/test/SemaTemplate/trailing-return-short-circuit.cpp
===================================================================
--- /dev/null
+++ 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@-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@-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@-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@-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}}
+}
Index: clang/test/SemaTemplate/instantiate-requires-clause.cpp
===================================================================
--- clang/test/SemaTemplate/instantiate-requires-clause.cpp
+++ 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@-1 {{because '(sizeof(int) == 1) , (sizeof(char) == 1) , (sizeof(int) == 1)' evaluated to false}}
@@ -40,6 +40,20 @@
 
 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@+3 {{candidate template ignored: constraints not satisfied [with U = int]}}
+  // expected-note@+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@+1 {{no matching function for call to 'f'}}
+static_assert(S1<void>::f(1));
+
 constexpr auto value = 0;
 
 template<typename T>
Index: clang/test/SemaTemplate/deferred-concept-inst.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaTemplate/deferred-concept-inst.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify -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
Index: clang/test/SemaTemplate/concepts.cpp
===================================================================
--- clang/test/SemaTemplate/concepts.cpp
+++ clang/test/SemaTemplate/concepts.cpp
@@ -256,3 +256,244 @@
 C auto **&j2 = g();  // expected-error {{deduced type 'int' does not satisfy 'C'}}
 C auto **&&j3 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}}
 }
+
+namespace 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 constraint = PR54443::is_same<typename remove_ref<T>::type,
+                                             int>::value;
+
+template <typename U>
+void SingleDepthReferencesTop(U &&u) {
+  struct lc {
+    void operator()() // #SDRT_OP
+      requires constraint<decltype(u)> // #SDRT_REQ
+    {}
+  };
+  lc lv;
+  lv(); // #SDRT_CALL
+}
+
+template <typename U>
+void SingleDepthReferencesTopNotCalled(U &&u) {
+  struct lc {
+    void operator()()
+      requires constraint<typename decltype(u)::FOO>
+    {}
+  };
+  lc lv;
+}
+
+template <typename U>
+void SingleDepthReferencesTopCalled(U &&u) {
+  struct lc {
+    void operator()() // #CALLOP
+      requires constraint<typename decltype(u)::FOO> // #CONSTR
+    {}
+  };
+  lc lv;
+  lv();
+  // expected-error@-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 constraint<decltype(u)>
+  {}();
+}
+
+template <typename U>
+void DoubleDepthReferencesTop(U &&u) {
+  struct lc { // #DDRT_STRCT
+    void operator()() {
+      struct lc2 {
+        void operator()() // #DDRT_OP
+          requires constraint<decltype(u)> // #DDRT_REQ
+        {}
+      };
+      lc2 lv2;
+      lv2(); // #DDRT_CALL
+    }
+  };
+  lc lv;
+  lv();
+}
+
+template <typename U>
+void DoubleDepthReferencesTopLambda(U &&u) {
+  []() { []()
+           requires constraint<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 constraint<decltype(u)> && // #DDRA_REQ
+                   constraint<decltype(u2)> && constraint<decltype(u3)>
+        {}
+      };
+      lc2 lv2;
+      lv2(u2); // #DDRA_CALL
+    }
+  };
+  lc lv;
+  lv(u);
+}
+
+template <typename U>
+void DoubleDepthReferencesAllLambda(U &&u) {
+  [](U &&u2) {
+    [](U && u3)
+      requires constraint<decltype(u)> &&
+               constraint<decltype(u2)> && constraint<decltype(u3)>
+    {}(u2);
+  }(u);
+}
+
+template <typename U>
+void HasInnerFunc(U &&u) {
+  void InnerFunc(U && u2)
+    requires constraint<decltype(u)> && // #INNERFUNC_REQ
+             constraint<decltype(u2)>;
+  InnerFunc(u); // #INNERFUNC_CALL
+}
+
+template <typename U>
+struct CausesFriendConstraint {
+  template <typename V>
+  friend void FriendFunc(CausesFriendConstraint, V)
+    requires constraint<U> &&
+             constraint<V>
+  {}
+};
+// FIXME: Re-enable this test when constraints are allowed to refer to captures.
+// template<typename T>
+// void ChecksCapture(T x) {
+//   [y = x]() requires(constraint<decltype(y)>){}();
+// }
+
+template <typename T>
+void ChecksLocalVar(T x) {
+  T Local;
+  []()
+    requires(constraint<decltype(Local)>)
+  {}();
+}
+
+template<typename T>
+void LocalStructMemberVar(T x) {
+  struct S {
+    T local;
+    void foo() requires(constraint<decltype(local)>){} // #LSMV_REQ
+  } s;
+  s.foo(); // #LSMV_CALL
+};
+
+template<typename T>
+struct ChecksMemberVar {
+  T t;
+  void foo() requires (constraint<decltype(t)>){} // #CMV_FOO
+  template<typename U>
+  void foo2() requires (constraint<decltype(t)>){} // #CMV_FOO2
+};
+
+
+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@-2{{in instantiation of function template specialization}}
+  // expected-note@#SDRT_OP{{candidate function not viable}}
+  // expected-note@#SDRT_REQ{{'constraint<decltype(u)>' evaluated to false}}
+
+  SingleDepthReferencesTopNotCalled(v);
+  // Won't error unless we try to call it.
+  SingleDepthReferencesTopNotCalled(will_fail);
+  SingleDepthReferencesTopCalled(v); // #SDRTC
+  SingleDepthReferencesTopLambda(v);
+  // TODO: 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@-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{{'constraint<decltype(u)>' evaluated to false}}
+
+  DoubleDepthReferencesTopLambda(v);
+  // TODO: 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@-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{{'constraint<decltype(u)>' evaluated to false}}
+
+  DoubleDepthReferencesAllLambda(v);
+  // TODO: This should error on constraint failure! (Lambda!)
+  DoubleDepthReferencesAllLambda(will_fail);
+  HasInnerFunc(v);
+  HasInnerFunc(will_fail);
+  // expected-error@#INNERFUNC_CALL{{invalid reference to function 'InnerFunc': constraints not satisfied}}
+  // expected-note@-2{{in instantiation of function template specialization}}
+  // expected-note@#INNERFUNC_REQ{{'constraint<decltype(u)>' evaluated to false}}
+
+  CausesFriendConstraint<int> CFC;
+   FriendFunc(CFC, 1);
+  // TODO: This should error on constraint failure!
+  // This one is odd, it fails ONLY if the 1st instantiation is invalid, so it
+  // isn't re-evaluating the constraint?
+  FriendFunc(CFC, 1.0);
+
+  // FIXME: Re-enable this test when constraints are allowed to refer to captures.
+  // ChecksCapture(v);
+
+  ChecksLocalVar(v);
+  // TODO: 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@-2{{in instantiation of function template specialization}}
+  // expected-note@#LSMV_REQ{{because 'constraint<decltype(this->local)>' evaluated to false}}
+
+  ChecksMemberVar<int>CMV;
+  CMV.foo();
+  CMV.foo2<int>();
+
+  ChecksMemberVar<float>CMV2;
+  CMV2.foo();
+  // expected-error@-1{{invalid reference to function 'foo'}}
+  // expected-note@#CMV_FOO{{because 'constraint<decltype(this->t)>' evaluated to false}}
+  CMV2.foo2<float>();
+  // expected-error@-1{{no matching member function for call to 'foo2'}}
+  // expected-note@#CMV_FOO2{{constraints not satisfied}}
+  // expected-note@#CMV_FOO2{{because 'constraint<decltype(this->t)>' evaluated to false}}
+}
+} // namespace DeferredInstantiationInstScope
Index: clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
===================================================================
--- clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
+++ clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
@@ -90,3 +90,24 @@
 
 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
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -585,6 +585,9 @@
   switch (D->getTemplatedKind()) {
   case FunctionDecl::TK_NonTemplate:
     break;
+  case FunctionDecl::TK_DependentNonTemplate:
+    Record.AddDeclRef(D->getInstantiatedFromDecl());
+    break;
   case FunctionDecl::TK_FunctionTemplate:
     Record.AddDeclRef(D->getDescribedFunctionTemplate());
     break;
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -940,6 +940,10 @@
   case FunctionDecl::TK_NonTemplate:
     mergeRedeclarable(FD, Redecl);
     break;
+  case FunctionDecl::TK_DependentNonTemplate:
+    mergeRedeclarable(FD, Redecl);
+    FD->setInstantiatedFromDecl(readDeclAs<FunctionDecl>());
+    break;
   case FunctionDecl::TK_FunctionTemplate:
     // Merged when we merge the template.
     FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>());
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -13000,9 +13000,7 @@
   // 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);
+    NewTrailingRequiresClause = TRC;
 
   // Create the local class that will describe the lambda.
 
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2051,19 +2051,7 @@
       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
@@ -2171,6 +2159,11 @@
     // definition. We don't want non-template functions to be marked as being
     // template instantiations.
     Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+  } else if (!isFriend) {
+    // If this is not a function template, and this is not a friend (that is,
+    // this is a locally declared function), save the instantiation relationship
+    // for the purposes of constraint instantiation.
+    Function->setInstantiatedFromDecl(D);
   }
 
   if (isFriend) {
@@ -2409,23 +2402,6 @@
       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) {
@@ -2443,6 +2419,9 @@
     if (!DC) return nullptr;
   }
 
+  CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+  Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+
   DeclarationNameInfo NameInfo
     = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
 
@@ -2450,7 +2429,6 @@
     adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
 
   // Build the instantiated method declaration.
-  CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
   CXXMethodDecl *Method = nullptr;
 
   SourceLocation StartLoc = D->getInnerLocStart();
@@ -2757,9 +2735,6 @@
       // 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))
         return nullptr;
     }
@@ -4002,18 +3977,7 @@
   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(),
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -55,9 +55,18 @@
 /// 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;
 
@@ -153,11 +162,13 @@
           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?");
       }
 
@@ -174,10 +185,18 @@
       }
     } 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());
+        }
       }
     }
 
@@ -2304,6 +2323,18 @@
     const MultiLevelTemplateArgumentList &TemplateArgs) {
   const ASTTemplateArgumentListInfo *TemplArgInfo =
       TC->getTemplateArgsAsWritten();
+
+  // If we're not checking a constraint, we shouldn't be instantiating the type
+  // constraint, so we should just create a copy of the previous one.
+  // TODO: ERICH: Should this be RebuildExprInCurrentInstantiation here?
+  if (!IsEvaluatingAConstraint()) {
+    Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(),
+                            TC->getConceptNameInfo(), TC->getNamedConcept(),
+                            TC->getNamedConcept(), TemplArgInfo,
+                            TC->getImmediatelyDeclaredConstraint());
+    return false;
+  }
+
   TemplateArgumentListInfo InstArgs;
 
   if (TemplArgInfo) {
@@ -3488,6 +3519,14 @@
   return Instantiator.TransformExpr(E);
 }
 
+ExprResult
+Sema::SubstConstraintExpr(Expr *E,
+                          const MultiLevelTemplateArgumentList &TemplateArgs) {
+
+  ConstraintEvalRAII EvalRAII(*this);
+  return SubstExpr(E, TemplateArgs);
+}
+
 ExprResult Sema::SubstInitializer(Expr *Init,
                           const MultiLevelTemplateArgumentList &TemplateArgs,
                           bool CXXDirectInit) {
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2791,8 +2791,10 @@
                                 TemplateDeductionInfo& Info) {
   llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
   Template->getAssociatedConstraints(AssociatedConstraints);
-  if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
-                                    DeducedArgs, Info.getLocation(),
+  MultiLevelTemplateArgumentList MLTAL;
+  MLTAL.addOuterTemplateArguments(DeducedArgs);
+  if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
+                                    Info.getLocation(),
                                     Info.AssociatedConstraintsSatisfaction) ||
       !Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
     Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
@@ -4572,8 +4574,11 @@
   if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
                                   /*PartialTemplateArgs=*/false, Converted))
     return Sema::DAR_FailedAlreadyDiagnosed;
+
+  MultiLevelTemplateArgumentList MLTAL;
+  MLTAL.addOuterTemplateArguments(Converted);
   if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
-                                    Converted, TypeLoc.getLocalSourceRange(),
+                                    MLTAL, TypeLoc.getLocalSourceRange(),
                                     Satisfaction))
     return Sema::DAR_FailedAlreadyDiagnosed;
   if (!Satisfaction.IsSatisfied) {
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -4706,9 +4706,11 @@
   bool AreArgsDependent =
       TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
                                                                 Converted);
+  MultiLevelTemplateArgumentList MLTAL;
+  MLTAL.addOuterTemplateArguments(Converted);
   if (!AreArgsDependent &&
       CheckConstraintSatisfaction(
-          NamedConcept, {NamedConcept->getConstraintExpr()}, Converted,
+          NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL,
           SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
                       TemplateArgs->getRAngleLoc()),
           Satisfaction))
@@ -5568,6 +5570,7 @@
     if (Inst.isInvalid())
       return true;
 
+    ConstraintEvalRAII EvalRAII(*this);
     TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
     Params = SubstTemplateParams(Params, CurContext,
                                  MultiLevelTemplateArgumentList(TemplateArgs));
@@ -5925,13 +5928,20 @@
   if (UpdateArgsWithConversions)
     TemplateArgs = std::move(NewArgs);
 
-  if (!PartialTemplateArgs &&
-      EnsureTemplateArgumentListConstraints(
-        Template, Converted, SourceRange(TemplateLoc,
-                                         TemplateArgs.getRAngleLoc()))) {
-    if (ConstraintsNotSatisfied)
-      *ConstraintsNotSatisfied = true;
-    return true;
+  if (!PartialTemplateArgs) {
+    TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
+                                           Converted);
+    MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
+        Template, &StackTemplateArgs, /*RelativeToPrimary*/ true,
+        /*Pattern*/ nullptr,
+        /*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
+    if (EnsureTemplateArgumentListConstraints(
+            Template, MLTAL,
+            SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
+      if (ConstraintsNotSatisfied)
+        *ConstraintsNotSatisfied = true;
+      return true;
+    }
   }
 
   return false;
@@ -7461,7 +7471,9 @@
       //   are not considered.
       if (ParamsAC.empty())
         return false;
+
       Template->getAssociatedConstraints(TemplateAC);
+
       bool IsParamAtLeastAsConstrained;
       if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
                                  IsParamAtLeastAsConstrained))
Index: clang/lib/Sema/SemaConcept.cpp
===================================================================
--- clang/lib/Sema/SemaConcept.cpp
+++ clang/lib/Sema/SemaConcept.cpp
@@ -30,6 +30,7 @@
 
 namespace {
 class LogicalBinOp {
+  SourceLocation Loc;
   OverloadedOperatorKind Op = OO_None;
   const Expr *LHS = nullptr;
   const Expr *RHS = nullptr;
@@ -40,12 +41,14 @@
       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 +59,22 @@
 
   const Expr *getLHS() const { return LHS; }
   const Expr *getRHS() const { return RHS; }
+
+  ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) {
+    return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS()));
+  }
+
+  ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS, ExprResult RHS) {
+    assert((isAnd() || isOr()) && "Not the right kind of op?");
+    assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?");
+    assert(LHS.isUsable() && RHS.isUsable() && "Side not usable?");
+    // 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 +141,18 @@
 }
 
 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 +163,7 @@
       //    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 LHSRes.isUsable() ? BO.recreateBinOp(S, LHSRes) : ExprEmpty();
 
     if (BO.isAnd() && !IsLHSSatisfied)
       // [temp.constr.op] p2
@@ -151,12 +172,21 @@
       //    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 LHSRes.isUsable() ? BO.recreateBinOp(S, LHSRes) : ExprEmpty();
 
-    return calculateConstraintSatisfaction(
+    ExprResult RHSRes = calculateConstraintSatisfaction(
         S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
+    if (RHSRes.isInvalid())
+      return ExprError();
+
+    if (!LHSRes.isUsable() || !RHSRes.isUsable())
+      return ExprEmpty();
+    return BO.recreateBinOp(S, LHSRes, RHSRes);
   } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
-    return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
+    // 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 +194,11 @@
   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 +215,7 @@
         << SubstitutedAtomicExpr.get()->getSourceRange();
     for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
       S.Diag(PDiag.first, PDiag.second);
-    return true;
+    return ExprError();
   }
 
   assert(EvalResult.Val.isInt() &&
@@ -195,13 +225,13 @@
     Satisfaction.Details.emplace_back(ConstraintExpr,
                                       SubstitutedAtomicExpr.get());
 
-  return false;
+  return SubstitutedAtomicExpr;
 }
 
-static bool calculateConstraintSatisfaction(
-    Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
-    SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
-    const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
+static ExprResult calculateConstraintSatisfaction(
+    Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
+    const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
+    ConstraintSatisfaction &Satisfaction) {
   return calculateConstraintSatisfaction(
       S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
         EnterExpressionEvaluationContext ConstantEvaluated(
@@ -219,8 +249,8 @@
             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
@@ -268,56 +298,70 @@
       });
 }
 
-static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template,
-                                        ArrayRef<const Expr *> ConstraintExprs,
-                                        ArrayRef<TemplateArgument> TemplateArgs,
-                                        SourceRange TemplateIDRange,
-                                        ConstraintSatisfaction &Satisfaction) {
+static bool CheckConstraintSatisfaction(
+    Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+    llvm::SmallVectorImpl<Expr *> &Converted,
+    const MultiLevelTemplateArgumentList &TemplateArgsList,
+    SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
   if (ConstraintExprs.empty()) {
     Satisfaction.IsSatisfied = true;
     return false;
   }
 
-  for (auto& Arg : TemplateArgs)
-    if (Arg.isInstantiationDependent()) {
-      // No need to check satisfaction for dependent constraint expressions.
-      Satisfaction.IsSatisfied = true;
-      return false;
-    }
+  if (TemplateArgsList.isAnyArgInstantiationDependent()) {
+    //  No need to check satisfaction for dependent constraint expressions.
+    Satisfaction.IsSatisfied = true;
+    return false;
+  }
 
-  Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
+  ArrayRef<TemplateArgument> TemplateArgs =
+      TemplateArgsList.getNumSubstitutedLevels() > 0
+          ? TemplateArgsList.getOutermost()
+          : ArrayRef<TemplateArgument>{};
+
+  Sema::InstantiatingTemplate Inst(
+      S, TemplateIDRange.getBegin(),
       Sema::InstantiatingTemplate::ConstraintsCheck{},
       const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
   if (Inst.isInvalid())
     return true;
 
-  MultiLevelTemplateArgumentList MLTAL;
-  MLTAL.addOuterTemplateArguments(TemplateArgs);
-
   for (const Expr *ConstraintExpr : ConstraintExprs) {
-    if (calculateConstraintSatisfaction(S, Template, TemplateArgs,
-                                        TemplateIDRange.getBegin(), MLTAL,
-                                        ConstraintExpr, Satisfaction))
+    ExprResult Res = calculateConstraintSatisfaction(
+        S, Template, TemplateIDRange.getBegin(), TemplateArgsList,
+        ConstraintExpr, Satisfaction);
+    if (Res.isInvalid())
       return true;
-    if (!Satisfaction.IsSatisfied)
-      // [temp.constr.op] p2
+
+    Converted.push_back(Res.get());
+    if (!Satisfaction.IsSatisfied) {
+      // Backfill the 'converted' list with nulls so we can keep the Converted
+      Converted.append(ConstraintExprs.size() - Converted.size(), nullptr);
+      // and unconverted lists in sync. [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. [...]
       return false;
+    }
   }
   return false;
 }
 
 bool Sema::CheckConstraintSatisfaction(
     const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
-    ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
-    ConstraintSatisfaction &OutSatisfaction) {
+    llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
+    const MultiLevelTemplateArgumentList &TemplateArgsList,
+    SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
   if (ConstraintExprs.empty()) {
     OutSatisfaction.IsSatisfied = true;
     return false;
   }
 
+  ArrayRef<TemplateArgument> TemplateArgs =
+      TemplateArgsList.getNumSubstitutedLevels() > 0
+          ? TemplateArgsList.getOutermost()
+          : ArrayRef<TemplateArgument>{};
+
   llvm::FoldingSetNodeID ID;
   void *InsertPos;
   ConstraintSatisfaction *Satisfaction = nullptr;
@@ -334,8 +378,8 @@
     Satisfaction = &OutSatisfaction;
   }
   if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
-                                    TemplateArgs, TemplateIDRange,
-                                    *Satisfaction)) {
+                                    ConvertedConstraints, TemplateArgsList,
+                                    TemplateIDRange, *Satisfaction)) {
     if (ShouldCache)
       delete Satisfaction;
     return true;
@@ -353,20 +397,121 @@
 bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
                                        ConstraintSatisfaction &Satisfaction) {
   return calculateConstraintSatisfaction(
-      *this, ConstraintExpr, Satisfaction,
-      [](const Expr *AtomicExpr) -> ExprResult {
-        return ExprResult(const_cast<Expr *>(AtomicExpr));
-      });
+             *this, ConstraintExpr, Satisfaction,
+             [](const Expr *AtomicExpr) -> ExprResult {
+               return ExprResult(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 (TemplateArgs) {
+      MultiLevelTemplateArgumentList JustTemplArgs(
+          *FD->getTemplateSpecializationArgs());
+      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;
+    }
+  } else if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) {
+    InstantiatingTemplate Inst(*this, FD->getPointOfInstantiation(),
+                               Sema::InstantiatingTemplate::ConstraintsCheck{},
+                               FD->getInstantiatedFromMemberFunction(),
+                               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, FD->getInstantiatedFromMemberFunction(), Scope, MLTAL))
+      return true;
+  } else if (FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) {
+
+    InstantiatingTemplate Inst(*this, FD->getPointOfInstantiation(),
+                               Sema::InstantiatingTemplate::ConstraintsCheck{},
+                               FD->getInstantiatedFromDecl(),
+                               TemplateArgs ? *TemplateArgs
+                                            : ArrayRef<TemplateArgument>{},
+                               SourceRange());
+    if (Inst.isInvalid())
+      return true;
+    // case where this is a function declared inside of another.
+    if (addInstantiatedParametersToScope(FD, FD->getInstantiatedFromDecl(),
+                                         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()) {
+  // 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, true);
+  llvm::Optional<MultiLevelTemplateArgumentList> MLTAL =
+      SetupConstraintCheckingTemplateArgumentsAndScope(
+          const_cast<FunctionDecl *>(FD), {}, Scope);
+
   Qualifiers ThisQuals;
   CXXRecordDecl *Record = nullptr;
   if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
@@ -377,14 +522,27 @@
   // 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 difficult, but we
+  // seem to always just pick up the constraints from the primary template.
+  assert(Converted.size() <= 1 && "Got more expressions converted?");
+  if (!Converted.empty() && Converted[0] != nullptr)
+    const_cast<FunctionDecl *>(FD)->setTrailingRequiresClause(Converted[0]);
+  return false;
 }
 
 bool Sema::EnsureTemplateArgumentListConstraints(
-    TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
+    TemplateDecl *TD, MultiLevelTemplateArgumentList TemplateArgs,
     SourceRange TemplateIDRange) {
   ConstraintSatisfaction Satisfaction;
   llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
@@ -397,7 +555,8 @@
     SmallString<128> TemplateArgString;
     TemplateArgString = " ";
     TemplateArgString += getTemplateArgumentBindingsText(
-        TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
+        TD->getTemplateParameters(), TemplateArgs.getInnermost().data(),
+        TemplateArgs.getInnermost().size());
 
     Diag(TemplateIDRange.getBegin(),
          diag::err_template_arg_list_constraints_not_satisfied)
@@ -429,21 +588,13 @@
   Sema::ContextRAII savedContext(*this, Decl);
   LocalInstantiationScope Scope(*this);
 
-  // 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)) {
@@ -451,7 +602,8 @@
     Record = Method->getParent();
   }
   CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
-  return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
+  llvm::SmallVector<Expr *, 1> Converted;
+  return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
                                      PointOfInstantiation, Satisfaction);
 }
 
Index: clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
===================================================================
--- clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -161,6 +161,7 @@
     // Skip templated functions.
     switch (Decl->getTemplatedKind()) {
     case FunctionDecl::TK_NonTemplate:
+    case FunctionDecl::TK_DependentNonTemplate:
       break;
     case FunctionDecl::TK_MemberSpecialization:
     case FunctionDecl::TK_FunctionTemplateSpecialization:
Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -293,6 +293,16 @@
   return nullptr;
 }
 
+const DeclContext *Decl::getLexicalParentFunctionOrMethod() const {
+  for (const DeclContext *DC = getLexicalDeclContext();
+       DC && !DC->isTranslationUnit() && !DC->isNamespace();
+       DC = DC->getParent())
+    if (DC->isFunctionOrMethod())
+      return DC;
+
+  return nullptr;
+}
+
 //===----------------------------------------------------------------------===//
 // PrettyStackTraceDecl Implementation
 //===----------------------------------------------------------------------===//
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -3729,6 +3729,8 @@
 FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
   if (TemplateOrSpecialization.isNull())
     return TK_NonTemplate;
+  if (TemplateOrSpecialization.is<FunctionDecl *>())
+    return TK_DependentNonTemplate;
   if (TemplateOrSpecialization.is<FunctionTemplateDecl *>())
     return TK_FunctionTemplate;
   if (TemplateOrSpecialization.is<MemberSpecializationInfo *>())
@@ -3780,6 +3782,16 @@
   TemplateOrSpecialization = Template;
 }
 
+void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) {
+  assert(TemplateOrSpecialization.isNull() &&
+         "function is already a specialization");
+  TemplateOrSpecialization = FD;
+}
+
+FunctionDecl *FunctionDecl::getInstantiatedFromDecl() const {
+  return TemplateOrSpecialization.dyn_cast<FunctionDecl *>();
+}
+
 bool FunctionDecl::isImplicitlyInstantiable() const {
   // If the function is invalid, it can't be implicitly instantiated.
   if (isInvalidDecl())
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -3109,6 +3109,11 @@
   case FunctionDecl::TK_FunctionTemplate:
     return Error::success();
 
+  case FunctionDecl::TK_DependentNonTemplate:
+    if (Expected<FunctionDecl *> InstFDOrErr =
+            import(FromFD->getInstantiatedFromDecl()))
+      ToFD->setInstantiatedFromDecl(*InstFDOrErr);
+    return Error::success();
   case FunctionDecl::TK_MemberSpecialization: {
     TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind();
 
Index: clang/include/clang/Sema/Template.h
===================================================================
--- clang/include/clang/Sema/Template.h
+++ clang/include/clang/Sema/Template.h
@@ -158,6 +158,14 @@
       return !(*this)(Depth, Index).isNull();
     }
 
+    bool isAnyArgInstantiationDependent() const {
+      for (ArgList List : TemplateArgumentLists)
+        for (const TemplateArgument &TA : List)
+          if (TA.isInstantiationDependent())
+            return true;
+      return false;
+    }
+
     /// Clear out a specific template argument.
     void setArgument(unsigned Depth, unsigned Index,
                      TemplateArgument Arg) {
@@ -197,6 +205,9 @@
     const ArgList &getInnermost() const {
       return TemplateArgumentLists.front();
     }
+
+    /// Retrieve the outermost template argument list.
+    const ArgList &getOutermost() const { return TemplateArgumentLists.back(); }
   };
 
   /// The context in which partial ordering of function templates occurs.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -6981,7 +6981,34 @@
       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);
+
+  // Keep track of whether we are evaluating a constraint.
+  unsigned ConstraintEvaluationDepth = 0;
+
+  class ConstraintEvalRAII {
+    Sema &S;
+
+  public:
+    ConstraintEvalRAII(Sema &S) : S(S) { ++S.ConstraintEvaluationDepth; }
+    ~ConstraintEvalRAII() { --S.ConstraintEvaluationDepth; }
+  };
+
 public:
+  bool IsEvaluatingAConstraint() { return ConstraintEvaluationDepth > 0; }
   const NormalizedConstraint *
   getNormalizedAssociatedConstraints(
       NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints);
@@ -7011,8 +7038,10 @@
   /// check (either a concept or a constrained entity).
   /// \param ConstraintExprs a list of constraint expressions, treated as if
   /// they were 'AND'ed together.
-  /// \param TemplateArgs the list of template arguments to substitute into the
-  /// constraint expression.
+  /// \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
@@ -7022,7 +7051,40 @@
   /// false otherwise.
   bool CheckConstraintSatisfaction(
       const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
-      ArrayRef<TemplateArgument> TemplateArgs,
+      const MultiLevelTemplateArgumentList &TemplateArgList,
+      SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
+    llvm::SmallVector<Expr *, 4> Converted;
+    return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted,
+                                       TemplateArgList, 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
@@ -7058,9 +7120,9 @@
   ///
   /// \returns true if the constrains are not satisfied or could not be checked
   /// for satisfaction, false if the constraints are satisfied.
-  bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template,
-                                       ArrayRef<TemplateArgument> TemplateArgs,
-                                             SourceRange TemplateIDRange);
+  bool EnsureTemplateArgumentListConstraints(
+      TemplateDecl *Template, MultiLevelTemplateArgumentList TemplateArgs,
+      SourceRange TemplateIDRange);
 
   /// \brief Emit diagnostics explaining why a constraint expression was deemed
   /// unsatisfied.
@@ -8793,7 +8855,8 @@
 
   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
@@ -9514,6 +9577,11 @@
                       ExtParameterInfoBuilder &ParamInfos);
   ExprResult SubstExpr(Expr *E,
                        const MultiLevelTemplateArgumentList &TemplateArgs);
+  // 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.
Index: clang/include/clang/AST/DeclBase.h
===================================================================
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -906,6 +906,14 @@
                     const_cast<const Decl*>(this)->getParentFunctionOrMethod());
   }
 
+  /// Does the same thing as getParentFunctionOrMethod, except starts with the
+  /// lexical declaration context instead.
+  const DeclContext *getLexicalParentFunctionOrMethod() const;
+  DeclContext *getLexicalParentFunctionOrMethod() {
+    return const_cast<DeclContext *>(
+        const_cast<const Decl *>(this)->getLexicalParentFunctionOrMethod());
+  }
+
   /// Retrieves the "canonical" declaration of the given declaration.
   virtual Decl *getCanonicalDecl() { return this; }
   const Decl *getCanonicalDecl() const {
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -1887,7 +1887,9 @@
     TK_FunctionTemplateSpecialization,
     // A function template specialization that hasn't yet been resolved to a
     // particular specialized function template.
-    TK_DependentFunctionTemplateSpecialization
+    TK_DependentFunctionTemplateSpecialization,
+    // A non templated function which is in a dependent scope.
+    TK_DependentNonTemplate
   };
 
   /// Stashed information about a defaulted function definition whose body has
@@ -1936,20 +1938,21 @@
   /// The template or declaration that this declaration
   /// describes or was instantiated from, respectively.
   ///
-  /// For non-templates, this value will be NULL. For function
-  /// declarations that describe a function template, this will be a
-  /// pointer to a FunctionTemplateDecl. For member functions
-  /// of class template specializations, this will be a MemberSpecializationInfo
-  /// pointer containing information about the specialization.
-  /// For function template specializations, this will be a
-  /// FunctionTemplateSpecializationInfo, which contains information about
-  /// the template being specialized and the template arguments involved in
-  /// that specialization.
-  llvm::PointerUnion<FunctionTemplateDecl *,
+  /// For non-templates this value will be NULL, unless this non-template
+  /// function declaration was declared directly inside of a function template,
+  /// in which case this will have a pointer to a FunctionDecl. For function
+  /// declarations that describe a function template, this will be a pointer to
+  /// a FunctionTemplateDecl. For member functions of class template
+  /// specializations, this will be a MemberSpecializationInfo pointer
+  /// containing information about the specialization. For function template
+  /// specializations, this will be a FunctionTemplateSpecializationInfo, which
+  /// contains information about the template being specialized and the template
+  /// arguments involved in that specialization.
+  llvm::PointerUnion<FunctionDecl *, FunctionTemplateDecl *,
                      MemberSpecializationInfo *,
                      FunctionTemplateSpecializationInfo *,
                      DependentFunctionTemplateSpecializationInfo *>
-    TemplateOrSpecialization;
+      TemplateOrSpecialization;
 
   /// Provides source/type location info for the declaration name embedded in
   /// the DeclaratorDecl base class.
@@ -2685,6 +2688,11 @@
     setInstantiationOfMemberFunction(getASTContext(), FD, TSK);
   }
 
+  /// Specify that this function declaration was instantiated from FunctionDecl
+  /// FD. This is only used if this is a function declaration declared locally
+  /// inside of a function template.
+  void setInstantiatedFromDecl(FunctionDecl *FD);
+
   /// Retrieves the function template that is described by this
   /// function declaration.
   ///
@@ -2699,6 +2707,8 @@
   /// FunctionTemplateDecl from a FunctionDecl.
   FunctionTemplateDecl *getDescribedFunctionTemplate() const;
 
+  FunctionDecl *getInstantiatedFromDecl() const;
+
   void setDescribedFunctionTemplate(FunctionTemplateDecl *Template);
 
   /// Determine whether this function is a function template
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -264,6 +264,10 @@
   `Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.
 
 - Implemented `__builtin_source_location()` which enables library support for std::source_location.
+- 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>`_.
 
 - The mangling scheme for C++20 modules has incompatibly changed. The
   initial mangling was discovered not to be reversible, and the weak
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to