saar.raz updated this revision to Diff 159323.
saar.raz added a comment.
Herald added a subscriber: jfb.

Adjusted to switch to ASTTemplateArgumentListInfo


Repository:
  rC Clang

https://reviews.llvm.org/D41910

Files:
  include/clang/AST/DeclTemplate.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/AST/ASTContext.cpp
  lib/AST/DeclTemplate.cpp
  lib/Sema/SemaConcept.cpp
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateDeduction.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
  test/CXX/concepts-ts/temp/temp.constr/temp.constr.normal/p1.cpp
  
test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
  test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/function-templates.cpp
  
test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp

Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T> requires sizeof(T) >= 4
+bool a = false; // expected-note{{template is declared here}}
+
+template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10
+bool a<T> = true; // expected-error{{variable template partial specialization is not more specialized than the primary template}}
+
+template<typename T>
+concept C1 = sizeof(T) >= 4;
+
+template<typename T> requires C1<T>
+bool b = false;
+
+template<typename T> requires C1<T> && sizeof(T) <= 10
+bool b<T> = true;
+
+template<typename T>
+concept C2 = sizeof(T) > 1 && sizeof(T) <= 8;
+
+template<typename T>
+bool c = false;
+
+template<typename T> requires C1<T>
+bool c<T> = true;
+
+template<typename T>
+bool d = false;
+
+template<typename T>
+bool d<T> = true; // expected-error{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<typename T> requires C1<T>
+bool e = false;
+
+template<typename T>
+bool e<T> = true; // expected-error{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<typename T>
+constexpr int f = 1;
+
+template<typename T> requires C1<T> && C2<T>
+constexpr int f<T> = 2;
+
+template<typename T> requires C1<T> || C2<T>
+constexpr int f<T> = 3;
+
+static_assert(f<unsigned> == 2);
+static_assert(f<char[10]> == 3);
+static_assert(f<char> == 1);
+
+
+
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/function-templates.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/function-templates.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T> requires sizeof(T) >= 4
+bool a() { return false; } // expected-note {{candidate function [with T = unsigned int]}}
+
+template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10
+bool a() { return true; } // expected-note {{candidate function [with T = unsigned int]}}
+
+bool av = a<unsigned>(); // expected-error {{call to 'a' is ambiguous}}
+
+template<typename T>
+concept C1 = sizeof(T) >= 4;
+
+template<typename T> requires C1<T>
+constexpr bool b() { return false; }
+
+template<typename T> requires C1<T> && sizeof(T) <= 10
+constexpr bool b() { return true; }
+
+static_assert(b<int>());
+static_assert(!b<int[10]>());
+
+template<typename T>
+concept C2 = sizeof(T) > 1 && sizeof(T) <= 8;
+
+template<typename T>
+bool c() { return false; }
+
+template<typename T> requires C1<T>
+bool c() { return true; }
+
+template<typename T> requires C1<T>
+constexpr bool d() { return false; }
+
+template<typename T>
+constexpr bool d() { return true; }
+
+static_assert(!d<int>());
+
+template<typename T>
+constexpr int e() { return 1; }
+
+template<typename T> requires C1<T> && C2<T>
+constexpr int e() { return 2; }
+
+template<typename T> requires C1<T> || C2<T>
+constexpr int e() { return 3; }
+
+static_assert(e<unsigned>() == 2);
+static_assert(e<char[10]>() == 3);
+static_assert(e<char>() == 1);
+
+
+
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T> requires sizeof(T) >= 4
+class A{}; // expected-note{{template is declared here}}
+
+template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10
+class A<T>{}; // expected-error{{class template partial specialization is not more specialized than the primary template}}
+
+template<typename T>
+concept C1 = sizeof(T) >= 4;
+
+template<typename T> requires C1<T>
+class B{};
+
+template<typename T> requires C1<T> && sizeof(T) <= 10
+class B<T>{};
+
+template<typename T>
+concept C2 = sizeof(T) > 1 && sizeof(T) <= 8;
+
+template<typename T>
+class C{};
+
+template<typename T> requires C1<T>
+class C<T>{};
+
+template<typename T>
+class D{}; // expected-note{{previous definition is here}}
+
+template<typename T>
+class D<T>{}; // expected-error{{class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}} expected-error{{redefinition of 'D'}}
+
+template<typename T> requires C1<T> // expected-note{{previous template declaration is here}}
+class E{};
+
+template<typename T> // expected-error{{associated constraints differ in template redeclaration}}
+class E<T>{}; // expected-error{{class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+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(F<unsigned>::value == 2);
+static_assert(F<char[10]>::value == 3);
+static_assert(F<char>::value == 1);
+
+template<typename T1, typename T2>
+concept C3 = true;
+
+template<typename... Ts>
+concept C4 = C3<Ts...>;
+
+// C4 is normalized to C3<Ts...>@<C4's definition> because there is a pack
+// expansion into a non-pack parameter. therefore the two C4<T...> subsume each
+// other and the following is non-ambiguous.
+
+template<typename... T> requires C4<T...>
+struct G { };
+
+template<typename... T> requires C4<T...> && C4<int, short>
+struct G<T...> { };
+
+// Here the two C3s cannot be normalized further, and do not subsume each other
+// because they originate in two different locations in code.
+
+template<typename... T> requires C3<T...>
+struct H { }; // expected-note {{template is declared here}}
+
+template<typename... T> requires C3<T...> && C4<int, short>
+struct H<T...> { }; // expected-error {{class template partial specialization is not more specialized than the primary template}}
+
+// Make sure atomic constraints subsume each other only if their parameter
+// mappings are identical.
+
+template<typename T, typename U> requires C2<T>
+struct I { }; // expected-note {{template is declared here}}
+
+template<typename T, typename U> requires C2<U>
+struct I<T, U> { }; // expected-error {{class template partial specialization is not more specialized than the primary template}}
\ No newline at end of file
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.normal/p1.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.normal/p1.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+namespace maybe_incorrect_args {
+  template<typename U, typename T>
+  concept C = true;
+
+  // diagnostic expected here - the C<Ts...>s are treated as atomic, and since
+  // they originate from different source-level constructs, they do not subsume
+  // each other.
+  template<typename... Ts> requires C<Ts...>
+  struct A {}; // expected-note{{template is declared here}}
+
+  template<typename... Ts> requires C<Ts...> && true
+  struct A<Ts...> {}; // expected-error{{class template partial specialization is not more specialized than the primary template}}
+}
+
+namespace ill_formed_subst {
+
+  template<typename T>
+  struct B; // expected-note 2{{template is declared here}}
+
+  template<typename T>
+  concept C1 = true;
+
+  template<typename T, typename U>
+  concept C2 = C1<typename B<U>::foo>; // expected-error 2{{implicit instantiation of undefined template 'ill_formed_subst::B<int>'}} expected-note 2{{could not substitute template arguments into C1<typename B<U>::foo> [with T = type-parameter-0-0, U = int]. Template arguments to a concept specialization expression must be valid expressions}}
+
+  template<typename T> requires C2<T, int>
+  struct A {}; // expected-note {{template is declared here}}
+
+  template<typename T> requires C2<T, int> && true
+  struct A<T> {}; // expected-error {{class template partial specialization is not more specialized than the primary template}}
+}
+
+namespace incorrect_args_after_subst {
+  template<typename T>
+  concept C1 = true; // expected-note 2{{template is declared here}}
+
+  template<typename... Ts>
+  concept C2 = C1<Ts...>; // expected-error 2{{too many template arguments for template 'C1'}} expected-note 2{{could not substitute template arguments into C1<Ts...> [with Ts = <type-parameter-0-0, type-parameter-0-0>] - the resulting template argument list does not match the concept's parameter list}}
+
+  template<typename T> requires C2<T, T>
+  struct A {}; // expected-note{{template is declared here}}
+
+  template<typename T> requires C2<T, T> && true
+  struct A<T> {}; // expected-error{{class template partial specialization is not more specialized than the primary template}}
+}
+
+namespace maybe_incorrect_args_after_subst {
+  template<typename T, typename U>
+  concept C1 = true;
+
+  template<typename... Us>
+  concept C2 = C1<Us...>;
+
+  // no diagnostic expected here - C1<Us...> is treated as atomic, and since it
+  // originates at the same source level construct, the specialized subsumes the
+  // primary.
+  template<typename... Ts> requires C2<Ts...>
+  struct A {};
+
+  template<typename... Ts> requires C2<Ts...> && true
+  struct A<Ts...> {};
+}
\ No newline at end of file
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
===================================================================
--- test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
@@ -9,23 +9,6 @@
 
 } // end namespace nodiag
 
