saar.raz updated this revision to Diff 232457.
saar.raz marked 7 inline comments as done.
saar.raz added a comment.

Address all CR comments by rsmith (including rewrite of normalization).
Decided to not support things like:

template<typename T, typename U>
concept C = ...;

template<typename... T> requires C<T...>
struct S { };

For now, as wording is not clear what the normal form of these should be.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D41910

Files:
  clang/include/clang/AST/DeclTemplate.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/DeclTemplate.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/Serialization/ASTReaderDecl.cpp
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
  clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.normal/p1.cpp
  
clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
  
clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/function-templates.cpp
  
clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp

Index: clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
===================================================================
--- /dev/null
+++ clang/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: clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/function-templates.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/function-templates.cpp
@@ -0,0 +1,82 @@
+// 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);
+
+template<class T, class U>
+concept BiggerThan = sizeof(T) > sizeof(U);
+
+template<class T>
+concept BiggerThanInt = BiggerThan<T, int>;
+
+template<class T, class U> requires BiggerThan<T, U>
+void f() { }
+// expected-note@-1 {{candidate function [with T = long long, U = int]}}
+
+template<class T, class U> requires BiggerThanInt<T>
+void f() { }
+// expected-note@-1 {{candidate function [with T = long long, U = int]}}
+
+static_assert(sizeof(f<long long, int>()));
+// expected-error@-1 {{call to 'f' is ambiguous}}
+
+template<typename T>
+concept C3 = true;
+
+template<typename T>
+concept C4 = true && C3<T>;
+
+template<typename T> requires C3<void>
+int g() { }
+
+template<typename T> requires C4<void>
+int g() { }
+
+static_assert(sizeof(g<int>()));
\ No newline at end of file
Index: clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
@@ -0,0 +1,50 @@
+// 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{{requires clause differs 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);
Index: clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.normal/p1.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/concepts-ts/temp/temp.constr/temp.constr.normal/p1.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T> concept True = true;
+template<typename T> concept Foo = True<T*>;
+template<typename T> concept Bar = Foo<T&>;
+template<typename T> requires Bar<T> struct S { };
+template<typename T> requires Bar<T> && true struct S<T> { };
+
+template<typename T> concept True2 = sizeof(T) >= 0;
+// expected-error@-1 2{{'type name' declared as a pointer to a reference of type 'type-parameter-0-0 &'}}
+template<typename T> concept Foo2 = True2<T*>;
+template<typename T> concept Bar2 = Foo2<T&>;
+template<typename T> requires Bar2<T> struct S2 { };
+// expected-error@-1 {{template is declared here}}
+template<typename T> requires Bar2<T> && true struct S2<T> { };
+// expected-error@-1{{class template partial specialization is not more specialized than the primary template}}
\ No newline at end of file
Index: clang/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
===================================================================
--- clang/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
+++ clang/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
@@ -75,11 +75,8 @@
 template<typename T, typename U, typename... Ts>
 concept OneOf = (Same<T, Ts> || ...);
 
-template<typename... X>
-constexpr bool S = OneOf<X..., int, int>;
-
-static_assert(S<int, long, int>);
-static_assert(!S<long, int, char, char>);
+static_assert(OneOf<int, long, int>);
+static_assert(!OneOf<long, int, char, char>);
 
 namespace piecewise_substitution {
   template <typename T>
@@ -182,3 +179,9 @@
 static_assert(AccessPrivate<T4>);
 // expected-error@-1{{static_assert failed}}
 // expected-note@-2{{because 'T4' does not satisfy 'AccessPrivate'}}
+
+template<typename T, typename U>
+concept C8 = sizeof(T) > sizeof(U);
+
+template<typename... T>
+constexpr bool B8 = C8<T...>; // expected-error{{pack expansion into non-pack concept parameters not currently supported}}
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1504,11 +1504,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());
@@ -1564,11 +1564,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: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2250,12 +2250,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 = 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(
@@ -2353,12 +2355,12 @@
 ///        using Template(Partial)SpecializationDecl as input type.
 void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
     VarTemplatePartialSpecializationDecl *D) {
-  RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
-
   TemplateParameterList *Params = Record.readTemplateParameterList();
   D->TemplateParams = 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: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3544,7 +3544,8 @@
   // in the member template's set of class template partial specializations.
   void *InsertPos = nullptr;
   ClassTemplateSpecializationDecl *PrevDecl
-    = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
+    = ClassTemplate->findPartialSpecialization(Converted, InstParams,
+                                               InsertPos);
 
   // Build the canonical type that describes the converted template
   // arguments of the class template partial specialization.
@@ -3668,7 +3669,7 @@
   // in the member template's set of variable template partial specializations.
   void *InsertPos = nullptr;
   VarTemplateSpecializationDecl *PrevDecl =
-      VarTemplate->findPartialSpecialization(Converted, InsertPos);
+      VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos);
 
   // Build the canonical type that describes the converted template
   // arguments of the variable template partial specialization.
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2892,6 +2892,17 @@
   return Instantiator.TransformStmt(S);
 }
 
