saar.raz updated this revision to Diff 147190.
saar.raz added a comment.

Adjusted to changes in dependent patches.


Repository:
  rC Clang

https://reviews.llvm.org/D44352

Files:
  include/clang/AST/DeclTemplate.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/TemplateBase.h
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  lib/AST/ASTContext.cpp
  lib/AST/ASTDumper.cpp
  lib/AST/ASTImporter.cpp
  lib/AST/DeclTemplate.cpp
  lib/AST/ODRHash.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Sema/SemaCXXScopeSpec.cpp
  lib/Sema/SemaConcept.cpp
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateDeduction.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
  test/CXX/concepts-ts/temp/temp.param/p10.cpp
  test/Parser/cxx-constrained-template-param-with-partial-id.cpp
  test/Parser/cxx-constrained-template-param.cpp
  tools/libclang/CIndex.cpp

Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -750,6 +750,10 @@
 }
 
 bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+  if (Expr *CE = D->getConstraintExpression())
+    if (Visit(MakeCXCursor(CE, StmtParent, TU, RegionOfInterest)))
+      return true;
+
   // Visit the default argument.
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
     if (TypeSourceInfo *DefArg = D->getDefaultArgumentInfo())
@@ -898,6 +902,10 @@
 bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
   if (VisitDeclaratorDecl(D))
     return true;
+
+  if (Expr *CE = D->getConstraintExpression())
+    if (Visit(MakeCXCursor(CE, StmtParent, TU, RegionOfInterest)))
+      return true;
   
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
     if (Expr *DefArg = D->getDefaultArgument())
@@ -929,7 +937,11 @@
 bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
   if (VisitTemplateParameters(D->getTemplateParameters()))
     return true;
-  
+
+  if (Expr *CE = D->getConstraintExpression())
+    if (Visit(MakeCXCursor(CE, StmtParent, TU, RegionOfInterest)))
+      return true;
+
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited() &&
       VisitTemplateArgumentLoc(D->getDefaultArgument()))
     return true;
Index: test/Parser/cxx-constrained-template-param.cpp
===================================================================
--- /dev/null
+++ test/Parser/cxx-constrained-template-param.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify
+// expected-no-diagnostics
+
+namespace type
+{
+  template<typename T>
+  concept C1 = true;
+
+  template<C1 T, C1 U = int>
+  using A = T[10];
+
+  using a = A<int>;
+
+  namespace ns {
+    template<typename T, int a = 0>
+    concept C2 = true;
+  }
+
+  template<ns::C2 T1, ::type::ns::C2 T2> requires sizeof(T1) <= sizeof(T2)
+  struct B { };
+
+  using b = B<int, int>;
+
+  template<ns::C2... T1>
+  struct C { };
+
+  using c1 = C<char, char, char>;
+  using c2 = C<char, char, char, char>;
+}
+
+namespace non_type
+{
+  template<int v>
+  concept C1 = true;
+
+  template<C1 v, C1 u = 0>
+  int A = v;
+
+  int& a = A<1>;
+
+  namespace ns {
+    template<bool x, typename T = int>
+    concept C2 = true;
+  }
+
+  template<ns::C2 v1, ::non_type::ns::C2 v2> requires sizeof(v1) <= sizeof(v2)
+  struct B { };
+
+  using b = B<true, false>;
+
+  template<ns::C2... T1>
+  struct C { };
+
+  using c1 = C<false, true, false>;
+  using c2 = C<false, true, false, false>;
+}
+
+namespace temp
+{
+  template<typename>
+  struct test1 { };
+
+  template<typename>
+  struct test2 { };
+
+  template<template<typename> typename T>
+  concept C1 = true;
+
+  template<C1 TT, C1 UU = test1>
+  using A = TT<int>;
+
+  using a = A<test1>;
+
+  namespace ns {
+    template<template<typename> typename... TT>
+    concept C2 = true;
+  }
+
+  template<ns::C2 TT1, ::temp::ns::C2 TT2>
+    requires sizeof(TT1<int>) <= sizeof(TT2<int>)
+  struct B { };
+
+  using b = B<test1, test2>;
+
+  template<ns::C2... T1>
+  struct C { };
+
+  using c1 = C<test1>;
+  using c2 = C<test1, test2, test2>;
+}
\ No newline at end of file
Index: test/Parser/cxx-constrained-template-param-with-partial-id.cpp
===================================================================
--- /dev/null
+++ test/Parser/cxx-constrained-template-param-with-partial-id.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify
+
+template<typename T, int a>
+concept C1 = true;
+
+template<C1 T> // expected-error {{concept 'C1' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}}
+using badA = T[10];
+
+template<C1<0> T>
+using A = T[10];
+
+using a = A<int>;
+
+namespace ns {
+  template<typename T, typename U, typename... X>
+  concept C2 = true;
+}
+
+template<ns::C2 T1, ::ns::C2 T2> // expected-error 2{{concept 'C2' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}}
+requires sizeof(T1) <= sizeof(T2)
+struct badB { };
+
+template<ns::C2<int> T1, ::ns::C2<char, T1> T2>
+  requires sizeof(T1) <= sizeof(T2)
+struct B { };
+
+using b = B<int, int>;
+
+template<ns::C2... T1> // expected-error {{concept 'C2' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}}
+struct badC { };
+
+template<ns::C2<int>... T1>
+struct C { };
+
+using c1 = C<char, char, char>;
+using c2 = C<char, char, char, char>;
\ No newline at end of file
Index: test/CXX/concepts-ts/temp/temp.param/p10.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.param/p10.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T>
+concept C1 = sizeof(T) == 1; // expected-note 2{{because 'sizeof(short) == 1' (2 == 1) evaluated to false}} expected-note {{because 'sizeof(int) == 1' (4 == 1) evaluated to false}}
+
+template<C1 T> // expected-note {{because 'int' does not satisfy 'C1'}}
+using A = T;
+
+using a1 = A<int>; // expected-error {{constraints not satisfied for alias template 'A' [with T = int]}}
+using a2 = A<char>;
+
+template<typename T>
+concept C2 = sizeof(T) == 2; // expected-note 2{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}}
+
+template<C1 T1, C2 T2> // expected-note 2{{because 'short' does not satisfy 'C1'}} expected-note {{because 'char' does not satisfy 'C2'}} expected-note {{and 'char' does not satisfy 'C2'}}
+using B = T1;
+
+using b1 = B<char, short>;
+using b2 = B<char, char>; // expected-error {{constraints not satisfied for alias template 'B' [with T1 = char, T2 = char]}}
+using b3 = B<short, short>; // expected-error {{constraints not satisfied for alias template 'B' [with T1 = short, T2 = short]}}
+using b4 = B<short, char>; // expected-error {{constraints not satisfied for alias template 'B' [with T1 = short, T2 = char]}}
+
+template<typename... T>
+concept C3 = (sizeof(T) + ...) == 12; // expected-note {{because 'sizeof(char [11]) == 12' (11 == 12) evaluated to false}} expected-note {{because 'sizeof(char [10]) == 12' (10 == 12) evaluated to false}} expected-note {{because 'sizeof(char [12]) + sizeof(int [3]) + sizeof(short [6]) == 12' (36 == 12) evaluated to false}}
+
+template<C3 T1, C3 T2, C3 T3> // expected-note {{because 'char [11]' does not satisfy 'C3'}} expected-note {{and 'char [10]' does not satisfy 'C3'}}
+using C = T2;
+
+using c1 = C<char[12], int[3], short[6]>;
+using c2 = C<char[12], char[11], char[10]>; // expected-error {{constraints not satisfied for alias template 'C' [with T1 = char [12], T2 = char [11], T3 = char [10]]}}
+
+template<C3... Ts> // expected-note {{because 'C3<char [12], int [3], short [6]>' evaluated to false}}
+using D = int;
+
+using d1 = D<char[12], int[3], short[6]>; // expected-error {{constraints not satisfied for alias template 'D' [with Ts = <char [12], int [3], short [6]>}}
+using d2 = D<int, int, int>;
+using d3 = D<short, short, short, short, short, short>;
+
+template<typename T>
+concept C4 = sizeof(T) == 4; // expected-note 3{{because 'sizeof(char) == 4' (1 == 4) evaluated to false}}
+
+template<C4... Ts> // expected-note 2{{because 'char' does not satisfy 'C4'}} expected-note {{and 'char' does not satisfy 'C4'}}
+using E = int;
+
+using e1 = E<int>;
+using e2 = E<char, int>; // expected-error {{constraints not satisfied for alias template 'E' [with Ts = <char, int>]}}
+using e3 = E<char, char>; // expected-error {{constraints not satisfied for alias template 'E' [with Ts = <char, char>]}}
+using e4 = E<>;
+
+template<typename T, typename U>
+constexpr bool is_same_v = false;
+
+template<typename T>
+constexpr bool is_same_v<T, T> = true;
+
+template<typename T, typename U>
+concept Same = is_same_v<T, U>; // expected-note {{because 'is_same_v<long, int>' evaluated to false}}
+
+template<Same<int> T> // expected-note {{because 'Same<long, int>' evaluated to false}}
+using F = T;
+
+using f1 = F<int>;
+using f2 = F<long>; // expected-error {{constraints not satisfied for alias template 'F' [with T = long]}}
+
+template<typename T, typename... Ts>
+concept OneOf = (is_same_v<T, Ts> || ...); // expected-note 2{{because 'is_same_v<char, char [1]>' evaluated to false}} expected-note 2{{and 'is_same_v<char, char [2]>' evaluated to false}} expected-note 2{{because 'is_same_v<short, int>' evaluated to false}} expected-note 2{{and 'is_same_v<short, long>' evaluated to false}} expected-note 2{{and 'is_same_v<short, char>' evaluated to false}}
+
+template<OneOf<char[1], char[2]> T, OneOf<int, long, char> U> // expected-note 2{{because 'OneOf<char, char [1], char [2]>' evaluated to false}} expected-note {{because 'OneOf<short, int, long, char>' evaluated to false}} expected-note {{and 'OneOf<short, int, long, char>' evaluated to false}}
+using G = T;
+
+using g1 = G<char[1], int>;
+using g2 = G<char, int>; // expected-error{{constraints not satisfied for alias template 'G' [with T = char, U = int]}}
+using g3 = G<char[1], short>; // expected-error{{constraints not satisfied for alias template 'G' [with T = char [1], U = short]}}
+using g4 = G<char, short>; // expected-error{{constraints not satisfied for alias template 'G' [with T = char, U = short]}}
+
+template<OneOf<char[1], char[2]>... Ts>
+using H = int;
+
+using h1 = H<char[1], int>;
+using h2 = H<int, int>;
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
===================================================================
--- test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
@@ -7,6 +7,14 @@
 template <typename U> requires bool(U())
 struct A;
 