-namespace diag {
-
-template <typename T> requires true // expected-note{{previous template declaration is here}}
-int A();
-template <typename T> int A(); // expected-error{{associated constraints differ in template redeclaration}}
-
-template <typename T> int B(); // expected-note{{previous template declaration is here}}
-template <typename T> requires true // expected-error{{associated constraints differ in template redeclaration}}
-int B();
-
-template <typename T> requires true // expected-note{{previous template declaration is here}}
-int C();
-template <typename T> requires !0 // expected-error{{associated constraints differ in template redeclaration}}
-int C();
-
-} // end namespace diag
-
 namespace nodiag {
 
 struct AA {
@@ -42,11 +25,11 @@
 
 template <unsigned N>
 struct TA {
-  template <template <unsigned> class TT> requires TT<N>::happy // expected-note{{previous template declaration is here}}
+  template <template <unsigned> class TT> requires TT<N>::happy
   int A();
 };
 
 template <unsigned N>
-template <template <unsigned> class TT> int TA<N>::A() { return sizeof(TT<N>); } // expected-error{{associated constraints differ in template redeclaration}}
+template <template <unsigned> class TT> int TA<N>::A() { return sizeof(TT<N>); } // expected-error{{out-of-line definition of 'A' does not match any declaration in 'TA<N>'}}
 
 } // end namespace diag
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -1458,11 +1458,11 @@
 
 void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
                                     ClassTemplatePartialSpecializationDecl *D) {
-  VisitClassTemplateSpecializationDecl(D);
-
   Record.AddTemplateParameterList(D->getTemplateParameters());
   Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
 
+  VisitClassTemplateSpecializationDecl(D);
+
   // These are read/set from/to the first declaration.
   if (D->getPreviousDecl() == nullptr) {
     Record.AddDeclRef(D->getInstantiatedFromMember());
@@ -1523,11 +1523,11 @@
 
 void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
     VarTemplatePartialSpecializationDecl *D) {
-  VisitVarTemplateSpecializationDecl(D);
-
   Record.AddTemplateParameterList(D->getTemplateParameters());
   Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
 
+  VisitVarTemplateSpecializationDecl(D);
+
   // These are read/set from/to the first declaration.
   if (D->getPreviousDecl() == nullptr) {
     Record.AddDeclRef(D->getInstantiatedFromMember());
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -2142,12 +2142,14 @@
 
 void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
                                     ClassTemplatePartialSpecializationDecl *D) {
-  RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
-
+  // We need to read the template params first because redeclarable is going to
+  // need them for profiling
   TemplateParameterList *Params = Record.readTemplateParameterList();
   D->TemplateParams.setPointer(Params);
   D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
 
+  RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
+
   // These are read/set from/to the first declaration.
   if (ThisDeclID == Redecl.getFirstID()) {
     D->InstantiatedFromMember.setPointer(
@@ -2253,12 +2255,12 @@
 ///        using Template(Partial)SpecializationDecl as input type.
 void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
     VarTemplatePartialSpecializationDecl *D) {
-  RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
-
   TemplateParameterList *Params = Record.readTemplateParameterList();
   D->TemplateParams.setPointer(Params);
   D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
 
+  RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
+
   // These are read/set from/to the first declaration.
   if (ThisDeclID == Redecl.getFirstID()) {
     D->InstantiatedFromMember.setPointer(
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3232,7 +3232,12 @@
   // in the member template's set of class template partial specializations.
   void *InsertPos = nullptr;
   ClassTemplateSpecializationDecl *PrevDecl
-    = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
+    = ClassTemplate->findPartialSpecialization(Converted,
+                                               // TODO: Concepts - change this
+                                               // to associated constraints once
+                                               // we have them.
+                                               InstParams->getRequiresClause(),
+                                               InsertPos);
 
   // Build the canonical type that describes the converted template
   // arguments of the class template partial specialization.
@@ -3363,7 +3368,12 @@
   // in the member template's set of variable template partial specializations.
   void *InsertPos = nullptr;
   VarTemplateSpecializationDecl *PrevDecl =
-      VarTemplate->findPartialSpecialization(Converted, InsertPos);
+      VarTemplate->findPartialSpecialization(Converted,
+                                             // TODO: Concepts - change this
+                                             // to associated constraints once
+                                             // we have them.
+                                             InstParams->getRequiresClause(),
+                                             InsertPos);
 
   // Build the canonical type that describes the converted template
   // arguments of the variable template partial specialization.
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -4755,6 +4755,65 @@
   return true;
 }
 
+/// Determine whether one partial specialization, P1, is at least as
+/// specialized than another, P2, based on deduction checking.
+///
+/// \tparam TemplateLikeDecl The kind of P2, which must be a TemplateDecl or
+/// {Class,Var}TemplatePartialSpecializationDecl.
+/// \param T1 The injected-class-name of P1 (faked for a variable template).
+/// \param T2 The injected-class-name of P2 (faked for a variable template).
+template<typename TemplateLikeDecl>
+static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
+                                     TemplateLikeDecl *P2,
+                                     TemplateDeductionInfo &Info) {
+    // C++ [temp.class.order]p1:
+    //   For two class template partial specializations, the first is at least as
+    //   specialized as the second if, given the following rewrite to two
+    //   function templates, the first function template is at least as
+    //   specialized as the second according to the ordering rules for function
+    //   templates (14.6.6.2):
+    //     - the first function template has the same template parameters as the
+    //       first partial specialization and has a single function parameter
+    //       whose type is a class template specialization with the template
+    //       arguments of the first partial specialization, and
+    //     - the second function template has the same template parameters as the
+    //       second partial specialization and has a single function parameter
+    //       whose type is a class template specialization with the template
+    //       arguments of the second partial specialization.
+    //
+    // Rather than synthesize function templates, we merely perform the
+    // equivalent partial ordering by performing deduction directly on
+    // the template arguments of the class template partial
+    // specializations. This computation is slightly simpler than the
+    // general problem of function template partial ordering, because
+    // class template partial specializations are more constrained. We
+    // know that every template parameter is deducible from the class
+    // template partial specialization's template arguments, for
+    // example.
+    SmallVector<DeducedTemplateArgument, 4> Deduced;
+
+    // Determine whether P1 is at least as specialized as P2.
+    Deduced.resize(P2->getTemplateParameters()->size());
+    if (DeduceTemplateArgumentsByTypeMatch(S, P2->getTemplateParameters(),
+                                           T2, T1, Info, Deduced, TDF_None,
+            /*PartialOrdering=*/true))
+        return false;
+
+    SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+                                                 Deduced.end());
+    Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs,
+                                     Info);
+    auto *TST1 = T1->castAs<TemplateSpecializationType>();
+    if (FinishTemplateArgumentDeduction(
+            S, P2, /*PartialOrdering=*/true,
+            TemplateArgumentList(TemplateArgumentList::OnStack,
+                                 TST1->template_arguments()),
+            Deduced, Info))
+        return false;
+
+    return true;
+}
+
 /// \brief Determine whether this a function template whose parameter-type-list
 /// ends with a function parameter pack.
 static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
@@ -4801,6 +4860,21 @@
                                  TemplatePartialOrderingContext TPOC,
                                  unsigned NumCallArguments1,
                                  unsigned NumCallArguments2) {
+
+  auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * {
+    bool MoreConstrained1 = IsMoreConstrained(FT1,
+                                              FT1->getAssociatedConstraints(),
+                                              FT2,
+                                              FT2->getAssociatedConstraints());
+    bool MoreConstrained2 = IsMoreConstrained(FT2,
+                                              FT2->getAssociatedConstraints(),
+                                              FT1,
+                                              FT1->getAssociatedConstraints());
+    if (MoreConstrained1 == MoreConstrained2)
+      return nullptr;
+    return MoreConstrained1 ? FT1 : FT2;
+  };
+
   bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
                                           NumCallArguments1);
   bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
@@ -4810,7 +4884,7 @@
     return Better1 ? FT1 : FT2;
 
   if (!Better1 && !Better2) // Neither is better than the other
-    return nullptr;
+    return JudgeByConstraints();
 
   // FIXME: This mimics what GCC implements, but doesn't match up with the
   // proposed resolution for core issue 692. This area needs to be sorted out,
@@ -4820,7 +4894,7 @@
   if (Variadic1 != Variadic2)
     return Variadic1? FT2 : FT1;
 
-  return nullptr;
+  return JudgeByConstraints();
 }
 
 /// \brief Determine if the two templates are equivalent.
@@ -4934,66 +5008,6 @@
   return SpecEnd;
 }
 