+bool Sema::SubstTemplateArguments(
+    ArrayRef<TemplateArgumentLoc> Args,
+    const MultiLevelTemplateArgumentList &TemplateArgs,
+    TemplateArgumentListInfo &Out) {
+  TemplateInstantiator Instantiator(*this, TemplateArgs,
+                                    SourceLocation(),
+                                    DeclarationName());
+  return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(),
+                                                 Out);
+}
+
 ExprResult
 Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
   if (!E)
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2501,6 +2501,23 @@
   llvm_unreachable("Invalid TemplateArgument Kind!");
 }
 
+TemplateArgumentLoc
+Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm) {
+  if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm))
+    return getTrivialTemplateArgumentLoc(
+        TemplateArgument(QualType(TTP->getTypeForDecl(), 0)), QualType(),
+        TTP->getLocation());
+  else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm))
+    return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)),
+                                         QualType(), TTP->getLocation());
+  auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm);
+  Expr *E = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue,
+                             NTTP->getLocation());
+  return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(),
+                                       NTTP->getLocation());
+}
+
+
 /// Convert the given deduced template argument and add it to the set of
 /// fully-converted template arguments.
 static bool
@@ -2709,6 +2726,23 @@
   static constexpr bool value = true;
 };
 
+template<typename TemplateDeclT>
+static Sema::TemplateDeductionResult
+CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
+                                ArrayRef<TemplateArgument> DeducedArgs,
+                                TemplateDeductionInfo& Info) {
+  llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
+  Template->getAssociatedConstraints(AssociatedConstraints);
+  if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
+                                    DeducedArgs, Info.getLocation(),
+                                    Info.AssociatedConstraintsSatisfaction)
+      || !Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+    Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
+    return Sema::TDK_ConstraintsNotSatisfied;
+  }
+  return Sema::TDK_Success;
+}
+
 /// Complete template argument deduction for a partial specialization.
 template <typename T>
 static typename std::enable_if<IsPartialSpecialization<T>::value,
@@ -2786,6 +2820,9 @@
   if (Trap.hasErrorOccurred())
     return Sema::TDK_SubstitutionFailure;
 
+  if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info))
+    return Result;
+
   return Sema::TDK_Success;
 }
 
@@ -2828,23 +2865,10 @@
   if (Trap.hasErrorOccurred())
     return Sema::TDK_SubstitutionFailure;
 
-  return Sema::TDK_Success;
-}
+  if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder,
+                                                    Info))
+    return Result;
 
-template<typename TemplateDeclT>
-static Sema::TemplateDeductionResult
-CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
-                                ArrayRef<TemplateArgument> DeducedArgs,
-                                TemplateDeductionInfo& Info) {
-  llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
-  Template->getAssociatedConstraints(AssociatedConstraints);
-  if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
-                                    DeducedArgs, Info.getLocation(),
-                                    Info.AssociatedConstraintsSatisfaction)
-      || !Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
-    Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
-    return Sema::TDK_ConstraintsNotSatisfied;
-  }
   return Sema::TDK_Success;
 }
 
@@ -2887,10 +2911,6 @@
   if (Trap.hasErrorOccurred())
     return Sema::TDK_SubstitutionFailure;
 
-  if (TemplateDeductionResult Result
-        = CheckDeducedArgumentConstraints(*this, Partial, DeducedArgs, Info))
-    return Result;
-
   return ::FinishTemplateArgumentDeduction(
       *this, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info);
 }