+template<typename T>
+concept C1 = true;
+
+template <C1 T> requires bool(T())
+struct B;
+template <C1 U> requires bool(U())
+struct B;
+
 } // end namespace nodiag
 
 namespace diag {
@@ -24,6 +32,14 @@
 template <typename T> requires !0 // expected-error{{associated constraints differ in template redeclaration}}
 struct C;
 
+template<typename T>
+concept C1 = true;
+
+template <C1 T> // expected-note{{previous template declaration is here}}
+struct D;
+template <typename T> requires C1<T> // expected-error{{associated constraints differ in template redeclaration}}
+struct D;
+
 } // end namespace diag
 
 namespace nodiag {
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -1567,6 +1567,11 @@
 
   Record.push_back(D->wasDeclaredWithTypename());
 
+  Expr *CE = D->getConstraintExpression();
+  Record.push_back(CE != nullptr);
+  if (CE)
+    Record.AddStmt(CE);
+
   bool OwnsDefaultArg = D->hasDefaultArgument() &&
                         !D->defaultArgumentWasInherited();
   Record.push_back(OwnsDefaultArg);
@@ -1598,6 +1603,10 @@
   } else {
     // Rest of NonTypeTemplateParmDecl.
     Record.push_back(D->isParameterPack());
+    Expr *CE = D->getConstraintExpression();
+    Record.push_back(CE != nullptr);
+    if (CE)
+      Record.AddStmt(CE);
     bool OwnsDefaultArg = D->hasDefaultArgument() &&
                           !D->defaultArgumentWasInherited();
     Record.push_back(OwnsDefaultArg);
@@ -1627,6 +1636,10 @@
   } else {
     // Rest of TemplateTemplateParmDecl.
     Record.push_back(D->isParameterPack());
+    Expr *CE = D->getConstraintExpression();
+    Record.push_back(CE != nullptr);
+    if (CE)
+      Record.AddStmt(CE);
     bool OwnsDefaultArg = D->hasDefaultArgument() &&
                           !D->defaultArgumentWasInherited();
     Record.push_back(OwnsDefaultArg);
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -5853,7 +5853,7 @@
 
   Record->push_back(TemplateParams->size());
   for (const auto &P : *TemplateParams)
-    AddDeclRef(P); // TODO: Concepts - constrained parameters.
+    AddDeclRef(P);
   if (const Expr *RequiresClause = TemplateParams->getRequiresClause()) {
     Record->push_back(true);
     AddStmt(const_cast<Expr*>(RequiresClause));
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -2287,6 +2287,9 @@
 
   D->setDeclaredWithTypename(Record.readInt());
 
+  if (Record.readInt())
+    D->setConstraintExpression(Record.readExpr());
+
   if (Record.readInt())
     D->setDefaultArgument(GetTypeSourceInfo());
 }
@@ -2306,6 +2309,8 @@
   } else {
     // Rest of NonTypeTemplateParmDecl.
     D->ParameterPack = Record.readInt();
+    if (Record.readInt())
+      D->setConstraintExpression(Record.readExpr());
     if (Record.readInt())
       D->setDefaultArgument(Record.readExpr());
   }
@@ -2325,6 +2330,8 @@
   } else {
     // Rest of TemplateTemplateParmDecl.
     D->ParameterPack = Record.readInt();
+    if (Record.readInt())
+      D->setConstraintExpression(Record.readExpr());
     if (Record.readInt())
       D->setDefaultArgument(Reader.getContext(),
                             Record.readTemplateArgumentLoc());
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -8664,7 +8664,6 @@
   Params.reserve(NumParams);
   while (NumParams--)
     Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
-    // TODO: Concepts: Constrained parameters
 
   bool HasRequiresClause = Record[Idx++];
   Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2181,7 +2181,12 @@
       D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
       D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
   Inst->setAccess(AS_public);
-
+  if (Expr *CE = D->getConstraintExpression()) {
+    ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs);
+    if (Result.isInvalid())
+      return nullptr;
+    Inst->setConstraintExpression(Result.get());
+  }
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
     TypeSourceInfo *InstantiatedDefaultArg =
         SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs,
@@ -2330,6 +2335,12 @@
   if (Invalid)
     Param->setInvalidDecl();
 
+  if (Expr *CE = D->getConstraintExpression()) {
+    ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs);
+    if (Result.isInvalid())
+      return nullptr;
+    Param->setConstraintExpression(Result.get());
+  }
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
     EnterExpressionEvaluationContext ConstantEvaluated(
         SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
@@ -2454,6 +2465,12 @@
         SemaRef.Context, Owner, D->getLocation(),
         D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
         D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams);
+  if (Expr *CE = D->getConstraintExpression()) {
+    ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs);
+    if (Result.isInvalid())
+      return nullptr;
+    Param->setConstraintExpression(Result.get());
+  }
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
     NestedNameSpecifierLoc QualifierLoc =
         D->getDefaultArgument().getTemplateQualifierLoc();
@@ -3262,10 +3279,7 @@
   void *InsertPos = nullptr;
   ClassTemplateSpecializationDecl *PrevDecl
     = ClassTemplate->findPartialSpecialization(Converted,
-                                               // TODO: Concepts - change this
-                                               // to associated constraints once
-                                               // we have them.
-                                               InstParams->getRequiresClause(),
+                                         InstParams->getAssociatedConstraints(),
                                                InsertPos);
 
   // Build the canonical type that describes the converted template
@@ -3398,10 +3412,7 @@
   void *InsertPos = nullptr;
   VarTemplateSpecializationDecl *PrevDecl =
       VarTemplate->findPartialSpecialization(Converted,
-                                             // TODO: Concepts - change this
-                                             // to associated constraints once
-                                             // we have them.
-                                             InstParams->getRequiresClause(),
+                                         InstParams->getAssociatedConstraints(),
                                              InsertPos);
 
   // Build the canonical type that describes the converted template
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -4431,7 +4431,7 @@
   QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
   NamedDecl *TemplParamPtr = TemplParam;
   FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
-      Loc, Loc, TemplParamPtr, Loc, nullptr);
+      Context, Loc, Loc, TemplParamPtr, Loc, nullptr, nullptr);
 
   QualType FuncParam =
       SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -904,15 +904,20 @@
   return QualType();
 }
 
-Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
+Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S,
+                                          const DeclSpec &DS,
+                                          SourceLocation StartLoc,
+                                          TypeSourceInfo *TInfo,
+                                          IdentifierInfo *ParamName,
+                                          SourceLocation ParamNameLoc,
+                                          bool IsParameterPack,
                                           unsigned Depth,
                                           unsigned Position,
                                           SourceLocation EqualLoc,
                                           Expr *Default) {
-  TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
 
   // Check that we have valid decl-specifiers specified.
-  auto CheckValidDeclSpecifiers = [this, &D] {
+  auto CheckValidDeclSpecifiers = [this, &DS] {
     // C++ [temp.param]
     // p1 
     //   template-parameter:
@@ -924,7 +929,6 @@
     // [dcl.typedef]p1: 
     //   The typedef specifier [...] shall not be used in the decl-specifier-seq
     //   of a parameter-declaration
-    const DeclSpec &DS = D.getDeclSpec();
     auto EmitDiag = [this](SourceLocation Loc) {
       Diag(Loc, diag::err_invalid_decl_specifier_in_nontype_parm)
           << FixItHint::CreateRemoval(Loc);
@@ -966,37 +970,34 @@
   CheckValidDeclSpecifiers();
   
   if (TInfo->getType()->isUndeducedType()) {
-    Diag(D.getIdentifierLoc(),
+    Diag(ParamNameLoc,
          diag::warn_cxx14_compat_template_nontype_parm_auto_type)
       << QualType(TInfo->getType()->getContainedAutoType(), 0);
   }
 
   assert(S->isTemplateParamScope() &&
          "Non-type template parameter not in template parameter scope!");
   bool Invalid = false;
 
-  QualType T = CheckNonTypeTemplateParameterType(TInfo, D.getIdentifierLoc());
+  QualType T = CheckNonTypeTemplateParameterType(TInfo, ParamNameLoc);
   if (T.isNull()) {
     T = Context.IntTy; // Recover with an 'int' type.
     Invalid = true;
   }
 
-  IdentifierInfo *ParamName = D.getIdentifier();
-  bool IsParameterPack = D.hasEllipsis();
   NonTypeTemplateParmDecl *Param
     = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
-                                      D.getLocStart(),
-                                      D.getIdentifierLoc(),
+                                      StartLoc,
+                                      ParamNameLoc,
                                       Depth, Position, ParamName, T,
                                       IsParameterPack, TInfo);
   Param->setAccess(AS_public);
 
   if (Invalid)
     Param->setInvalidDecl();
 
   if (ParamName) {
-    maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
-                                         ParamName);
+    maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
 
     // Add the template parameter into the current scope.
     S->AddDecl(Param);
@@ -2004,12 +2005,11 @@
   if (OldParams)
     OldParam = OldParams->begin();
 
-  // TODO: Concepts: Replace getRequiresClause with getAssociatedConstraints
-  // when we have it.
   if (OldParams &&
-      !CheckRedeclarationConstraintMatch(OldParams->getRequiresClause(),
-                                         NewParams->getRequiresClause())) {
-    DiagnoseRedeclarationConstraintMismatch(OldParams, NewParams);
+      !CheckRedeclarationConstraintMatch(OldParams->getAssociatedConstraints(),
+                                        NewParams->getAssociatedConstraints())){
+    DiagnoseRedeclarationConstraintMismatch(OldParams->getTemplateLoc(),
+                                            NewParams->getTemplateLoc());
     Invalid = true;
   }
 
@@ -3595,9 +3595,7 @@
     if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
                                 Converted)
         && (!Context.getLangOpts().ConceptsTS
-            // TODO: Concepts: change this to getAssociatedConstraints when we
-            // have them.
-            || TemplateParams->getRequiresClause() == nullptr)) {
+            || TemplateParams->getAssociatedConstraints() == nullptr)) {
       // C++ [temp.class.spec]p9b3:
       //
       //   -- The argument list of the specialization shall not be identical
@@ -3618,10 +3616,7 @@
   if (IsPartialSpecialization)
     // FIXME: Template parameter list matters too
     PrevDecl = VarTemplate->findPartialSpecialization(Converted,
-                                            // TODO: Concepts - replace with
-                                            // AssociatedConstraints once we
-                                            // have them.
-                                            TemplateParams->getRequiresClause(),
+                                     TemplateParams->getAssociatedConstraints(),
                                                       InsertPos);
   else
     PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
@@ -3931,20 +3926,19 @@
 
 ExprResult
 Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
-                             const DeclarationNameInfo &NameInfo,
                              ConceptDecl *Template,
                              SourceLocation TemplateLoc,
                              const TemplateArgumentListInfo *TemplateArgs) {
   assert(Template && "A concept template id without template?");
 
   // Check that the template argument list is well-formed for this template.
   SmallVector<TemplateArgument, 4> Converted;
-  if (CheckTemplateArgumentList(Template, NameInfo.getLoc(),
+  if (CheckTemplateArgumentList(Template, TemplateLoc,
         const_cast<TemplateArgumentListInfo &>(*TemplateArgs), false,
           Converted, /*UpdateArgsWithConversions=*/false))
     return ExprError();
 
-  return CreateConceptSpecializationExpr(NameInfo.getLoc(), Template,
+  return CreateConceptSpecializationExpr(TemplateLoc, Template,
                                          TemplateArgs);
 }
 
@@ -3979,9 +3973,8 @@
   }
 
   if (R.getAsSingle<ConceptDecl>()) {
-    return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
-                                  R.getAsSingle<ConceptDecl>(),
-                                  TemplateKWLoc, TemplateArgs);
+    return CheckConceptTemplateId(SS, R.getAsSingle<ConceptDecl>(),
+                                  R.getNameLoc(), TemplateArgs);
   }
 
   // We don't want lookup warnings at this point.
@@ -6768,7 +6761,6 @@
                                        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) {
@@ -6813,55 +6805,67 @@
     return false;
   }
 
+  Expr *OldCE, *NewCE;
+
   // For non-type template parameters, check the type of the parameter.
   if (NonTypeTemplateParmDecl *OldNTTP
                                     = dyn_cast<NonTypeTemplateParmDecl>(Old)) {
     NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(New);
+    OldCE = OldNTTP->getConstraintExpression();
+    NewCE = NewNTTP->getConstraintExpression();
 
     // If we are matching a template template argument to a template
     // template parameter and one of the non-type template parameter types
     // is dependent, then we must wait until template instantiation time
     // to actually compare the arguments.
-    if (Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
-        (OldNTTP->getType()->isDependentType() ||
-         NewNTTP->getType()->isDependentType()))
-      return true;
-
-    if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
-      if (Complain) {
-        unsigned NextDiag = diag::err_template_nontype_parm_different_type;
-        if (TemplateArgLoc.isValid()) {
-          S.Diag(TemplateArgLoc,
-                 diag::err_template_arg_template_params_mismatch);
-          NextDiag = diag::note_template_nontype_parm_different_type;
+    if (Kind != Sema::TPL_TemplateTemplateArgumentMatch ||
+        (!OldNTTP->getType()->isDependentType() &&
+         !NewNTTP->getType()->isDependentType()))
+      if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
+        if (Complain) {
+          unsigned NextDiag = diag::err_template_nontype_parm_different_type;
+          if (TemplateArgLoc.isValid()) {
+            S.Diag(TemplateArgLoc,
+                   diag::err_template_arg_template_params_mismatch);
+            NextDiag = diag::note_template_nontype_parm_different_type;
+          }
+          S.Diag(NewNTTP->getLocation(), NextDiag)
+            << NewNTTP->getType()
+            << (Kind != Sema::TPL_TemplateMatch);
+          S.Diag(OldNTTP->getLocation(),
+                 diag::note_template_nontype_parm_prev_declaration)
+            << OldNTTP->getType();
         }
-        S.Diag(NewNTTP->getLocation(), NextDiag)
-          << NewNTTP->getType()
-          << (Kind != Sema::TPL_TemplateMatch);
-        S.Diag(OldNTTP->getLocation(),
-               diag::note_template_nontype_parm_prev_declaration)
-          << OldNTTP->getType();
-      }
-
-      return false;
-    }
 
-    return true;
+        return false;
+      }
   }
-
   // For template template parameters, check the template parameter types.
   // The template parameter lists of template template
   // parameters must agree.
-  if (TemplateTemplateParmDecl *OldTTP
+  else if (TemplateTemplateParmDecl *OldTTP
                                     = dyn_cast<TemplateTemplateParmDecl>(Old)) {
     TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
-    return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
-                                            OldTTP->getTemplateParameters(),
-                                            Complain,
+    OldCE = OldTTP->getConstraintExpression();
+    NewCE = NewTTP->getConstraintExpression();
+    if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
+                                          OldTTP->getTemplateParameters(),
+                                          Complain,
                                         (Kind == Sema::TPL_TemplateMatch
                                            ? Sema::TPL_TemplateTemplateParmMatch
                                            : Kind),
-                                            TemplateArgLoc);
+                                          TemplateArgLoc))
+      return false;
+  } else {
+    OldCE = cast<TemplateTypeParmDecl>(Old)->getConstraintExpression();
+    NewCE = cast<TemplateTypeParmDecl>(New)->getConstraintExpression();
+  }
+
+  if (!S.CheckRedeclarationConstraintMatch(OldCE, NewCE)) {
+    if (Complain)
+      S.DiagnoseRedeclarationConstraintMismatch(Old->getLocStart(),
+                                                New->getLocStart());
+    return false;
   }
 
   return true;
@@ -6978,10 +6982,14 @@
     return false;
   }
 
-  if (!CheckRedeclarationConstraintMatch(Old->getRequiresClause(),
-                                         New->getRequiresClause())) {
+  Expr *OldRC = Old->getRequiresClause(),
+       *NewRC = New->getRequiresClause();
+  if (!CheckRedeclarationConstraintMatch(OldRC, NewRC)) {
     if (Complain)
-      DiagnoseRedeclarationConstraintMismatch(Old, New);
+      DiagnoseRedeclarationConstraintMismatch(OldRC ? OldRC->getLocStart()
+                                                    : Old->getTemplateLoc(),
+                                              NewRC ? NewRC->getLocStart()
+                                                    : New->getTemplateLoc());
     return false;
   }
 
@@ -7535,10 +7543,7 @@
   if (isPartialSpecialization)
     // FIXME: Template parameter list matters, too
     PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
-                                            // TODO: Concepts: Replace with
-                                            // AssociatedConstraints once we
-                                            // have them.
-                                            TemplateParams->getRequiresClause(),
+                                     TemplateParams->getAssociatedConstraints(),
                                                         InsertPos);
   else
     PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