-/// Determine whether one partial specialization, P1, is at least as
-/// specialized than another, P2.
-///
-/// \tparam TemplateLikeDecl The kind of P2, which must be a
-/// TemplateDecl or {Class,Var}TemplatePartialSpecializationDecl.
-/// \param T1 The injected-class-name of P1 (faked for a variable template).
-/// \param T2 The injected-class-name of P2 (faked for a variable template).
-template<typename TemplateLikeDecl>
-static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
-                                     TemplateLikeDecl *P2,
-                                     TemplateDeductionInfo &Info) {
-  // TODO: Concepts: Regard constraints
-  // C++ [temp.class.order]p1:
-  //   For two class template partial specializations, the first is at least as
-  //   specialized as the second if, given the following rewrite to two
-  //   function templates, the first function template is at least as
-  //   specialized as the second according to the ordering rules for function
-  //   templates (14.6.6.2):
-  //     - the first function template has the same template parameters as the
-  //       first partial specialization and has a single function parameter
-  //       whose type is a class template specialization with the template
-  //       arguments of the first partial specialization, and
-  //     - the second function template has the same template parameters as the
-  //       second partial specialization and has a single function parameter
-  //       whose type is a class template specialization with the template
-  //       arguments of the second partial specialization.
-  //
-  // Rather than synthesize function templates, we merely perform the
-  // equivalent partial ordering by performing deduction directly on
-  // the template arguments of the class template partial
-  // specializations. This computation is slightly simpler than the
-  // general problem of function template partial ordering, because
-  // class template partial specializations are more constrained. We
-  // know that every template parameter is deducible from the class
-  // template partial specialization's template arguments, for
-  // example.
-  SmallVector<DeducedTemplateArgument, 4> Deduced;
-
-  // Determine whether P1 is at least as specialized as P2.
-  Deduced.resize(P2->getTemplateParameters()->size());
-  if (DeduceTemplateArgumentsByTypeMatch(S, P2->getTemplateParameters(),
-                                         T2, T1, Info, Deduced, TDF_None,
-                                         /*PartialOrdering=*/true))
-    return false;
-
-  SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
-                                               Deduced.end());
-  Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs,
-                                   Info);
-  auto *TST1 = T1->castAs<TemplateSpecializationType>();
-  if (FinishTemplateArgumentDeduction(
-          S, P2, /*PartialOrdering=*/true,
-          TemplateArgumentList(TemplateArgumentList::OnStack,
-                               TST1->template_arguments()),
-          Deduced, Info))
-    return false;
-
-  return true;
-}
-
 /// \brief Returns the more specialized class template partial specialization
 /// according to the rules of partial ordering of class template partial
 /// specializations (C++ [temp.class.order]).
@@ -5016,8 +5030,19 @@
   bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
   bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
 