@@ -2932,10 +2952,6 @@
   if (Trap.hasErrorOccurred())
     return Sema::TDK_SubstitutionFailure;
 
-  if (TemplateDeductionResult Result
-        = CheckDeducedArgumentConstraints(*this, Partial, DeducedArgs, Info))
-    return Result;
-
   return ::FinishTemplateArgumentDeduction(
       *this, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info);
 }
@@ -3045,12 +3061,6 @@
     = TemplateArgumentList::CreateCopy(Context, Builder);
   Info.setExplicitArgs(ExplicitArgumentList);
 
-  if (TemplateDeductionResult Result
-        = CheckDeducedArgumentConstraints(*this, FunctionTemplate,
-                                          ExplicitArgumentList->asArray(),
-                                          Info))
-    return Result;
-
   // Template argument deduction and the final substitution should be
   // done in the context of the templated declaration.  Explicit
   // argument substitution, on the other hand, needs to happen in the
@@ -3364,7 +3374,7 @@
     return Result;
 
   if (TemplateDeductionResult Result
-        = CheckDeducedArgumentConstraints(*this, FunctionTemplate, DeducedArgs,
+        = CheckDeducedArgumentConstraints(*this, FunctionTemplate, Builder,
                                           Info))
     return Result;
 
@@ -4919,6 +4929,18 @@
                                  TemplatePartialOrderingContext TPOC,
                                  unsigned NumCallArguments1,
                                  unsigned NumCallArguments2) {
+
+  auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * {
+    llvm::SmallVector<const Expr *, 3> AC1, AC2;
+    FT1->getAssociatedConstraints(AC1);
+    FT2->getAssociatedConstraints(AC2);
+    bool MoreConstrained1 = IsMoreConstrained(FT1, AC1, FT2, AC2);
+    bool MoreConstrained2 = IsMoreConstrained(FT2, AC2, FT1, AC1);
+    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,
@@ -4928,7 +4950,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,
@@ -4938,7 +4960,7 @@
   if (Variadic1 != Variadic2)
     return Variadic1? FT2 : FT1;
 
-  return nullptr;
+  return JudgeByConstraints();
 }
 
 /// Determine if the two templates are equivalent.
@@ -5063,7 +5085,6 @@
 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
@@ -5134,8 +5155,16 @@
   bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
   bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
 
-  if (Better1 == Better2)
-    return nullptr;
+  if (Better1 == Better2) {
+    llvm::SmallVector<const Expr *, 3> AC1, AC2;
+    PS1->getAssociatedConstraints(AC1);
+    PS2->getAssociatedConstraints(AC2);
+    bool MoreConstrained1 = IsMoreConstrained(PS1, AC1, PS2, AC2);
+    bool MoreConstrained2 = IsMoreConstrained(PS2, AC2, PS1, AC1);
+    if (MoreConstrained1 == MoreConstrained2)
+      return nullptr;
+    return MoreConstrained1 ? PS1 : PS2;
+  }
 
   return Better1 ? PS1 : PS2;
 }
@@ -5145,11 +5174,23 @@
   ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
   QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
   QualType PartialT = Spec->getInjectedSpecializationType();
+  auto JudgeByConstraints = [&] {
+    llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
+    Primary->getAssociatedConstraints(PrimaryAC);
+    Spec->getAssociatedConstraints(SpecAC);
+    bool MoreConstrainedPrimary = IsMoreConstrained(Primary, PrimaryAC, Spec,
+                                                    SpecAC);
+    bool MoreConstrainedSpec = IsMoreConstrained(Spec, SpecAC, Primary,
+                                                 PrimaryAC);
+    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;
 }
@@ -5174,8 +5215,17 @@
   bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
   bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
 
-  if (Better1 == Better2)
-    return nullptr;
+  if (Better1 == Better2) {
+    llvm::SmallVector<const Expr *, 3> AC1, AC2;
+    PS1->getAssociatedConstraints(AC1);
+    PS2->getAssociatedConstraints(AC2);
+    bool MoreConstrained1 = IsMoreConstrained(PS1, AC1, PS2, AC2);
+    bool MoreConstrained2 = IsMoreConstrained(PS2, AC2, PS1, AC1);
+    if (MoreConstrained1 == MoreConstrained2) {
+      return nullptr;
+    }
+    return MoreConstrained1 ? PS1 : PS2;
+  }
 
   return Better1 ? PS1 : PS2;
 }