@@ -7565,9 +7570,7 @@
     if (Context.hasSameType(CanonType,
                         ClassTemplate->getInjectedClassNameSpecialization())
         && (!Context.getLangOpts().ConceptsTS
-            // TODO: Concepts: change this to getAssociatedConstraints when we
-            // have them.
-            || TemplateParams->getRequiresClause() == nullptr)) {
+            || TemplateParams->getAssociatedConstraints() == 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
@@ -63,13 +63,11 @@
 }
 
 void
-Sema::DiagnoseRedeclarationConstraintMismatch(const TemplateParameterList *Old,
-                                              const TemplateParameterList *New){
-  Diag(New->getTemplateLoc(),
-       diag::err_template_different_associated_constraints);
+Sema::DiagnoseRedeclarationConstraintMismatch(SourceLocation Old,
+                                              SourceLocation New){
+  Diag(New, diag::err_template_different_associated_constraints);
 
-  Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
-        << /*declaration*/0;
+  Diag(Old, diag::note_template_prev_declaration) << /*declaration*/0;
 }
 
 template <typename AtomicEvaluator>
Index: lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- lib/Sema/SemaCXXScopeSpec.cpp
+++ lib/Sema/SemaCXXScopeSpec.cpp
@@ -462,6 +462,7 @@
 ///       'true' if the identifier is treated as if it was followed by ':',
 ///        not '::'.
 /// \param OnlyNamespace If true, only considers namespaces in lookup.
+/// \param SuppressDiagnostics If true, will not emit diagnostics on an error.
 ///
 /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
 /// that it contains an extra parameter \p ScopeLookupResult, which provides
@@ -479,7 +480,8 @@
                                        NamedDecl *ScopeLookupResult,
                                        bool ErrorRecoveryLookup,
                                        bool *IsCorrectedToColon,
-                                       bool OnlyNamespace) {
+                                       bool OnlyNamespace,
+                                       bool SuppressDiagnostics) {
   if (IdInfo.Identifier->isEditorPlaceholder())
     return true;
   LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
@@ -574,7 +576,7 @@
     return false;
   }
 
-  if (Found.empty() && !ErrorRecoveryLookup) {
+  if (Found.empty() && !ErrorRecoveryLookup && !SuppressDiagnostics) {
     // If identifier is not found as class-name-or-namespace-name, but is found
     // as other entity, don't look for typos.
     LookupResult R(*this, Found.getLookupNameInfo(), LookupOrdinaryName);
@@ -608,7 +610,8 @@
     }
   }
 
-  if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MSVCCompat) {
+  if (Found.empty() && !ErrorRecoveryLookup && !SuppressDiagnostics
+      && !getLangOpts().MSVCCompat) {
     // We haven't found anything, and we're not recovering from a
     // different kind of error, so look for typos.
     DeclarationName Name = Found.getLookupName();
@@ -678,7 +681,7 @@
            !Context.hasSameType(
                             Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
                                Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
-        if (ErrorRecoveryLookup)
+        if (ErrorRecoveryLookup || SuppressDiagnostics)
           return true;
 
          Diag(IdInfo.IdentifierLoc,
@@ -760,7 +763,7 @@
 
   // Otherwise, we have an error case.  If we don't want diagnostics, just
   // return an error now.
-  if (ErrorRecoveryLookup)
+  if (ErrorRecoveryLookup || SuppressDiagnostics)
     return true;
 
   // If we didn't find anything during our lookup, try again with
@@ -828,13 +831,15 @@
                                        bool EnteringContext, CXXScopeSpec &SS,
                                        bool ErrorRecoveryLookup,
                                        bool *IsCorrectedToColon,
-                                       bool OnlyNamespace) {
+                                       bool OnlyNamespace,
+                                       bool SuppressDiagnostic) {
   if (SS.isInvalid())
     return true;
 
   return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
                                      /*ScopeLookupResult=*/nullptr, false,
-                                     IsCorrectedToColon, OnlyNamespace);
+                                     IsCorrectedToColon, OnlyNamespace,
+                                     SuppressDiagnostic);
 }
 
 bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/RAIIObjectsForParser.h"
@@ -532,29 +533,121 @@
 ///       template-parameter: [C++ temp.param]
 ///         type-parameter
 ///         parameter-declaration
+///         constrained-parameter
+///
+///       type-parameter: (See below)
+///         type-parameter-key ...[opt] identifier[opt]
+///         type-parameter-key identifier[opt] = type-id
+///         'template' '<' template-parameter-list '>' type-parameter-key
+///               ...[opt] identifier[opt]
+///         'template' '<' template-parameter-list '>' type-parameter-key
+///               identifier[opt] '=' id-expression
+///
+///       type-parameter-key:
+///         class
+///         typename
+///
+///       constrained-parameter:
+///         qualified-concept-name ... identifier[opt]
+///         qualified-concept-name identifier[opt]
+///             default-template-argument[opt]
+///
+///       qualified-concept-name:
+///         nested-name-specifier[opt] concept-name
+///         nested-name-specifier[opt] partial-concept-id
+///
+///       partial-concept-id:
+///         concept-name '<' template-argument-list[opt] '>'
+///
+///       default-template-argument:
+///         = type-id
+///         = id-expression
+///         = initializer-clause
 ///
-///       type-parameter: (see below)
-///         'class' ...[opt] identifier[opt]
-///         'class' identifier[opt] '=' type-id
-///         'typename' ...[opt] identifier[opt]
-///         'typename' identifier[opt] '=' type-id
-///         'template' '<' template-parameter-list '>' 
-///               'class' ...[opt] identifier[opt]
-///         'template' '<' template-parameter-list '>' 'class' identifier[opt]
-///               = id-expression
 Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
   if (isStartOfTemplateTypeParameter())
     return ParseTypeParameter(Depth, Position);
 
   if (Tok.is(tok::kw_template))
     return ParseTemplateTemplateParameter(Depth, Position);
 
+  // At this point we're either facing a constrained-parameter or a typename for
+  // a non type template parameter.
+  DeclResult CP = TryParseConstrainedTemplateParameter(Depth, Position);
+  if (!CP.isUnset())
+    return CP.isInvalid() ? nullptr : CP.get();
+
   // If it's none of the above, then it must be a parameter declaration.
   // NOTE: This will pick up errors in the closure of the template parameter
   // list (e.g., template < ; Check here to implement >> style closures.
   return ParseNonTypeTemplateParameter(Depth, Position);
 }
 
+
+DeclResult
+Parser::TryParseConstrainedTemplateParameter(unsigned Depth, unsigned Position){
+  TentativeParsingAction TPA(*this);
+  CXXScopeSpec SS;
+  SourceLocation ParamStartLoc = Tok.getLocation();
+
+  if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+                                     /*EnteringContext=*/false,
+                                     /*MayBePseudoDestructor=*/nullptr,
+                                     /*IsTypename=*/false,
+                                     /*LastII=*/nullptr,
+                                     /*OnlyNamespace=*/true,
+                                     /*SuppressDiagnostics=*/true)) {
+    TPA.Revert();
+    return{};
+  }
+
+  if (!Tok.is(tok::identifier)) {
+    TPA.Revert();
+    return{};
+  }
+
+  UnqualifiedId PossibleConceptName;
+  PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
+                                    Tok.getLocation());
+  ConsumeToken();
+
+  TemplateTy PossibleConcept;
+  bool MemberOfUnknownSpecialization = false;
+  auto TNK = Actions.isTemplateName(getCurScope(), SS,
+                                    /*hasTemplateKeyword=*/false,
+                                    PossibleConceptName,
+                                    /*ObjectType=*/ParsedType(),
+                                    /*EnteringContext=*/false,
+                                    PossibleConcept,
+                                    MemberOfUnknownSpecialization);
+  assert(!MemberOfUnknownSpecialization
+         && "Member when we only allowed namespace scope qualifiers??");
+  if (!PossibleConcept || TNK != TNK_Concept_template) {
+    TPA.Revert();
+    return{};
+  }
+
+  TPA.Commit();
+
+  // At this point we're sure we're dealing with a constrained parameter. It
+  // may or may not have a template parameter list following the concept name.
+  if (Tok.is(tok::less)) {
+    if (AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
+                                /*TemplateKWLoc=*/SourceLocation(),
+                                PossibleConceptName,
+                                /*AllowTypeAnnotation=*/false))
+      return DeclResult(/*Invalid=*/true);
+    PossibleConceptName
+                .setTemplateId((TemplateIdAnnotation*)Tok.getAnnotationValue());
+    ConsumeAnnotationToken();
+  }
+
+  auto *CD = cast<ConceptDecl>(PossibleConcept.get().getAsTemplateDecl());
+  Decl *CP = ParseConstrainedTemplateParameter(Depth, Position, ParamStartLoc,
+                                               PossibleConceptName, CD);
+  return CP ? DeclResult(CP) : DeclResult(/*Invalid=*/true);
+}
+
 /// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
 /// Other kinds of template parameters are parsed in
 /// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
@@ -774,11 +867,240 @@
   }
 
   // Create the parameter.
-  return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl, 
+  return Actions.ActOnNonTypeTemplateParameter(getCurScope(),
+                                               ParamDecl.getDeclSpec(),
+                                               ParamDecl.getLocStart(),
+                                               Actions.GetTypeForDeclarator(
+                                                      ParamDecl, getCurScope()),
+                                               ParamDecl.getIdentifier(),
+                                               ParamDecl.getIdentifierLoc(),
+                                               ParamDecl.hasEllipsis(),
                                                Depth, Position, EqualLoc, 
                                                DefaultArg.get());
 }
 