-  if (Better1 == Better2)
-    return nullptr;
+  if (Better1 == Better2) {
+    bool MoreConstrained1 = IsMoreConstrained(PS1,
+                                              PS1->getAssociatedConstraints(),
+                                              PS2,
+                                              PS2->getAssociatedConstraints());
+    bool MoreConstrained2 = IsMoreConstrained(PS2,
+                                              PS2->getAssociatedConstraints(),
+                                              PS1,
+                                              PS1->getAssociatedConstraints());
+    if (MoreConstrained1 == MoreConstrained2)
+      return nullptr;
+    return MoreConstrained1 ? PS1 : PS2;
+  }
 
   return Better1 ? PS1 : PS2;
 }
@@ -5027,11 +5052,24 @@
   ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
   QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
   QualType PartialT = Spec->getInjectedSpecializationType();
+  auto JudgeByConstraints = [&] {
+    bool MoreConstrainedPrimary = IsMoreConstrained(Primary,
+                                            Primary->getAssociatedConstraints(),
+                                            Spec,
+                                            Spec->getAssociatedConstraints());
+    bool MoreConstrainedSpec = IsMoreConstrained(Spec,
+                                           Spec->getAssociatedConstraints(),
+                                           Primary,
+                                           Primary->getAssociatedConstraints());
+    if (MoreConstrainedPrimary == MoreConstrainedSpec)
+      return false;
+    return MoreConstrainedSpec;
+  };
   if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
-    return false;
-  if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
+    return JudgeByConstraints();
+  if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)){
     Info.clearSFINAEDiagnostic();
-    return false;
+    return JudgeByConstraints();
   }
   return true;
 }
@@ -5056,8 +5094,20 @@
   bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
   bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
 
-  if (Better1 == Better2)
-    return nullptr;
+  if (Better1 == Better2) {
+    bool MoreConstrained1 = IsMoreConstrained(PS1,
+                                              PS1->getAssociatedConstraints(),
+                                              PS2,
+                                              PS2->getAssociatedConstraints());
+    bool MoreConstrained2 = IsMoreConstrained(PS2,
+                                              PS2->getAssociatedConstraints(),
+                                              PS1,
+                                              PS1->getAssociatedConstraints());
+    if (MoreConstrained1 == MoreConstrained2) {
+      return nullptr;
+    }
+    return MoreConstrained1 ? PS1 : PS2;
+  }
 
   return Better1 ? PS1 : PS2;
 }
@@ -5077,11 +5127,26 @@
       CanonTemplate, PrimaryArgs);
   QualType PartialT = Context.getTemplateSpecializationType(
       CanonTemplate, Spec->getTemplateArgs().asArray());
+
+  auto JudgeByConstraints = [&] {
+      bool MoreConstrainedPrimary = IsMoreConstrained(Primary,
+                                            Primary->getAssociatedConstraints(),
+                                            Spec,
+                                            Spec->getAssociatedConstraints());
+      bool MoreConstrainedSpec = IsMoreConstrained(Spec,
+                                           Spec->getAssociatedConstraints(),
+                                           Primary,
+                                           Primary->getAssociatedConstraints());
+      if (MoreConstrainedPrimary == MoreConstrainedSpec)
+        return false;
+      return MoreConstrainedSpec;
+  };
+
   if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
-    return false;
-  if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
+    return JudgeByConstraints();
+  if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)){
     Info.clearSFINAEDiagnostic();
-    return false;
+    return JudgeByConstraints();
   }
   return true;
 }
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -915,9 +915,9 @@
   auto CheckValidDeclSpecifiers = [this, &D] {
     // C++ [temp.param]
     // p1 
-    //   template-parameter:
-    //     ...
-    //     parameter-declaration
+    //   template-parameter:
+    //     ...
+    //     parameter-declaration
     // p2 
     //   ... A storage class shall not be specified in a template-parameter
     //   declaration.
@@ -2009,11 +2009,7 @@
   if (OldParams &&
       !CheckRedeclarationConstraintMatch(OldParams->getRequiresClause(),
                                          NewParams->getRequiresClause())) {
-    Diag(NewParams->getTemplateLoc(),
-         diag::err_template_different_associated_constraints);
-    Diag(OldParams->getTemplateLoc(),  diag::note_template_prev_declaration)
-        << /*declaration*/0;
-
+    DiagnoseRedeclarationConstraintMismatch(OldParams, NewParams);
     Invalid = true;
   }
 
@@ -3597,7 +3593,11 @@
     }
 
     if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
-                                Converted)) {
+                                Converted)
+        && (!Context.getLangOpts().ConceptsTS
+            // TODO: Concepts: change this to getAssociatedConstraints when we
+            // have them.
+            || TemplateParams->getRequiresClause() == nullptr)) {
       // C++ [temp.class.spec]p9b3:
       //
       //   -- The argument list of the specialization shall not be identical
@@ -3617,7 +3617,12 @@
 
   if (IsPartialSpecialization)
     // FIXME: Template parameter list matters too
-    PrevDecl = VarTemplate->findPartialSpecialization(Converted, InsertPos);
+    PrevDecl = VarTemplate->findPartialSpecialization(Converted,
+                                            // TODO: Concepts - replace with
+                                            // AssociatedConstraints once we
+                                            // have them.
+                                            TemplateParams->getRequiresClause(),
+                                                      InsertPos);
   else
     PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
 
@@ -3934,7 +3939,7 @@
 
   // Check that the template argument list is well-formed for this template.
   SmallVector<TemplateArgument, 4> Converted;
-  if (CheckTemplateArgumentList(Template, TemplateLoc,
+  if (CheckTemplateArgumentList(Template, NameInfo.getLoc(),
         const_cast<TemplateArgumentListInfo &>(*TemplateArgs), false,
           Converted, /*UpdateArgsWithConversions=*/false))
     return ExprError();
@@ -6763,6 +6768,7 @@
                                        bool Complain,
                                      Sema::TemplateParameterListEqualKind Kind,
                                        SourceLocation TemplateArgLoc) {
+  // TODO: Concepts: Check constrained-parameter constraints here.
   // Check the actual kind (type, non-type, template).
   if (Old->getKind() != New->getKind()) {
     if (Complain) {
@@ -6972,6 +6978,13 @@
     return false;
   }
 
+  if (!CheckRedeclarationConstraintMatch(Old->getRequiresClause(),
+                                         New->getRequiresClause())) {
+    if (Complain)
+      DiagnoseRedeclarationConstraintMismatch(Old, New);
+    return false;
+  }
+
   return true;
 }
 
@@ -7521,7 +7534,12 @@
 
   if (isPartialSpecialization)
     // FIXME: Template parameter list matters, too
-    PrevDecl = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
+    PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
+                                            // TODO: Concepts: Replace with
+                                            // AssociatedConstraints once we
+                                            // have them.
+                                            TemplateParams->getRequiresClause(),
+                                                        InsertPos);
   else
     PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
 
@@ -7545,7 +7563,11 @@
                                                       Converted);
 
     if (Context.hasSameType(CanonType,
-                        ClassTemplate->getInjectedClassNameSpecialization())) {
+                        ClassTemplate->getInjectedClassNameSpecialization())
+        && (!Context.getLangOpts().ConceptsTS
+            // TODO: Concepts: change this to getAssociatedConstraints when we
+            // have them.
+            || TemplateParams->getRequiresClause() == nullptr)) {
       // C++ [temp.class.spec]p9b3:
       //
       //   -- The argument list of the specialization shall not be identical
Index: lib/Sema/SemaConcept.cpp
===================================================================
--- lib/Sema/SemaConcept.cpp
+++ lib/Sema/SemaConcept.cpp
@@ -62,6 +62,16 @@
   return false;
 }
 