@@ -5195,11 +5245,25 @@
       CanonTemplate, PrimaryArgs);
   QualType PartialT = Context.getTemplateSpecializationType(
       CanonTemplate, Spec->getTemplateArgs().asArray());
+
+  auto JudgeByConstraints = [&] {
+    llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
+    Primary->getAssociatedConstraints(PrimaryAC);
+    Spec->getAssociatedConstraints(SpecAC);
+    bool MoreConstrainedPrimary = IsMoreConstrained(Primary, PrimaryAC, Spec,
+                                                    SpecAC);
+    bool MoreConstrainedSpec = IsMoreConstrained(Spec, SpecAC, Primary,
+                                                 PrimaryAC);
+    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: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -1096,11 +1096,11 @@
   // Check that we have valid decl-specifiers specified.
   auto CheckValidDeclSpecifiers = [this, &D] {
     // C++ [temp.param]
-    // p1
+    // p1 
     //   template-parameter:
     //     ...
     //     parameter-declaration
-    // p2
+    // p2 
     //   ... A storage class shall not be specified in a template-parameter
     //   declaration.
     // [dcl.typedef]p1:
@@ -3876,7 +3876,9 @@
     }
 
     if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
-                                Converted)) {
+                                Converted) &&
+        (!Context.getLangOpts().ConceptsTS ||
+         !TemplateParams->hasAssociatedConstraints())) {
       // C++ [temp.class.spec]p9b3:
       //
       //   -- The argument list of the specialization shall not be identical
@@ -3895,8 +3897,8 @@
   VarTemplateSpecializationDecl *PrevDecl = nullptr;
 
   if (IsPartialSpecialization)
-    // FIXME: Template parameter list matters too
-    PrevDecl = VarTemplate->findPartialSpecialization(Converted, InsertPos);
+    PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams,
+                                                      InsertPos);
   else
     PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
 
@@ -4216,12 +4218,19 @@
   assert(NamedConcept && "A concept template id without a template?");
 
   llvm::SmallVector<TemplateArgument, 4> Converted;
+  bool IsMatchInstantiationDependent;
   if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc,
                            const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
                                 /*PartialTemplateArgs=*/false, Converted,
-                                /*UpdateArgsWithConversion=*/false))
+                                /*UpdateArgsWithConversion=*/false,
+                                &IsMatchInstantiationDependent))
     return ExprError();
 
+  if (IsMatchInstantiationDependent) {
+    Diag(TemplateArgs->getLAngleLoc(), diag::err_pack_expansion_concept_args);
+    return ExprError();
+  }
+
   ConstraintSatisfaction Satisfaction;
   bool IsInstantiationDependent = false;
   for (TemplateArgument &Arg : Converted) {
@@ -7112,6 +7121,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) {
@@ -7820,8 +7830,9 @@
   ClassTemplateSpecializationDecl *PrevDecl = nullptr;
 
   if (isPartialSpecialization)
-    // FIXME: Template parameter list matters, too
-    PrevDecl = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
+    PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
+                                                        TemplateParams,
+                                                        InsertPos);
   else
     PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
 
@@ -7845,7 +7856,9 @@
                                                       Converted);
 
     if (Context.hasSameType(CanonType,
-                        ClassTemplate->getInjectedClassNameSpecialization())) {
+                        ClassTemplate->getInjectedClassNameSpecialization()) &&
+        (!Context.getLangOpts().ConceptsTS ||
+         !TemplateParams->hasAssociatedConstraints())) {
       // C++ [temp.class.spec]p9b3:
       //
       //   -- The argument list of the specialization shall not be identical
@@ -10505,3 +10518,9 @@
                           MissingImportKind::PartialSpecialization,
                           /*Recover*/true);
 }
+
+    // p1
+    //   template-parameter:
+    //     ...
+    //     parameter-declaration
+    // p2
\ No newline at end of file
Index: clang/lib/Sema/SemaConcept.cpp
===================================================================
--- clang/lib/Sema/SemaConcept.cpp
+++ clang/lib/Sema/SemaConcept.cpp
@@ -17,6 +17,7 @@
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/Sema/Template.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PointerUnion.h"
 using namespace clang;