+Decl *
+Parser::ParseConstrainedTemplateParameter(unsigned Depth, unsigned Position,
+                                          SourceLocation ParamStartLoc,
+                                          UnqualifiedId &ConceptName,
+                                          ConceptDecl *CD) {
+
+  TemplateArgumentListInfo TALI;
+  bool HasPartialConceptId = ConceptName.Kind == UnqualifiedId::IK_TemplateId;
+
+  if (HasPartialConceptId) {
+    // partial-concept-id
+    TALI.setLAngleLoc(ConceptName.TemplateId->LAngleLoc);
+    TALI.setRAngleLoc(ConceptName.TemplateId->RAngleLoc);
+    // Translate the parser's template argument list into our AST format.
+    Actions.translateTemplateArguments(
+      MutableArrayRef<ParsedTemplateArgument>(
+        ConceptName.TemplateId->getTemplateArgs(),
+        ConceptName.TemplateId->NumArgs), TALI);
+  }
+
+  // Grab the ellipsis (if given).
+  SourceLocation EllipsisLoc;
+  TryConsumeToken(tok::ellipsis, EllipsisLoc);
+
+  // Grab the template parameter name (if given)
+  SourceLocation NameLoc;
+  IdentifierInfo *ParamName = nullptr;
+  if (Tok.is(tok::identifier)) {
+    ParamName = Tok.getIdentifierInfo();
+    NameLoc = ConsumeToken();
+  } else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater,
+                         tok::greatergreater)) {
+    // Unnamed template parameter. Don't have to do anything here, just
+    // don't consume this token.
+  } else {
+    Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+    return nullptr;
+  }
+
+  // Recover from misplaced ellipsis.
+  bool AlreadyHasEllipsis = EllipsisLoc.isValid();
+  if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
+    DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis,
+                              true);
+
+  // Grab a default argument (if available).
+  // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
+  // we introduce the type parameter into the local scope.
+  SourceLocation EqualLoc;
+
+  NamedDecl *DeclaredParm = nullptr;
+  NamedDecl *ConceptPrototypeParameter = *CD->getTemplateParameters()->begin();
+  if (TemplateTypeParmDecl *TypeP = dyn_cast<TemplateTypeParmDecl>(
+                                      ConceptPrototypeParameter)) {
+    ParsedType DefaultArg;
+    if (TryConsumeToken(tok::equal, EqualLoc))
+      DefaultArg = ParseTypeName(/*SourceRange=*/nullptr,
+                                 Declarator::TemplateTypeArgContext)
+                     .get();
+    DeclaredParm = cast_or_null<NamedDecl>(
+      Actions.ActOnTypeParameter(getCurScope(),
+                                 TypeP->wasDeclaredWithTypename(),
+                                 EllipsisLoc, ParamStartLoc, ParamName,
+                                 NameLoc, Depth, Position, EqualLoc,
+                                 DefaultArg));
+    if (!DeclaredParm)
+      return nullptr;
+
+    QualType Q(cast<TemplateTypeParmDecl>(DeclaredParm)->getTypeForDecl(),
+               0);
+    if (!EllipsisLoc.isInvalid()
+        && CD->getTemplateParameters()->hasParameterPack())
+      // C++ [temp.param]p11.1
+      //   If P declares a template parameter pack and C is a variadic concept,
+      //   then A is the pack expansion P... . Otherwise, A is the
+      //   id-expression P.
+      Q = Actions.Context.getPackExpansionType(Q, /*NumExpansions=*/None);
+    TALI.prependArgument(
+      TemplateArgumentLoc(TemplateArgument(Q),
+                          TemplateArgumentLocInfo(
+                            Actions.Context.getTrivialTypeSourceInfo(Q))));
+  } else if (TemplateTemplateParmDecl *TemplateP =
+               dyn_cast<TemplateTemplateParmDecl>(ConceptPrototypeParameter)) {
+    ParsedTemplateArgument DefaultArg;
+    if (TryConsumeToken(tok::equal, EqualLoc)) {
+      DefaultArg = ParseTemplateTemplateArgument();
+      if (DefaultArg.isInvalid()) {
+        Diag(Tok.getLocation(),
+             diag::err_default_template_template_parameter_not_template);
+        SkipUntil(tok::comma, tok::greater, tok::greatergreater,
+                  StopAtSemi | StopBeforeMatch);
+      }
+    }
+
+
+    DeclaredParm = cast_or_null<NamedDecl>(
+      Actions.ActOnTemplateTemplateParameter(getCurScope(),
+                                             ParamStartLoc,
+                                             TemplateP->getTemplateParameters(),
+                                             EllipsisLoc, ParamName,
+                                             NameLoc, Depth, Position,
+                                             EqualLoc, DefaultArg));
+    if (!DeclaredParm)
+      return nullptr;
+    TemplateName TemplName(cast_or_null<TemplateDecl>(DeclaredParm));
+
+    // C++ [temp.param]p11.1
+    //   If P declares a template parameter pack and C is a variadic concept,
+    //   then A is the pack expansion P... . Otherwise, A is the
+    //   id-expression P.
+    bool ShouldExpand = !EllipsisLoc.isInvalid()
+        && CD->getTemplateParameters()->hasParameterPack();
+
+    NestedNameSpecifierLocBuilder Builder;
+    TemplateArgumentLocInfo LocInf(Builder.getWithLocInContext(Actions.Context),
+                                   NameLoc, EllipsisLoc);
+    TemplateArgumentLoc TAL(ShouldExpand
+                            ? TemplateArgument(TemplName, Optional<unsigned>())
+                            : TemplateArgument(TemplName), LocInf);
+    TALI.prependArgument(TAL);
+  } else if (NonTypeTemplateParmDecl *NonTypeP =
+               dyn_cast<NonTypeTemplateParmDecl>(ConceptPrototypeParameter)) {
+    ExprResult DefaultArg;
+    if (TryConsumeToken(tok::equal, EqualLoc)) {
+      // C++ [temp.param]p15:
+      //   When parsing a default template-argument for a non-type
+      //   template-parameter, the first non-nested > is taken as the
+      //   end of the template-parameter-list rather than a greater-than
+      //   operator.
+      GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+      EnterExpressionEvaluationContext ConstantEvaluated(
+          Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+      DefaultArg = Actions.CorrectDelayedTyposInExpr(
+                     ParseAssignmentExpression());
+      if (DefaultArg.isInvalid())
+        SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
+    }
+
+    DeclaredParm = cast_or_null<NamedDecl>(
+      Actions.ActOnNonTypeTemplateParameter(getCurScope(),
+                                            DeclSpec(getAttrFactory()),
+                                            ParamStartLoc,
+                                            NonTypeP->getTypeSourceInfo(),
+                                            ParamName,
+                                            NameLoc,
+                                            EllipsisLoc.isValid(),
+                                            Depth, Position, EqualLoc,
+                                            DefaultArg.isInvalid() ? nullptr :
+                                                             DefaultArg.get()));
+    if (!DeclaredParm)
+      return nullptr;
+
+    ValueDecl *VD = cast<ValueDecl>(DeclaredParm);
+    Expr *DerivedArgument =
+      new (Actions.Context) DeclRefExpr(VD,
+                                   /*RefersToEnclosingVariableOrCapture=*/false,
+                                        VD->getType(), VK_LValue, NameLoc,
+                                        DeclarationNameLoc(VD->getDeclName()));
+    // C++ [temp.param]p11.1
+    //   If P declares a template parameter pack and C is a variadic concept,
+    //   then A is the pack expansion P... . Otherwise, A is the
+    //   id-expression P.
+    if (EllipsisLoc.isValid()
+        && CD->getTemplateParameters()->hasParameterPack())
+      DerivedArgument =
+        new (Actions.Context) PackExpansionExpr(Actions.Context.DependentTy,
+                                                DerivedArgument, EllipsisLoc,
+                                                /*NumExpansions=*/None);
+    TemplateArgument DeclaredParmA(DerivedArgument);
+    TALI.prependArgument(
+      TemplateArgumentLoc(DeclaredParmA,
+                          TemplateArgumentLocInfo(DerivedArgument)));
+  } else
+    llvm_unreachable("Unrecognized concept prototype parameter type.");
+
+  // We now have an actual template parmeter declared - form the constraint
+  // expression and attach it to the declared parameter.
+
+  // If the user did not use a partial concept id and the concept does not
+  // accept a single argument or parameter pack, fail now with a nicer error
+  // message
+  if (!HasPartialConceptId
+      && CD->getTemplateParameters()->getMinRequiredArguments() > 1) {
+    Diag(diag::err_constrained_parameter_missing_arguments) << CD;
+    return DeclaredParm;
+  }
+
+  CXXScopeSpec SS;
+  ExprResult Result = Actions.CheckConceptTemplateId(SS, CD, ParamStartLoc,
+                                                     &TALI);
+  if (Result.isInvalid() || !Result.isUsable())
+    // Just ignore the constraint and attempt to continue.
+    return DeclaredParm;
+
+  Expr *IntroducedConstraint = Result.get();
+  if (EllipsisLoc.isValid() && !CD->getTemplateParameters()->hasParameterPack())
+    // We have the following case:
+    //
+    // template<typename T> concept C1 = true;
+    // template<C1... T> struct s1;
+    //
+    // The constraint: (C1<T> && ...)
+    IntroducedConstraint =
+      Actions.ActOnCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
+                               IntroducedConstraint, tok::ampamp,
+                               EllipsisLoc, /*RHS=*/nullptr,
+                               /*RParenLoc=*/SourceLocation()).get();
+
+  if (TemplateTypeParmDecl *TypeP =
+        dyn_cast<TemplateTypeParmDecl>(DeclaredParm))
+    TypeP->setConstraintExpression(IntroducedConstraint);
+  else if (TemplateTemplateParmDecl *TemplateP =
+               dyn_cast<TemplateTemplateParmDecl>(DeclaredParm))
+    TemplateP->setConstraintExpression(IntroducedConstraint);
+  else
+    cast<NonTypeTemplateParmDecl>(DeclaredParm)
+      ->setConstraintExpression(IntroducedConstraint);
+
+  return DeclaredParm;
+}
+
 void Parser::DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc,
                                        SourceLocation CorrectLoc,
                                        bool AlreadyHasEllipsis,
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -143,14 +143,18 @@
 ///
 /// \param OnlyNamespace If true, only considers namespaces in lookup.
 ///