+void
+Sema::DiagnoseRedeclarationConstraintMismatch(const TemplateParameterList *Old,
+                                              const TemplateParameterList *New){
+  Diag(New->getTemplateLoc(),
+       diag::err_template_different_associated_constraints);
+
+  Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
+        << /*declaration*/0;
+}
+
 template<typename TemplateDeclT>
 static bool
 calculateConstraintSatisfaction(Sema& S, TemplateDeclT *Template,
@@ -345,4 +355,382 @@
     diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
     First = false;
   }
+}
+namespace {
+struct AtomicConstraint {
+  AtomicConstraint(Expr *ConstraintExpr,
+      const ASTTemplateArgumentListInfo *ParameterMapping = nullptr) :
+      ConstraintExpr{ConstraintExpr}, ParameterMapping{ParameterMapping} {}
+
+  bool subsumes(ASTContext &C, const AtomicConstraint &Other) const {
+    // C++ [temp.constr.order] p2
+    //   - an atomic constraint A subsumes another atomic constraint B
+    //     if and only if the A and B are identical [...]
+    //
+    // C++ [temp.constr.atomic] p2
+    //   Two atomic constraints are identical if they are formed from the
+    //   same expression and the targets of the parameter mappings are
+    //   equivalent according to the rules for expressions [...]
+
+    // We do not actually substitute the parameter mappings, therefore the
+    // constraint expressions are the originals, and comparing them will
+    // suffice.
+    if (ConstraintExpr != Other.ConstraintExpr)
+      return false;
+
+    // Check that the parameter lists are identical
+    if ((!ParameterMapping) != (!Other.ParameterMapping))
+      return false;
+    if (!ParameterMapping)
+      return true;
+    if (ParameterMapping->NumTemplateArgs !=
+        Other.ParameterMapping->NumTemplateArgs)
+      return false;
+
+    for (unsigned I = 0, S = ParameterMapping->NumTemplateArgs; I < S; ++I)
+      if (!C.getCanonicalTemplateArgument(
+                ParameterMapping->arguments()[I].getArgument())
+               .structurallyEquals(C.getCanonicalTemplateArgument(
+                   Other.ParameterMapping->arguments()[I].getArgument())))
+        return false;
+
+
+    return true;
+  }
+
+  Expr *ConstraintExpr;
+  const ASTTemplateArgumentListInfo *ParameterMapping;
+};
+
+class NormalizedConstraint {
+public:
+  enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
+
+private:
+  using CompoundConstraint = llvm::PointerIntPair<
+      std::pair<NormalizedConstraint, NormalizedConstraint> *, 1,
+      CompoundConstraintKind>;
+
+  llvm::PointerUnion<AtomicConstraint *, CompoundConstraint> Constraint;
+
+  NormalizedConstraint(AtomicConstraint *C) : Constraint{C} {};
+  NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS,
+                       NormalizedConstraint RHS, CompoundConstraintKind Kind)
+      : Constraint{CompoundConstraint{
+            new std::pair<NormalizedConstraint, NormalizedConstraint>{LHS, RHS},
+            Kind}} {};
+
+public:
+  CompoundConstraintKind getCompoundKind() const {
+    assert(!isAtomic() && "getCompoundKind called on atomic constraint.");
+    return Constraint.get<CompoundConstraint>().getInt();
+  }
+
+  bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); }
+
+  NormalizedConstraint &getLHS() const {
+    assert(!isAtomic() && "getLHS called on atomic constraint.");
+    return Constraint.get<CompoundConstraint>().getPointer()->first;
+  }
+
+  NormalizedConstraint &getRHS() const {
+    assert(!isAtomic() && "getRHS called on atomic constraint.");
+    return Constraint.get<CompoundConstraint>().getPointer()->second;
+  }
+
+  AtomicConstraint *getAtomicConstraint() const {
+    assert(isAtomic() &&
+           "getAtomicConstraint called on non-atomic constraint.");
+    return Constraint.get<AtomicConstraint *>();
+  }
+  static llvm::Optional<NormalizedConstraint> fromConstraintExpr(
+      Sema &S, Expr *E, TemplateDecl *TD = nullptr,
+      const ASTTemplateArgumentListInfo *ParameterMapping = nullptr) {
+    assert(E != nullptr);
+
+    // C++ [temp.constr.normal]p1.1
+    // - The normal form of an expression (E) is the normal form of E.
+    if (ParenExpr *P = dyn_cast<ParenExpr>(E))
+      return fromConstraintExpr(S, P->getSubExpr(), TD, ParameterMapping);
+    if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+      if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
+        auto LHS = fromConstraintExpr(S, BO->getLHS(), TD, ParameterMapping);
+        if (!LHS)
+          return llvm::Optional<NormalizedConstraint>{};
+        auto RHS = fromConstraintExpr(S, BO->getRHS(), TD, ParameterMapping);
+        if (!RHS)
+          return llvm::Optional<NormalizedConstraint>{};
+
+        return NormalizedConstraint(
+            S.Context, *LHS, *RHS,
+            BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction);
+      }
+    } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(E)) {
+      const ASTTemplateArgumentListInfo *Mapping =
+          CSE->getTemplateArgumentListInfo();
+      if (!ParameterMapping) {
+        llvm::SmallVector<TemplateArgument, 4> TempList;
+        bool InstantiationDependent = false;
+        TemplateArgumentListInfo TALI(Mapping->LAngleLoc, Mapping->RAngleLoc);
+        for (auto &Arg : Mapping->arguments())
+          TALI.addArgument(Arg);
+        bool Failed = S.CheckTemplateArgumentList(CSE->getNamedConcept(),
+            E->getLocStart(), TALI, /*PartialTemplateArgs=*/false, TempList,
+            /*UpdateArgsWithConversions=*/false, &InstantiationDependent);
+        // The potential failure case here is this:
+        //
+        // template<typename U>
+        // concept C = true;
+        //
+        // template<typename T>
+        // void foo() requires C<T, T> // The immediate constraint expr
+        //                             // contains a CSE with incorrect no.
+        //                             // of arguments.
+        // {}
+        // This will be handled when C<T, T> is parsed.
+        assert(
+            !Failed &&
+            "Unmatched arguments in top level concept specialization "
+            "expression should've been caught while it was being constructed");
+
+        if (InstantiationDependent)
+          // The case is this:
+          //
+          // template<typename U, typename T>
+          // concept C = true;
+          //
+          // template<typename... Ts>
+          // void foo() requires C<Ts...> // The immediate constraint expr
+          //                              // contains a CSE whose parameters
+          //                              // are not mappable to arguments
+          //                              // without concrete values.
+          // {}
+          //
+          // Just treat C<Ts...> as an atomic constraint.
+          return NormalizedConstraint{new (S.Context)
+                                          AtomicConstraint(E, Mapping)};
+
+        return fromConstraintExpr(S,
+                                  CSE->getNamedConcept()->getConstraintExpr(),
+                                  CSE->getNamedConcept(), Mapping);
+      }
+
+      assert(TD && "ParameterMapping provided without TemplateDecl");
+
+      TemplateArgumentListInfo TALI(ParameterMapping->LAngleLoc,
+                                    ParameterMapping->RAngleLoc);
+      for (auto &Arg : ParameterMapping->arguments())
+        TALI.addArgument(Arg);
+      llvm::SmallVector<TemplateArgument, 4> TempList;
+      bool InstantiationDependent = false;
+      bool Success =
+          !S.CheckTemplateArgumentList(TD, ParameterMapping->LAngleLoc,
+                                       TALI, /*PartialTemplateArgs=*/false,
+                                       TempList,
+                                       /*UpdateArgsWithConversions=*/true,
+                                       &InstantiationDependent) &&
+          !InstantiationDependent;
+      assert(Success && "ParameterMapping should have already been cheked "
+                        "against template argument list earlier.");
+
+      auto DiagnoseSubstitutionError = [&](unsigned int Diag) {
+        std::string TemplateArgString = S.getTemplateArgumentBindingsText(
+            TD->getTemplateParameters(), TempList.data(), TempList.size());
+        S.Diag(CSE->getLocStart(), Diag) << CSE << TemplateArgString;
+      };
+
+      MultiLevelTemplateArgumentList MLTAL;
+      MLTAL.addOuterTemplateArguments(TempList);
+
+      ExprResult Result = S.SubstExpr(CSE, MLTAL);
+      if (!Result.isUsable() || Result.isInvalid()) {
+        // C++ [temp.constr.normal]
+        // If any such substitution results in an invalid type or
+        // expression, the program is ill-formed; no diagnostic is required.
+
+        // A diagnostic was already emitted from the substitution , but
+        // we'll let the user know why it's not SFINAEd from them.
+        DiagnoseSubstitutionError(
+            diag::note_could_not_normalize_argument_substitution_failed);
+        return llvm::Optional<NormalizedConstraint>{};
+      }
+      Mapping = cast<ConceptSpecializationExpr>(Result.get())
+                    ->getTemplateArgumentListInfo();
+
+      TemplateArgumentListInfo SubstTALI(ParameterMapping->LAngleLoc,
+                                         ParameterMapping->RAngleLoc);
+      for (auto &Arg : ParameterMapping->arguments())
+        SubstTALI.addArgument(Arg);
+      llvm::SmallVector<TemplateArgument, 4> Converted;
+      if (S.CheckTemplateArgumentList(
+              CSE->getNamedConcept(), CSE->getLocStart(), SubstTALI,
+              /*PartialTemplateArgs=*/false, Converted,
+              /*UpdateArgsWithConversions=*/true, &InstantiationDependent)) {
+        // The case is this:
+        //
+        // template<typename T, typename U>
+        // concept C1 = true;
+        //
+        // template<typename... Ts>
+        // concept C2 = C1<Ts...>; // After substituting Ts = {T}, the
+        //                         // resulting argument list does not match
+        //                         // the parameter list.
+        //
+        // template<typename T>
+        // void foo() requires C2<T> {}
+        DiagnoseSubstitutionError(
+            diag::note_could_not_normalize_unmatched_argument_list_after_subst);
+        return llvm::Optional<NormalizedConstraint>{};
+      }
+      if (InstantiationDependent)
+        // The case is this:
+        //
+        // template<typename T, typename U>
+        // concept C1 = true;
+        //
+        // template<typename... Us>
+        // concept C2 = C1<Us...>; // After substituting Us = {Ts}, we cannot
+        //                         // match arguments to parameters.
+        //
+        // template<typename... Ts>
+        // void foo() requires C2<T...> {}
+        //
+        // Treat the CSE as an atomic expression.
+        return NormalizedConstraint{new (S.Context)
+                                        AtomicConstraint(E, ParameterMapping)};
+
+      return fromConstraintExpr(S, CSE->getNamedConcept()->getConstraintExpr(),
+                                CSE->getNamedConcept(), Mapping);
+    }
+    return NormalizedConstraint{new (S.Context)
+                                    AtomicConstraint(E, ParameterMapping)};
+  }
+};
+} // namespace
+
+using NormalForm =
+    llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>;
+
+static NormalForm makeCNF(const NormalizedConstraint &Normalized) {
+  if (Normalized.isAtomic())
+    return {{Normalized.getAtomicConstraint()}};
+
+  NormalForm LCNF = makeCNF(Normalized.getLHS());
+  NormalForm RCNF = makeCNF(Normalized.getRHS());
+  if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) {
+    LCNF.reserve(LCNF.size() + RCNF.size());
+    while (!RCNF.empty())
+      LCNF.push_back(std::move(RCNF.pop_back_val()));
+    return LCNF;
+  }
+
+  // Disjunction
+  NormalForm Res;
+  Res.reserve(LCNF.size() * RCNF.size());
+  for (auto &LDisjunction : LCNF)
+    for (auto &RDisjunction : RCNF) {
+      NormalForm::value_type Combined;
+      Combined.reserve(LDisjunction.size() + RDisjunction.size());
+      std::copy(LDisjunction.begin(), LDisjunction.end(),
+                std::back_inserter(Combined));
+      std::copy(RDisjunction.begin(), RDisjunction.end(),
+                std::back_inserter(Combined));
+      Res.emplace_back(Combined);
+    }
+  return Res;
+}
+
+static NormalForm makeDNF(const NormalizedConstraint &Normalized) {
+  if (Normalized.isAtomic())
+    return {{Normalized.getAtomicConstraint()}};
+
+  NormalForm LDNF = makeDNF(Normalized.getLHS());
+  NormalForm RDNF = makeDNF(Normalized.getRHS());
+  if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) {
+    LDNF.reserve(LDNF.size() + RDNF.size());
+    while (!RDNF.empty())
+      LDNF.push_back(std::move(RDNF.pop_back_val()));
+    return LDNF;
+  }
+
+  // Conjunction
+  NormalForm Res;
+  Res.reserve(LDNF.size() * RDNF.size());
+  for (auto &LConjunction : LDNF) {
+    for (auto &RConjunction : RDNF) {
+      NormalForm::value_type Combined;
+      Combined.reserve(LConjunction.size() + RConjunction.size());
+      std::copy(LConjunction.begin(), LConjunction.end(),
+                std::back_inserter(Combined));
+      std::copy(RConjunction.begin(), RConjunction.end(),
+                std::back_inserter(Combined));
+      Res.emplace_back(Combined);
+    }
+  }
+  return Res;
+}
+
+static bool subsumes(Sema &S, Expr *P, Expr *Q) {
+  // C++ [temp.constr.order] p2
+  //   In order to determine if a constraint P subsumes a constraint Q, P is
+  //   transformed into disjunctive normal form, and Q is transformed into
+  //   conjunctive normal form. [...]
+  auto PNormalized = NormalizedConstraint::fromConstraintExpr(S, P);
+  if (!PNormalized)
+    // Program is ill formed at this point.
+    return false;
+  const NormalForm PDNF = makeDNF(*PNormalized);
+
+  auto QNormalized = NormalizedConstraint::fromConstraintExpr(S, Q);
+  if (!QNormalized)
+    // Program is ill formed at this point.
+    return false;
+  const NormalForm QCNF = makeCNF(*QNormalized);
+
+  // C++ [temp.constr.order] p2
+  //   Then, P subsumes Q if and only if, for every disjunctive clause Pi in the
+  //   disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in
+  //   the conjuctive normal form of Q, where [...]
+  for (const auto &Pi : PDNF) {
+    for (const auto &Qj : QCNF) {
+      // C++ [temp.constr.order] p2
+      //   - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if
+      //     and only if there exists an atomic constraint Pia in Pi for which
+      //     there exists an atomic constraint, Qjb, in Qj such that Pia
+      //     subsumes Qjb.
+      bool Found = false;
+      for (const AtomicConstraint *Pia : Pi) {
+        for (const AtomicConstraint *Qjb : Qj) {
+          if (Pia->subsumes(S.Context, *Qjb)) {
+            Found = true;
+            break;
+          }
+        }
+        if (Found)
+          break;
+      }
+      if (!Found) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool Sema::IsMoreConstrained(NamedDecl *D1, Expr *AC1, NamedDecl *D2,
+                             Expr *AC2) {
+  if (!AC1)
+    return AC2 == nullptr;
+  if (!AC2)
+    // TD1 has associated constraints and TD2 does not.
+    return true;
+
+  std::pair<NamedDecl *, NamedDecl *> Key{D1, D2};
+  auto CacheEntry = SubsumptionCache.find(Key);
+  if (CacheEntry != SubsumptionCache.end()) {
+    return CacheEntry->second;
+  }
+  bool Subsumes = subsumes(*this, AC1, AC2);
+  SubsumptionCache.try_emplace(Key, Subsumes);
+  return Subsumes;
 }
\ No newline at end of file
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -256,15 +256,15 @@
   }
 }
 
-template<class EntryType>
+template<class EntryType, typename... ProfileArguments>
 typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
 RedeclarableTemplateDecl::findSpecializationImpl(
-    llvm::FoldingSetVector<EntryType> &Specs, ArrayRef<TemplateArgument> Args,
-    void *&InsertPos) {
+    llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
+    ProfileArguments... ProfileArgs) {
   using SETraits = SpecEntryTraits<EntryType>;
 
   llvm::FoldingSetNodeID ID;
-  EntryType::Profile(ID, Args, getASTContext());
+  EntryType::Profile(ID, ProfileArgs..., getASTContext());
   EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos);
   return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr;
 }