@@ -405,4 +406,375 @@
     diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
     First = false;
   }
+}
+
+namespace {
+struct AtomicConstraint {
+  const Expr *ConstraintExpr;
+  llvm::Optional<llvm::SmallVector<TemplateArgumentLoc, 3>> ParameterMapping;
+
+  AtomicConstraint(Sema &S, const Expr *ConstraintExpr) :
+      ConstraintExpr{ConstraintExpr} { };
+
+  bool hasMatchingParameterMapping(ASTContext &C,
+                                   const AtomicConstraint &Other) const {
+    if (!ParameterMapping != !Other.ParameterMapping)
+      return false;
+    if (!ParameterMapping)
+      return true;
+    if (ParameterMapping->size() != Other.ParameterMapping->size())
+      return false;
+
+    for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I)
+      if (!C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
+               .structurallyEquals(C.getCanonicalTemplateArgument(
+                  (*Other.ParameterMapping)[I].getArgument())))
+        return false;
+    return true;
+  }
+
+  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 into the
+    // constraint expressions, 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
+    return hasMatchingParameterMapping(C, Other);
+  }
+};
+
+/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
+/// either an atomic constraint, a conjunction of normalized constraints or a
+/// disjunction of normalized constraints.
+struct NormalizedConstraint {
+  enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
+
+  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 (C) std::pair<NormalizedConstraint, NormalizedConstraint>{LHS,
+                                                                          RHS},
+            Kind}} { };
+
+  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>
+  fromConstraintExprs(Sema &S, ArrayRef<const Expr *> E) {
+    assert(E.size() != 0);
+    auto First = fromConstraintExpr(S, E[0]);
+    if (E.size() == 1)
+      return First;
+    auto Second = fromConstraintExpr(S, E[1]);
+    if (!Second)
+      return llvm::Optional<NormalizedConstraint>{};
+    llvm::Optional<NormalizedConstraint> Conjunction;
+    Conjunction.emplace(S.Context, std::move(*First), std::move(*Second),
+                        CCK_Conjunction);
+    for (unsigned I = 2; I < E.size(); ++I) {
+      auto Next = fromConstraintExpr(S, E[I]);
+      if (!Next)
+        return llvm::Optional<NormalizedConstraint>{};
+      NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction),
+                                          std::move(*Next), CCK_Conjunction);
+      *Conjunction = std::move(NewConjunction);
+    }
+    return Conjunction;
+  }
+
+private:
+  static llvm::Optional<NormalizedConstraint> fromConstraintExpr(Sema &S,
+                                                                 const Expr *E);
+};
+
+struct OccurringTemplateParameterFinder :
+    RecursiveASTVisitor<OccurringTemplateParameterFinder> {
+  llvm::SmallBitVector &OccurringIndices;
+
+  OccurringTemplateParameterFinder(llvm::SmallBitVector &OccurringIndices)
+      : OccurringIndices(OccurringIndices) { }
+
+  bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
+    assert(T->getDepth() == 0 && "This assumes that we allow concepts at "
+                                 "namespace scope only");
+    noteParameter(T->getIndex());
+    return true;
+  }
+
+  bool TraverseTemplateName(TemplateName Template) {
+    if (auto *TTP =
+            dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl())) {
+      assert(TTP->getDepth() == 0 && "This assumes that we allow concepts at "
+                                     "namespace scope only");
+      noteParameter(TTP->getIndex());
+    }
+    RecursiveASTVisitor<OccurringTemplateParameterFinder>::
+        TraverseTemplateName(Template);
+    return true;
+  }
+
+  bool VisitDeclRefExpr(DeclRefExpr *E) {
+    if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
+      assert(NTTP->getDepth() == 0 && "This assumes that we allow concepts at "
+                                      "namespace scope only");
+      noteParameter(NTTP->getIndex());
+    }
+    return true;
+  }
+
+protected:
+  void noteParameter(unsigned Index) {
+    if (OccurringIndices.size() >= Index)
+      OccurringIndices.resize(Index + 1, false);
+    OccurringIndices.set(Index);
+  }
+};
+
+static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+    TemplateParameterList *TemplateParams,
+    ArrayRef<TemplateArgument> TemplateArgs) {
+  if (!N.isAtomic()) {
+    if (substituteParameterMappings(S, N.getLHS(), TemplateParams,
+                                    TemplateArgs))
+      return true;
+    return substituteParameterMappings(S, N.getRHS(), TemplateParams,
+                                       TemplateArgs);
+  }
+
+  AtomicConstraint &Atomic = *N.getAtomicConstraint();
+  TemplateArgumentListInfo SubstArgs;
+  MultiLevelTemplateArgumentList MLTAL;
+  MLTAL.addOuterTemplateArguments(TemplateArgs);
+  if (!Atomic.ParameterMapping) {
+    llvm::SmallBitVector OccurringIndices;
+    OccurringTemplateParameterFinder(OccurringIndices)
+        .TraverseStmt(const_cast<Expr *>(Atomic.ConstraintExpr));
+    Atomic.ParameterMapping.emplace();
+    Atomic.ParameterMapping->reserve(OccurringIndices.size());
+    for (unsigned I = 0, C = TemplateParams->size(); I != C; ++I)
+      if (OccurringIndices[I])
+        Atomic.ParameterMapping->push_back(
+            S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I]));
+  }
+
+  if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
+    return true;
+  std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
+            N.getAtomicConstraint()->ParameterMapping->begin());
+  return false;
+}
+
+llvm::Optional<NormalizedConstraint>
+NormalizedConstraint::fromConstraintExpr(Sema &S, const Expr *E) {
+  assert(E != nullptr);
+
+  // C++ [temp.constr.normal]p1.1
+  // [...]
+  // - The normal form of an expression (E) is the normal form of E.
+  // [...]
+  E = E->IgnoreParenImpCasts();
+  if (auto *BO = dyn_cast<const BinaryOperator>(E)) {
+    if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
+      auto LHS = fromConstraintExpr(S, BO->getLHS());
+      if (!LHS)
+        return None;
+      auto RHS = fromConstraintExpr(S, BO->getRHS());
+      if (!RHS)
+        return None;
+
+      return NormalizedConstraint(
+          S.Context, *LHS, *RHS,
+          BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction);
+    }
+  } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
+    // C++ [temp.constr.normal]p1.1
+    // [...]
+    // The normal form of an id-expression of the form C<A1, A2, ..., AN>,
+    // where C names a concept, is the normal form of the
+    // constraint-expression of C, after substituting A1, A2, ..., AN for C’s
+    // respective template parameters in the parameter mappings in each atomic
+    // constraint. If any such substitution results in an invalid type or
+    // expression, the program is ill-formed; no diagnostic is required.
+    // [...]
+    Optional<NormalizedConstraint> SubNF =
+      fromConstraintExpr(S, CSE->getNamedConcept()->getConstraintExpr());
+    if (!SubNF)
+      return None;
+
+    if (substituteParameterMappings(S, *SubNF,
+            CSE->getNamedConcept()->getTemplateParameters(),
+            CSE->getTemplateArguments()))
+      return None;
+
+    return SubNF;
+  }
+  return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)};
+}
+
+} // 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, ArrayRef<const Expr *> P,
+                     ArrayRef<const 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::fromConstraintExprs(S, P);
+  if (!PNormalized)
+    // Program is ill formed at this point.
+    return false;
+  const NormalForm PDNF = makeDNF(*PNormalized);
+
+  auto QNormalized = NormalizedConstraint::fromConstraintExprs(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, ArrayRef<const Expr *> AC1,
+                             NamedDecl *D2, ArrayRef<const Expr *> AC2) {
+  if (AC1.empty())
+    return AC2.empty();
+  if (AC2.empty())
+    // 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: clang/lib/AST/DeclTemplate.cpp
===================================================================
--- clang/lib/AST/DeclTemplate.cpp
+++ clang/lib/AST/DeclTemplate.cpp
@@ -231,15 +231,16 @@
   }
 }
 