+/// \param SuppressDiagnostic If true, suppress diagnostic on incorrect scope
+///                           specifier.
+///
 /// \returns true if there was an error parsing a scope specifier
 bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
                                             ParsedType ObjectType,
                                             bool EnteringContext,
                                             bool *MayBePseudoDestructor,
                                             bool IsTypename,
                                             IdentifierInfo **LastII,
-                                            bool OnlyNamespace) {
+                                            bool OnlyNamespace,
+                                            bool SuppressDiagnostic) {
   assert(getLangOpts().CPlusPlus &&
          "Call sites of this function should be guarded by checking for C++");
 
@@ -455,7 +459,7 @@
       bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
       if (Actions.ActOnCXXNestedNameSpecifier(
               getCurScope(), IdInfo, EnteringContext, SS, false,
-              CorrectionFlagPtr, OnlyNamespace)) {
+              CorrectionFlagPtr, OnlyNamespace, SuppressDiagnostic)) {
         // Identifier is not recognized as a nested name, but we can have
         // mistyped '::' instead of ':'.
         if (CorrectionFlagPtr && IsCorrectedToColon) {
@@ -476,6 +480,11 @@
     // nested-name-specifier:
     //   type-name '<'
     if (Next.is(tok::less)) {
+      if (OnlyNamespace)
+        // We can't have template-ids as part of a namespace scope specifier,
+        // the scope specifier must end here.
+        break;
+
       TemplateTy Template;
       UnqualifiedId TemplateName;
       TemplateName.setIdentifier(&II, Tok.getLocation());
@@ -2440,14 +2449,17 @@
 ///
 /// \param Result on a successful parse, contains the parsed unqualified-id.
 ///
+/// \param SuppressDiag whether to suppress the diagnostic when an unqualified
+///        id was not found at the current location.
+///
 /// \returns true if parsing fails, false otherwise.
 bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
                                 bool AllowDestructorName,
                                 bool AllowConstructorName,
                                 bool AllowDeductionGuide,
                                 ParsedType ObjectType,
                                 SourceLocation& TemplateKWLoc,
-                                UnqualifiedId &Result) {
+                                UnqualifiedId &Result, bool SuppressDiag) {
 
   // Handle 'A::template B'. This is for template-ids which have not
   // already been annotated by ParseOptionalCXXScopeSpecifier().
@@ -2649,9 +2661,10 @@
     Result.setDestructorName(TildeLoc, Ty, ClassNameLoc);
     return false;
   }
-  
-  Diag(Tok, diag::err_expected_unqualified_id)
-    << getLangOpts().CPlusPlus;
+
+  if (!SuppressDiag)
+    Diag(Tok, diag::err_expected_unqualified_id)
+      << getLangOpts().CPlusPlus;
   return true;
 }
 
Index: lib/AST/ODRHash.cpp
===================================================================
--- lib/AST/ODRHash.cpp
+++ lib/AST/ODRHash.cpp
@@ -365,6 +365,11 @@
       AddTemplateArgument(D->getDefaultArgument());
     }
 
+    Expr *CE = D->getConstraintExpression();
+    Hash.AddBoolean(CE != nullptr);
+    if (CE)
+      AddStmt(CE);
+
     Inherited::VisitTemplateTypeParmDecl(D);
   }
 
@@ -377,6 +382,11 @@
       AddStmt(D->getDefaultArgument());
     }
 
+    Expr *CE = D->getConstraintExpression();
+    Hash.AddBoolean(CE != nullptr);
+    if (CE)
+      AddStmt(CE);
+
     Inherited::VisitNonTypeTemplateParmDecl(D);
   }
 
@@ -389,6 +399,11 @@
       AddTemplateArgument(D->getDefaultArgument().getArgument());
     }
 
+    Expr *CE = D->getConstraintExpression();
+    Hash.AddBoolean(CE != nullptr);
+    if (CE)
+      AddStmt(CE);
+
     Inherited::VisitTemplateTemplateParmDecl(D);
   }
 };
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -43,14 +43,30 @@
 // TemplateParameterList Implementation
 //===----------------------------------------------------------------------===//
 
-TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
+// Create a constraint expression as the conjunction (the "and") of two other
+// constraint expressions.
+static Expr *CreateConstraintConjunction(const ASTContext &C, Expr *A, Expr *B){
+  if (!A) {
+    return B;
+  }
+  if (B) {
+    return new (C) BinaryOperator(A, B, BO_LAnd, C.BoolTy, VK_RValue,
+                                  OK_Ordinary, /*opLoc=*/SourceLocation(),
+                                  FPOptions());
+  }
+  return A;
+}
+
+TemplateParameterList::TemplateParameterList(const ASTContext& C,
+                                             SourceLocation TemplateLoc,
                                              SourceLocation LAngleLoc,
                                              ArrayRef<NamedDecl *> Params,
                                              SourceLocation RAngleLoc,
-                                             Expr *RequiresClause)
+                                             Expr *RequiresClause,
+                                             Expr *ConstrainedParamsConstraints)
     : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
       NumParams(Params.size()), ContainsUnexpandedParameterPack(false),
-      HasRequiresClause(static_cast<bool>(RequiresClause)) {
+      HasAssociatedConstraints(ConstrainedParamsConstraints || RequiresClause) {
   for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
     NamedDecl *P = Params[Idx];
     begin()[Idx] = P;
@@ -68,21 +84,37 @@
       // template parameter list does too.
     }
   }
-  if (RequiresClause) {
-    *getTrailingObjects<Expr *>() = RequiresClause;
+  if (HasAssociatedConstraints) {
+    Expr **ACStorage = getTrailingObjects<Expr *>();
+    ACStorage[0] = RequiresClause;
+    ACStorage[1] = CreateConstraintConjunction(C, RequiresClause,
+                                               ConstrainedParamsConstraints);
   }
 }
 
 TemplateParameterList *
 TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc,
                               SourceLocation LAngleLoc,
                               ArrayRef<NamedDecl *> Params,
                               SourceLocation RAngleLoc, Expr *RequiresClause) {
+  Expr *AC = nullptr;
+  for (NamedDecl *P : Params)
+    if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
+      if (Expr *CE = NTTP->getConstraintExpression())
+        AC = CreateConstraintConjunction(C, AC, CE);
+    } else if (TemplateTemplateParmDecl *TTP =
+                                        dyn_cast<TemplateTemplateParmDecl>(P)) {
+      if (Expr *CE = TTP->getConstraintExpression())
+        AC = CreateConstraintConjunction(C, AC, CE);
+    } else
+      if (Expr *CE = cast<TemplateTypeParmDecl>(P)->getConstraintExpression())
+        AC = CreateConstraintConjunction(C, AC, CE);
+
   void *Mem = C.Allocate(totalSizeToAlloc<NamedDecl *, Expr *>(
-                             Params.size(), RequiresClause ? 1u : 0u),
+                             Params.size(), RequiresClause || AC ? 2u : 0u),
                          alignof(TemplateParameterList));
-  return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
-                                         RAngleLoc, RequiresClause);
+  return new (Mem) TemplateParameterList(C, TemplateLoc, LAngleLoc, Params,
+                                         RAngleLoc, RequiresClause, AC);
 }
 
 unsigned TemplateParameterList::getMinRequiredArguments() const {
@@ -146,27 +178,11 @@
 
 } // namespace clang
 