@@ -279,8 +279,8 @@
 #ifndef NDEBUG
     void *CorrectInsertPos;
     assert(!findSpecializationImpl(Specializations,
-                                   SETraits::getTemplateArgs(Entry),
-                                   CorrectInsertPos) &&
+                                   CorrectInsertPos,
+                                   SETraits::getTemplateArgs(Entry)) &&
            InsertPos == CorrectInsertPos &&
            "given incorrect InsertPos for specialization");
 #endif
@@ -337,7 +337,7 @@
 FunctionDecl *
 FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
                                          void *&InsertPos) {
-  return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+  return findSpecializationImpl(getSpecializations(), InsertPos, Args);
 }
 
 void FunctionTemplateDecl::addSpecialization(
@@ -409,7 +409,7 @@
 ClassTemplateSpecializationDecl *
 ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
                                       void *&InsertPos) {
-  return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+  return findSpecializationImpl(getSpecializations(), InsertPos, Args);
 }
 
 void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
@@ -419,8 +419,10 @@
 
 ClassTemplatePartialSpecializationDecl *
 ClassTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
+                                             Expr *AssociatedConstraints,
                                              void *&InsertPos) {
-  return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
+  return findSpecializationImpl(getPartialSpecializations(), InsertPos,
+                                Args, AssociatedConstraints);
 }
 
 void ClassTemplateDecl::AddPartialSpecialization(
@@ -913,9 +915,10 @@
   return Result;
 }
 