-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, std::forward<ProfileArguments>(ProfileArgs)...,
+                     getASTContext());
   EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos);
   return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr;
 }
@@ -254,8 +255,8 @@
 #ifndef NDEBUG
     void *CorrectInsertPos;
     assert(!findSpecializationImpl(Specializations,
-                                   SETraits::getTemplateArgs(Entry),
-                                   CorrectInsertPos) &&
+                                   CorrectInsertPos,
+                                   SETraits::getTemplateArgs(Entry)) &&
            InsertPos == CorrectInsertPos &&
            "given incorrect InsertPos for specialization");
 #endif
@@ -312,7 +313,7 @@
 FunctionDecl *
 FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
                                          void *&InsertPos) {
-  return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+  return findSpecializationImpl(getSpecializations(), InsertPos, Args);
 }
 
 void FunctionTemplateDecl::addSpecialization(
@@ -418,7 +419,7 @@
 ClassTemplateSpecializationDecl *
 ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
                                       void *&InsertPos) {
-  return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+  return findSpecializationImpl(getSpecializations(), InsertPos, Args);
 }
 
 void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
@@ -428,8 +429,49 @@
 
 ClassTemplatePartialSpecializationDecl *
 ClassTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
-                                             void *&InsertPos) {
-  return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
+    TemplateParameterList *TPL, void *&InsertPos) {
+  return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args,
+                                TPL);
+}
+
+static void ProfileTemplateParameterList(ASTContext &C,
+    llvm::FoldingSetNodeID &ID, const TemplateParameterList *TPL) {
+  const Expr *RC = TPL->getRequiresClause();
+  ID.AddBoolean(RC != nullptr);
+  if (RC)
+    RC->Profile(ID, C, /*Canonical=*/true);
+  ID.AddInteger(TPL->size());
+  for (NamedDecl *D : *TPL) {
+    if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+      ID.AddInteger(NTTP->getDepth());
+      ID.AddInteger(NTTP->getIndex());
+      ID.AddBoolean(NTTP->isParameterPack());
+      NTTP->getType().getCanonicalType().Profile(ID);
+      continue;
+    }
+    if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) {
+      ID.AddInteger(TTP->getDepth());
+      ID.AddInteger(TTP->getIndex());
+      ID.AddBoolean(TTP->isParameterPack());
+      // TODO: Concepts: profile type-constraints.
+      continue;
+    }
+    const auto *TTP = cast<TemplateTemplateParmDecl>(D);
+    ID.AddInteger(TTP->getDepth());
+    ID.AddInteger(TTP->getIndex());
+    ID.AddBoolean(TTP->isParameterPack());
+    ProfileTemplateParameterList(C, ID, TTP->getTemplateParameters());
+  }
+}
+
+void
+ClassTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID,
+    ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL,
+    ASTContext &Context) {
+  ID.AddInteger(TemplateArgs.size());
+  for (const TemplateArgument &TemplateArg : TemplateArgs)
+    TemplateArg.Profile(ID, Context);
+  ProfileTemplateParameterList(Context, ID, TPL);
 }
 
 void ClassTemplateDecl::AddPartialSpecialization(
@@ -1031,7 +1073,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 +1083,19 @@
 
 VarTemplatePartialSpecializationDecl *
 VarTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
-                                           void *&InsertPos) {
-  return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
+     TemplateParameterList *TPL, void *&InsertPos) {
+  return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args,
+                                TPL);
+}
+
+void
+VarTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID,
+    ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL,
+    ASTContext &Context) {
+  ID.AddInteger(TemplateArgs.size());
+  for (const TemplateArgument &TemplateArg : TemplateArgs)
+    TemplateArg.Profile(ID, Context);
+  ProfileTemplateParameterList(Context, ID, TPL);
 }
 
 void VarTemplateDecl::AddPartialSpecialization(
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -5115,16 +5115,25 @@
   if (Error Err = ImportTemplateArguments(
       D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs))
     return std::move(Err);
-
-  // Try to find an existing specialization with these template arguments.
+  // Try to find an existing specialization with these template arguments and
+  // template parameter list.
   void *InsertPos = nullptr;
   ClassTemplateSpecializationDecl *PrevDecl = nullptr;
   ClassTemplatePartialSpecializationDecl *PartialSpec =
             dyn_cast<ClassTemplatePartialSpecializationDecl>(D);
-  if (PartialSpec)
-    PrevDecl =
-        ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos);
-  else
+
+  // Import template parameters.
+  TemplateParameterList *ToTPList = nullptr;
+
+  if (PartialSpec) {
+    auto ToTPListOrErr = import(PartialSpec->getTemplateParameters());
+    if (!ToTPListOrErr)
+      return ToTPListOrErr.takeError();
+    ToTPList = *ToTPListOrErr;
+    PrevDecl = ClassTemplate->findPartialSpecialization(TemplateArgs,
+                                                        *ToTPListOrErr,
+                                                        InsertPos);
+  } else
     PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos);
 
   if (PrevDecl) {
@@ -5183,13 +5192,9 @@
       return std::move(Err);
     CanonInjType = CanonInjType.getCanonicalType();
 
-    auto ToTPListOrErr = import(PartialSpec->getTemplateParameters());
-    if (!ToTPListOrErr)
-      return ToTPListOrErr.takeError();
-
     if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
             D2, D, Importer.getToContext(), D->getTagKind(), DC,
-            *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate,
+            *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate,
             llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
             ToTAInfo, CanonInjType,
             cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
@@ -5197,10 +5202,11 @@
 
     // Update InsertPos, because preceding import calls may have invalidated
     // it by adding new specializations.
-    if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos))
+    auto *PartSpec2 = cast<ClassTemplatePartialSpecializationDecl>(D2);
+    if (!ClassTemplate->findPartialSpecialization(TemplateArgs, ToTPList,
+                                                  InsertPos))
       // Add this partial specialization to the class template.