-// Create a constraint expression as the conjunction (the "and") of two other
-// constraint expressions.
-static Expr *CreateConstraintConjunction(ASTContext &C, Expr *A, Expr *B) {
-  if (!A) {
-    return B;
-  }
-  if (B) {
-    return new (C) BinaryOperator(A, B, BO_LAnd, C.BoolTy, VK_RValue,
-                                  OK_Ordinary, /*opLoc=*/SourceLocation(),
-                                  FPOptions());
-  }
-  return A;
-}
-
 static ConstrainedTemplateDeclInfo *
 collectAssociatedConstraints(ASTContext &C, TemplateParameterList *Params,
                              Expr *TrailingRequiresClause = nullptr) {
-  // TODO: Instead of calling getRequiresClause - write and call a
-  // TemplateParameterList member function calculateAssociatedConstraints, which
-  // will also fetch constraint-expressions from constrained-parameters.
-  Expr *TotalAC = CreateConstraintConjunction(C, Params->getRequiresClause(),
+  Expr *TotalAC = CreateConstraintConjunction(C,
+                                             Params->getAssociatedConstraints(),
                                               TrailingRequiresClause);
   if (TotalAC) {
     ConstrainedTemplateDeclInfo *CTDI = new (C) ConstrainedTemplateDeclInfo;
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -3696,15 +3696,17 @@
   // is created.
   
   // FIXME: Import default argument.
-  return TemplateTypeParmDecl::Create(Importer.getToContext(),
-                              Importer.getToContext().getTranslationUnitDecl(),
-                                      Importer.Import(D->getLocStart()),
-                                      Importer.Import(D->getLocation()),
-                                      D->getDepth(),
-                                      D->getIndex(), 
-                                      Importer.Import(D->getIdentifier()),
-                                      D->wasDeclaredWithTypename(),
-                                      D->isParameterPack());
+  auto *R = TemplateTypeParmDecl::Create(Importer.getToContext(),
+                               Importer.getToContext().getTranslationUnitDecl(),
+                               Importer.Import(D->getLocStart()),
+                               Importer.Import(D->getLocation()),
+                               D->getDepth(), D->getIndex(),
+                               Importer.Import(D->getIdentifier()),
+                               D->wasDeclaredWithTypename(),
+                               D->isParameterPack());
+  if (Expr *CE = D->getConstraintExpression())
+    R->setConstraintExpression(VisitExpr(CE));
+  return R;
 }
 
 Decl *
@@ -3729,12 +3731,15 @@
 
   // FIXME: Import default argument.
   
-  return NonTypeTemplateParmDecl::Create(Importer.getToContext(),
+  auto *R = NonTypeTemplateParmDecl::Create(Importer.getToContext(),
                                Importer.getToContext().getTranslationUnitDecl(),
-                                         Importer.Import(D->getInnerLocStart()),
-                                         Loc, D->getDepth(), D->getPosition(),
-                                         Name.getAsIdentifierInfo(),
-                                         T, D->isParameterPack(), TInfo);
+                               Importer.Import(D->getInnerLocStart()),
+                               Loc, D->getDepth(), D->getPosition(),
+                               Name.getAsIdentifierInfo(), T,
+                               D->isParameterPack(), TInfo);
+  if (Expr *CE = D->getConstraintExpression())
+    R->setConstraintExpression(VisitExpr(CE));
+  return R;
 }
 
 Decl *
@@ -3754,13 +3759,14 @@
     return nullptr;
 
   // FIXME: Import default argument.
-  
-  return TemplateTemplateParmDecl::Create(Importer.getToContext(), 
-                              Importer.getToContext().getTranslationUnitDecl(), 
-                                          Loc, D->getDepth(), D->getPosition(),
-                                          D->isParameterPack(),
-                                          Name.getAsIdentifierInfo(), 
-                                          TemplateParams);
+  auto *R = TemplateTemplateParmDecl::Create(Importer.getToContext(),
+                              Importer.getToContext().getTranslationUnitDecl(),
+                              Loc, D->getDepth(), D->getPosition(),
+                              D->isParameterPack(), Name.getAsIdentifierInfo(),
+                              TemplateParams);
+  if (Expr *CE = D->getConstraintExpression())
+    R->setConstraintExpression(VisitExpr(CE));
+  return R;
 }
 
 Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -1649,6 +1649,10 @@
   if (D->isParameterPack())
     OS << " ...";
   dumpName(D);
+  if (Expr *CE = D->getConstraintExpression()) {
+    OS << " requires ";
+    dumpStmt(CE);
+  }
   if (D->hasDefaultArgument())
     dumpTemplateArgument(D->getDefaultArgument());
 }
@@ -1659,6 +1663,10 @@
   if (D->isParameterPack())
     OS << " ...";
   dumpName(D);
+  if (Expr *CE = D->getConstraintExpression()) {
+    OS << " requires ";
+    dumpStmt(CE);
+  }
   if (D->hasDefaultArgument())
     dumpTemplateArgument(D->getDefaultArgument());
 }
@@ -1670,6 +1678,10 @@
     OS << " ...";
   dumpName(D);
   dumpTemplateParameters(D->getTemplateParameters());
+  if (Expr *CE = D->getConstraintExpression()) {
+    OS << " requires ";
+    dumpStmt(CE);
+  }
   if (D->hasDefaultArgument())
     dumpTemplateArgumentLoc(D->getDefaultArgument());
 }
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -699,8 +699,8 @@
                                            cast<TemplateTemplateParmDecl>(*P)));
   }
 
-  assert(!TTP->getTemplateParameters()->getRequiresClause() &&
-         "Unexpected requires-clause on template template-parameter");
+  assert(!TTP->getAssociatedConstraints() &&
+         "Unexpected constraints on template template-parameter");
   Expr *const CanonRequiresClause = nullptr;
 
   TemplateTemplateParmDecl *CanonTTP
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5327,7 +5327,8 @@
                                    NamedDecl *ScopeLookupResult,
                                    bool ErrorRecoveryLookup,
                                    bool *IsCorrectedToColon = nullptr,
-                                   bool OnlyNamespace = false);
+                                   bool OnlyNamespace = false,
+                                   bool SuppressDiagnostics = false);
 
   /// \brief The parser has parsed a nested-name-specifier 'identifier::'.
   ///
@@ -5353,14 +5354,17 @@
   ///
   /// \param OnlyNamespace If true, only considers namespaces in lookup.
   ///
+  /// \param SuppressDiagnostic If true, suppress diagnostic on error.
+  ///
   /// \returns true if an error occurred, false otherwise.
   bool ActOnCXXNestedNameSpecifier(Scope *S,
                                    NestedNameSpecInfo &IdInfo,
                                    bool EnteringContext,
                                    CXXScopeSpec &SS,
                                    bool ErrorRecoveryLookup = false,
                                    bool *IsCorrectedToColon = nullptr,
-                                   bool OnlyNamespace = false);
+                                   bool OnlyNamespace = false,
+                                   bool SuppressDiagnostic = false);
 
   ExprResult ActOnDecltypeExpression(Expr *E);
 
@@ -5658,8 +5662,8 @@
   void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation,
                                               StringRef Diagnostic);
 
-  void DiagnoseRedeclarationConstraintMismatch(const TemplateParameterList *Old,
-                                              const TemplateParameterList *New);
+  void DiagnoseRedeclarationConstraintMismatch(SourceLocation Old,
+                                               SourceLocation New);
 
   // ParseObjCStringLiteral - Parse Objective-C string literals.
   ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
@@ -6166,11 +6170,17 @@
                                              SourceLocation Loc);
   QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
 
-  Decl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
+  Decl *ActOnNonTypeTemplateParameter(Scope *S,
+                                      const DeclSpec &DS,
+                                      SourceLocation StartLoc,
+                                      TypeSourceInfo *TInfo,
+                                      IdentifierInfo *ParamName,
+                                      SourceLocation ParamNameLoc,
+                                      bool IsParameterPack,
                                       unsigned Depth,
                                       unsigned Position,
                                       SourceLocation EqualLoc,
-                                      Expr *DefaultArg);
+                                      Expr *Default);
   Decl *ActOnTemplateTemplateParameter(Scope *S,
                                        SourceLocation TmpLoc,
                                        TemplateParameterList *Params,
@@ -6277,9 +6287,7 @@
                                 const TemplateArgumentListInfo *TemplateArgs);
 
   ExprResult
-  CheckConceptTemplateId(const CXXScopeSpec &SS,
-                         const DeclarationNameInfo &NameInfo,
-                         ConceptDecl *Template,
+  CheckConceptTemplateId(const CXXScopeSpec &SS, ConceptDecl *Template,
                          SourceLocation TemplateLoc,
                          const TemplateArgumentListInfo *TemplateArgs);
 
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1584,7 +1584,8 @@
                                       bool *MayBePseudoDestructor = nullptr,
                                       bool IsTypename = false,
                                       IdentifierInfo **LastII = nullptr,
-                                      bool OnlyNamespace = false);
+                                      bool OnlyNamespace = false,
+                                      bool SuppressDiagnostic = false);
 
   //===--------------------------------------------------------------------===//
   // C++0x 5.1.2: Lambda expressions
@@ -2719,7 +2720,7 @@
                           bool AllowDeductionGuide,
                           ParsedType ObjectType,
                           SourceLocation& TemplateKWLoc,
-                          UnqualifiedId &Result);
+                          UnqualifiedId &Result, bool SuppressDiag = false);
 
 private:
   //===--------------------------------------------------------------------===//
@@ -2752,6 +2753,12 @@
   Decl *ParseTypeParameter(unsigned Depth, unsigned Position);
   Decl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position);
   Decl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position);
+  DeclResult TryParseConstrainedTemplateParameter(unsigned Depth,
+                                                             unsigned Position);
+  Decl *ParseConstrainedTemplateParameter(unsigned Depth, unsigned Position,
+                                      SourceLocation ParamStartLoc,
+                                      UnqualifiedId &ConceptName,
+                                      ConceptDecl *CD);
   void DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc,
                                  SourceLocation CorrectLoc,
                                  bool AlreadyHasEllipsis,
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -666,6 +666,9 @@
 def err_explicit_instantiation_enum : Error<
   "enumerations cannot be explicitly instantiated">;
 def err_expected_template_parameter : Error<"expected template parameter">;