-Expr* ClassTemplatePartialSpecializationDecl::getAssociatedConstraints() {
+Expr* ClassTemplatePartialSpecializationDecl::getAssociatedConstraints() const {
   return getOrCollectAssociatedConstraints(getASTContext(),
-           cast<ClassTemplatePartialSpecializationDecl>(getCanonicalDecl())
+           const_cast<ClassTemplatePartialSpecializationDecl*>(
+              cast<ClassTemplatePartialSpecializationDecl>(getCanonicalDecl()))
              ->TemplateParams);
 }
 
@@ -1031,7 +1034,7 @@
 VarTemplateSpecializationDecl *
 VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
                                     void *&InsertPos) {
-  return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+  return findSpecializationImpl(getSpecializations(), InsertPos, Args);
 }
 
 void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
@@ -1041,8 +1044,10 @@
 
 VarTemplatePartialSpecializationDecl *
 VarTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
+                                           Expr *AssociatedConstraints,
                                            void *&InsertPos) {
-  return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
+  return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args,
+                                AssociatedConstraints);
 }
 
 void VarTemplateDecl::AddPartialSpecialization(
@@ -1191,9 +1196,10 @@
   return new (C, ID) VarTemplatePartialSpecializationDecl(C);
 }
 
-Expr* VarTemplatePartialSpecializationDecl::getAssociatedConstraints() {
+Expr* VarTemplatePartialSpecializationDecl::getAssociatedConstraints() const {
   return getOrCollectAssociatedConstraints(getASTContext(),
-           cast<VarTemplatePartialSpecializationDecl>(getCanonicalDecl())
+           const_cast<VarTemplatePartialSpecializationDecl*>(
+             cast<VarTemplatePartialSpecializationDecl>(getCanonicalDecl()))
              ->TemplateParams);
 }
 
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -699,7 +699,7 @@
                                            cast<TemplateTemplateParmDecl>(*P)));
   }
 