-      ClassTemplate->AddPartialSpecialization(
-          cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos);
+      ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos);
 
   } else { // Not a partial specialization.
     if (GetImportedOrCreateDecl(
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5941,6 +5941,19 @@
   /// 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, ArrayRef<const Expr *> AC1,
+                         NamedDecl *D2, ArrayRef<const Expr *> AC2);
+
   /// \brief Check whether the given list of constraint expressions are
   /// satisfied (as if in a 'conjunction') given template arguments.
   /// \param ConstraintExprs a list of constraint expressions, treated as if
@@ -6019,6 +6032,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);
@@ -6630,6 +6646,11 @@
                                                     QualType NTTPType,
                                                     SourceLocation Loc);
 
+  /// Get a template argument mapping the given template parameter to itself,
+  /// e.g. for X in \c template<int X>, this would return an expression template
+  /// argument referencing X.
+  TemplateArgumentLoc getIdentityTemplateArgumentLoc(Decl *Param);
+
   void translateTemplateArguments(const ASTTemplateArgsPtr &In,
                                   TemplateArgumentListInfo &Out);
 
@@ -8227,6 +8248,12 @@
   SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
                       const MultiLevelTemplateArgumentList &TemplateArgs);
 
+  bool
+  SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
+                         const MultiLevelTemplateArgumentList &TemplateArgs,
+                         TemplateArgumentListInfo &Outputs);
+
+
   Decl *SubstDecl(Decl *D, DeclContext *Owner,
                   const MultiLevelTemplateArgumentList &TemplateArgs);
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2503,11 +2503,11 @@
   "%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<