+def err_constrained_parameter_missing_arguments : Error<
+  "concept %0 requires more than 1 template argument; provide the remaining "
+  "arguments explicitly to use it here">;
 
 def err_missing_dependent_template_keyword : Error<
   "use 'template' keyword to treat '%0' as a dependent template name">;
Index: include/clang/AST/TemplateBase.h
===================================================================
--- include/clang/AST/TemplateBase.h
+++ include/clang/AST/TemplateBase.h
@@ -586,6 +586,10 @@
   void addArgument(const TemplateArgumentLoc &Loc) {
     Arguments.push_back(Loc);
   }
+
+  void prependArgument(const TemplateArgumentLoc &Loc) {
+    Arguments.insert(Arguments.begin(), Loc);
+  }
 };
 
 /// \brief Represents an explicit template argument list in C++, e.g.,
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1730,9 +1730,10 @@
   // D is the "T" in something like
   //   template <template <typename> class T> class container { };
   TRY_TO(TraverseDecl(D->getTemplatedDecl()));
-  if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
+  if (Expr *CE = D->getConstraintExpression())
+    TRY_TO(TraverseStmt(CE));
+  if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
     TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
-  }
   TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
 })
 
@@ -1744,6 +1745,8 @@
   // D is the "T" in something like "template<typename T> class vector;"
   if (D->getTypeForDecl())
     TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
+  if (Expr *CE = D->getConstraintExpression())
+    TRY_TO(TraverseStmt(CE));
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
     TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
 })
@@ -2061,6 +2064,8 @@
 DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
   // A non-type template parameter, e.g. "S" in template<int S> class Foo ...
   TRY_TO(TraverseDeclaratorHelper(D));
+  if (Expr *CE = D->getConstraintExpression())
+    TRY_TO(TraverseStmt(CE));
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
     TRY_TO(TraverseStmt(D->getDefaultArgument()));
 })
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -82,20 +82,22 @@
   /// pack.
   unsigned ContainsUnexpandedParameterPack : 1;
 
-  /// Whether this template parameter list has an associated requires-clause
-  unsigned HasRequiresClause : 1;
+  /// Whether this template parameter list has associated constraints, be it a
+  /// requires clause or constrained parameters.
+  unsigned HasAssociatedConstraints : 1;
 
 protected:
-  TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
-                        ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc,
-                        Expr *RequiresClause);
+  TemplateParameterList(const ASTContext& C, SourceLocation TemplateLoc,
+                        SourceLocation LAngleLoc, ArrayRef<NamedDecl *> Params,
+                        SourceLocation RAngleLoc, Expr *RequiresClause,
+                        Expr *ConstrainedParamsConstraints);
 
   size_t numTrailingObjects(OverloadToken<NamedDecl *>) const {
     return NumParams;
   }
 
   size_t numTrailingObjects(OverloadToken<Expr *>) const {
-    return HasRequiresClause;
+    return HasAssociatedConstraints ? 2 : 0;
   }
 
 public:
@@ -159,14 +161,29 @@
     return ContainsUnexpandedParameterPack;
   }
 
+  /// \brief Determine whether this template parameter list contains a parameter
+  /// pack.
+  bool hasParameterPack() const {
+    for (const NamedDecl *P : asArray())
+      if (P->isParameterPack())
+        return true;
+    return false;
+  }
+
   /// \brief The constraint-expression of the associated requires-clause.
   Expr *getRequiresClause() {
-    return HasRequiresClause ? *getTrailingObjects<Expr *>() : nullptr;
+    return HasAssociatedConstraints ? getTrailingObjects<Expr *>()[0] : nullptr;
   }
 
   /// \brief The constraint-expression of the associated requires-clause.
   const Expr *getRequiresClause() const {
-    return HasRequiresClause ? *getTrailingObjects<Expr *>() : nullptr;
+    return HasAssociatedConstraints ? getTrailingObjects<Expr *>()[0] : nullptr;
+  }
+
+  /// \brief Gets the combined constraint-expression derived from the associated
+  /// requires-clause and constrained-parameters (if any).
+  Expr *getAssociatedConstraints() const {
+    return HasAssociatedConstraints ? getTrailingObjects<Expr *>()[1] : nullptr;
   }
 
   SourceLocation getTemplateLoc() const { return TemplateLoc; }
@@ -185,25 +202,29 @@
 /// \brief Stores a list of template parameters and the associated
 /// requires-clause (if any) for a TemplateDecl and its derived classes.
 /// Suitable for creating on the stack.
-template <size_t N, bool HasRequiresClause>
+template <size_t N, bool HasAssociatedConstraints>
 class FixedSizeTemplateParameterListStorage
     : public TemplateParameterList::FixedSizeStorageOwner {
   typename TemplateParameterList::FixedSizeStorage<
       NamedDecl *, Expr *>::with_counts<
-      N, HasRequiresClause ? 1u : 0u
+      N, HasAssociatedConstraints ? 2u : 0u
       >::type storage;
 
 public:
-  FixedSizeTemplateParameterListStorage(SourceLocation TemplateLoc,
+  FixedSizeTemplateParameterListStorage(const ASTContext &C,
+                                        SourceLocation TemplateLoc,
                                         SourceLocation LAngleLoc,
                                         ArrayRef<NamedDecl *> Params,
                                         SourceLocation RAngleLoc,
-                                        Expr *RequiresClause)
+                                        Expr *RequiresClause,
+                                        Expr *ConstrainedParamsConstraints)
       : FixedSizeStorageOwner(
             (assert(N == Params.size()),
-             assert(HasRequiresClause == static_cast<bool>(RequiresClause)),
-             new (static_cast<void *>(&storage)) TemplateParameterList(
-                 TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause))) {}
+             assert(HasAssociatedConstraints ==
+                              (RequiresClause || ConstrainedParamsConstraints)),
+             new (static_cast<void *>(&storage)) TemplateParameterList(C,
+                 TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause,
+                 ConstrainedParamsConstraints))) {}
 };
 
 /// \brief A template argument list.
@@ -1131,6 +1152,10 @@
       DefaultArgStorage<TemplateTypeParmDecl, TypeSourceInfo *>;
   DefArgStorage DefaultArgument;
 
+  /// \brief The constraint expression introduced by this declaration (by means
+  /// of a 'constrained-parameter'.
+  Expr *ConstraintExpression = nullptr;
+
   TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc,
                        SourceLocation IdLoc, IdentifierInfo *Id,
                        bool Typename)
@@ -1207,6 +1232,18 @@
   /// \brief Returns whether this is a parameter pack.
   bool isParameterPack() const;
 
+  /// \brief Returns the constraint expression associated with this template
+  /// parameter (if any).
+  Expr *getConstraintExpression() const {
+    return ConstraintExpression;
+  }
+
+  /// \brief Sets the constraint expression associated with this template
+  /// parameter (if any).
+  void setConstraintExpression(Expr *E) {
+    ConstraintExpression = E;
+  }
+
   SourceRange getSourceRange() const override LLVM_READONLY;
 
   // Implement isa/cast/dyncast/etc.
@@ -1246,6 +1283,10 @@
   /// \brief The number of types in an expanded parameter pack.
   unsigned NumExpandedTypes = 0;
 
+  /// \brief The constraint expression introduced by this declaration (by means
+  /// of a 'constrained-parameter'.
+  Expr *ConstraintExpression = nullptr;
+
   size_t numTrailingObjects(
       OverloadToken<std::pair<QualType, TypeSourceInfo *>>) const {
     return NumExpandedTypes;
@@ -1392,6 +1433,18 @@
     return TypesAndInfos[I].second;
   }
 
+  /// \brief Returns the constraint expression associated with this template
+  /// parameter (if any).
+  Expr *getConstraintExpression() const {
+    return ConstraintExpression;
+  }
+
+  /// \brief Sets the constraint expression associated with this template
+  /// parameter (if any).
+  void setConstraintExpression(Expr *E) {
+    ConstraintExpression = E;
+  }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == NonTypeTemplateParm; }
@@ -1425,6 +1478,10 @@
   /// \brief The number of parameters in an expanded parameter pack.
   unsigned NumExpandedParams = 0;
 
+  /// \brief The constraint expression introduced by this declaration (by means
+  /// of a 'constrained-parameter'.
+  Expr *ConstraintExpression = nullptr;
+
   TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
                            unsigned D, unsigned P, bool ParameterPack,
                            IdentifierInfo *Id, TemplateParameterList *Params)
@@ -1552,6 +1609,18 @@
   /// \brief Removes the default argument of this template parameter.
   void removeDefaultArgument() { DefaultArgument.clear(); }
 
+  /// \brief Returns the constraint expression associated with this template
+  /// parameter (if any).
+  Expr *getConstraintExpression() const {
+    return ConstraintExpression;
+  }
+
+  /// \brief Sets the constraint expression associated with this template
+  /// parameter (if any).
+  void setConstraintExpression(Expr *E) {
+    ConstraintExpression = E;
+  }
+
   SourceRange getSourceRange() const override LLVM_READONLY {
     SourceLocation End = getLocation();
     if (hasDefaultArgument() && !defaultArgumentWasInherited())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to