-  assert(!TTP->getRequiresClause() &&
+  assert(!TTP->getTemplateParameters()->getRequiresClause() &&
          "Unexpected requires-clause on template template-parameter");
   Expr *const CanonRequiresClause = nullptr;
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5582,6 +5582,17 @@
   /// expression. A diagnostic is emitted if it is not, and false is returned.
   bool CheckConstraintExpression(Expr *CE);
 
+private:
+  /// \brief Caches pairs of template-like decls whose associated constraints
+  /// were checked for subsumption and whether or not the first's constraints
+  /// did in fact subsume the second's.
+  llvm::DenseMap<std::pair<NamedDecl *, NamedDecl *>, bool> SubsumptionCache;
+
+public:
+  /// \brief Returns whether the given declaration's associated constraints are
+  /// more constrained than another declaration's according to the partial
+  /// ordering of constraints.
+  bool IsMoreConstrained(NamedDecl *D1, Expr *AC1, NamedDecl *D2, Expr *AC2);
 
   /// \brief Check whether the given constraint expression is satisfied given
   /// template arguments. Returns false and updates IsSatisfied with the
@@ -5645,6 +5656,9 @@
   void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation,
                                               StringRef Diagnostic);
 
+  void DiagnoseRedeclarationConstraintMismatch(const TemplateParameterList *Old,
+                                              const TemplateParameterList *New);
+
   // ParseObjCStringLiteral - Parse Objective-C string literals.
   ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
                                     ArrayRef<Expr *> Strings);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2422,11 +2422,13 @@
   "%select{and |because }0%1 does not satisfy %2">;
 def note_atomic_constraint_evaluated_to_false_elaborated : Note<
   "%select{and |because }0'%1' (%2 %3 %4) evaluated to false">;
-def err_could_not_normalize_ill_formed_constraint : Error<
-  "required expansion of concept specialization %0 failed, substituted "
-  "expression would be illegal">;
-def note_could_not_normalize_ill_formed_constraint_reason : Note<
-  "because: %0">;
+def note_could_not_normalize_argument_substitution_failed : Note<
+  "could not substitute template arguments into %0 %1. "
+  "Template arguments to a concept specialization expression must be valid "
+  "expressions">;
+def note_could_not_normalize_unmatched_argument_list_after_subst : Note<
+  "could not substitute template arguments into %0 %1 - the resulting template "
+  "argument list does not match the concept's parameter list">;
 
 def err_template_different_associated_constraints : Error<
   "associated constraints differ in template redeclaration">;
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -764,9 +764,10 @@
 
   void loadLazySpecializationsImpl() const;
 
-  template <class EntryType> typename SpecEntryTraits<EntryType>::DeclType*
+  template <class EntryType, typename... ProfileArguments>
+  typename SpecEntryTraits<EntryType>::DeclType*
   findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
-                         ArrayRef<TemplateArgument> Args, void *&InsertPos);
+                         void *&InsertPos, ProfileArguments... ProfileArgs);
 
   template <class Derived, class EntryType>
   void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
@@ -1936,7 +1937,7 @@
   /// including constraint-expressions derived from the requires-clause,
   /// trailing requires-clause (for functions and methods) and constrained
   /// template parameters.
-  Expr *getAssociatedConstraints();
+  Expr *getAssociatedConstraints() const;
 
   /// Get the template arguments as written.
   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
@@ -2020,7 +2021,22 @@
              ->getInjectedSpecializationType();
   }
 
-  // FIXME: Add Profile support!
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    Profile(ID, getTemplateArgs().asArray(), getAssociatedConstraints(),
+            getASTContext());
+  }
+
+  static void
+  Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
+          Expr *AssociatedConstraints, ASTContext &Context) {
+    ID.AddInteger(TemplateArgs.size());
+    for (const TemplateArgument &TemplateArg : TemplateArgs)
+      TemplateArg.Profile(ID, Context);
+    ID.AddBoolean(AssociatedConstraints != nullptr);
+    if (AssociatedConstraints) {
+        AssociatedConstraints->Profile(ID, Context, /*Canonical=*/true);
+    }
+  }
 
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
@@ -2145,7 +2161,8 @@
   /// \brief Return the partial specialization with the provided arguments if it
   /// exists, otherwise return the insertion point.
   ClassTemplatePartialSpecializationDecl *
-  findPartialSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos);
+  findPartialSpecialization(ArrayRef<TemplateArgument> Args,
+                            Expr *AssociatedConstraints, void *&InsertPos);
 
   /// \brief Insert the specified partial specialization knowing that it is not
   /// already in. InsertPos must be obtained from findPartialSpecialization.
@@ -2780,7 +2797,7 @@
   /// including constraint-expressions derived from the requires-clause,
   /// trailing requires-clause (for functions and methods) and constrained
   /// template parameters.
-  Expr *getAssociatedConstraints();
+  Expr *getAssociatedConstraints() const;
 
   /// \brief Retrieve the member variable template partial specialization from
   /// which this particular variable template partial specialization was
@@ -2846,6 +2863,23 @@
     return First->InstantiatedFromMember.setInt(true);
   }
 
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    Profile(ID, getTemplateArgs().asArray(), getAssociatedConstraints(),
+            getASTContext());
+  }
+
+  static void
+  Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
+          Expr *AssociatedConstraints, ASTContext &Context) {
+    ID.AddInteger(TemplateArgs.size());
+    for (const TemplateArgument &TemplateArg : TemplateArgs)
+      TemplateArg.Profile(ID, Context);
+    ID.AddBoolean(AssociatedConstraints != nullptr);
+    if (AssociatedConstraints) {
+        AssociatedConstraints->Profile(ID, Context, /*Canonical=*/true);
+    }
+  }
+
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
   static bool classofKind(Kind K) {
@@ -2964,7 +2998,8 @@
   /// \brief Return the partial specialization with the provided arguments if it
   /// exists, otherwise return the insertion point.
   VarTemplatePartialSpecializationDecl *
-  findPartialSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos);
+  findPartialSpecialization(ArrayRef<TemplateArgument> Args,
+                            Expr *AssociatedConstraints, void *&InsertPos);
 
   /// \brief Insert the specified partial specialization knowing that it is not
   /// already in. InsertPos must be obtained from findPartialSpecialization.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to