+  "while substituting into %0 %1; make sure no invalid expressions/types form "
+  "in concept arguments">;
+def err_pack_expansion_concept_args : Error<"pack expansion into non-pack "
+  "concept parameters not currently supported">;
 
 def err_template_different_requires_clause : Error<
   "requires clause differs in template redeclaration">;
Index: clang/include/clang/AST/DeclTemplate.h
===================================================================
--- clang/include/clang/AST/DeclTemplate.h
+++ clang/include/clang/AST/DeclTemplate.h
@@ -793,9 +793,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,
@@ -2056,7 +2057,14 @@
              ->getInjectedSpecializationType();
   }
 
-  // FIXME: Add Profile support!
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
+            getASTContext());
+  }
+
+  static void
+  Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
+          TemplateParameterList *TPL, ASTContext &Context);
 
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
@@ -2180,7 +2188,8 @@
   /// 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,
+                            TemplateParameterList *TPL, void *&InsertPos);
 
   /// Insert the specified partial specialization knowing that it is not
   /// already in. InsertPos must be obtained from findPartialSpecialization.
@@ -2884,6 +2893,15 @@
     return First->InstantiatedFromMember.setInt(true);
   }
 
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
+            getASTContext());
+  }
+
+  static void
+  Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
+          TemplateParameterList *TPL, ASTContext &Context);
+
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
   static bool classofKind(Kind K) {
@@ -3002,7 +3020,8 @@
   /// 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,
+                            TemplateParameterList *TPL, void *&InsertPos);
 
   /// 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
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to