[Concepts] Placeholder constraints and abbreviated templates

This patch implements P1141R2 "Yet another approach for constrained declarations".

General strategy for this patch was:

- Expand AutoType to include optional type-constraint, reflecting the wording and easing the integration of constraints.
- Replace autos in parameter type specifiers with invented parameters in GetTypeSpecTypeForDeclarator, using the same logic
  previously used for generic lambdas, now unified with abbreviated templates, by:
  - Tracking the template parameter lists in the Declarator object
  - Tracking the template parameter depth before parsing function declarators (at which point we can match template
    parameters against scope specifiers to know if we have an explicit template parameter list to append invented parameters
    to or not).
- When encountering an AutoType in a parameter context we check a stack of InventedTemplateParameterInfo structures that
  contain the info required to create and accumulate invented template parameters (fields that were already present in
  LambdaScopeInfo, which now inherits from this class and is looked up when an auto is encountered in a lambda context).

Resubmit after fixing MSAN failures caused by incomplete initialization of AutoTypeLocs in TypeSpecLocFiller.

Differential Revision: https://reviews.llvm.org/D65042
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a514292..6d1db38 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -716,6 +716,61 @@
     RequiresClause->Profile(ID, C, /*Canonical=*/true);
 }
 
+static Expr *
+canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
+                                          QualType ConstrainedType) {
+  // This is a bit ugly - we need to form a new immediately-declared
+  // constraint that references the new parameter; this would ideally
+  // require semantic analysis (e.g. template<C T> struct S {}; - the
+  // converted arguments of C<T> could be an argument pack if C is
+  // declared as template<typename... T> concept C = ...).
+  // We don't have semantic analysis here so we dig deep into the
+  // ready-made constraint expr and change the thing manually.
+  ConceptSpecializationExpr *CSE;
+  if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
+    CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
+  else
+    CSE = cast<ConceptSpecializationExpr>(IDC);
+  ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
+  SmallVector<TemplateArgument, 3> NewConverted;
+  NewConverted.reserve(OldConverted.size());
+  if (OldConverted.front().getKind() == TemplateArgument::Pack) {
+    // The case:
+    // template<typename... T> concept C = true;
+    // template<C<int> T> struct S; -> constraint is C<{T, int}>
+    NewConverted.push_back(ConstrainedType);
+    for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
+      NewConverted.push_back(Arg);
+    TemplateArgument NewPack(NewConverted);
+
+    NewConverted.clear();
+    NewConverted.push_back(NewPack);
+    assert(OldConverted.size() == 1 &&
+           "Template parameter pack should be the last parameter");
+  } else {
+    assert(OldConverted.front().getKind() == TemplateArgument::Type &&
+           "Unexpected first argument kind for immediately-declared "
+           "constraint");
+    NewConverted.push_back(ConstrainedType);
+    for (auto &Arg : OldConverted.drop_front(1))
+      NewConverted.push_back(Arg);
+  }
+  Expr *NewIDC = ConceptSpecializationExpr::Create(
+      C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
+      CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
+      CSE->getNamedConcept(),
+      // Actually canonicalizing a TemplateArgumentLoc is difficult so we
+      // simply omit the ArgsAsWritten
+      /*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
+
+  if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
+    NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC,
+                                 BinaryOperatorKind::BO_LAnd,
+                                 SourceLocation(), /*RHS=*/nullptr,
+                                 SourceLocation(), /*NumExpansions=*/None);
+  return NewIDC;
+}
+
 TemplateTemplateParmDecl *
 ASTContext::getCanonicalTemplateTemplateParmDecl(
                                           TemplateTemplateParmDecl *TTP) const {
@@ -743,68 +798,23 @@
           TTP->isExpandedParameterPack() ?
           llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
       if (const auto *TC = TTP->getTypeConstraint()) {
-        // This is a bit ugly - we need to form a new immediately-declared
-        // constraint that references the new parameter; this would ideally
-        // require semantic analysis (e.g. template<C T> struct S {}; - the
-        // converted arguments of C<T> could be an argument pack if C is
-        // declared as template<typename... T> concept C = ...).
-        // We don't have semantic analysis here so we dig deep into the
-        // ready-made constraint expr and change the thing manually.
-        Expr *IDC = TC->getImmediatelyDeclaredConstraint();
-        ConceptSpecializationExpr *CSE;
-        if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
-          CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
-        else
-          CSE = cast<ConceptSpecializationExpr>(IDC);
-        ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
-        SmallVector<TemplateArgument, 3> NewConverted;
-        NewConverted.reserve(OldConverted.size());
-
         QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0);
-        if (OldConverted.front().getKind() == TemplateArgument::Pack) {
-          // The case:
-          // template<typename... T> concept C = true;
-          // template<C<int> T> struct S; -> constraint is C<{T, int}>
-          NewConverted.push_back(ParamAsArgument);
-          for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
-            NewConverted.push_back(Arg);
-          TemplateArgument NewPack(NewConverted);
-
-          NewConverted.clear();
-          NewConverted.push_back(NewPack);
-          assert(OldConverted.size() == 1 &&
-                 "Template parameter pack should be the last parameter");
-        } else {
-          assert(OldConverted.front().getKind() == TemplateArgument::Type &&
-                 "Unexpected first argument kind for immediately-declared "
-                 "constraint");
-          NewConverted.push_back(ParamAsArgument);
-          for (auto &Arg : OldConverted.drop_front(1))
-            NewConverted.push_back(Arg);
-        }
-        Expr *NewIDC = ConceptSpecializationExpr::Create(*this,
-            NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
-            CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
-            CSE->getNamedConcept(),
-            // Actually canonicalizing a TemplateArgumentLoc is difficult so we
-            // simply omit the ArgsAsWritten
-            /*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
-
-        if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
-          NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(),
-                                           SourceLocation(), NewIDC,
-                                           BinaryOperatorKind::BO_LAnd,
-                                           SourceLocation(), /*RHS=*/nullptr,
-                                           SourceLocation(),
-                                           /*NumExpansions=*/None);
-
+        Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint(
+                *this, TC->getImmediatelyDeclaredConstraint(),
+                ParamAsArgument);
+        TemplateArgumentListInfo CanonArgsAsWritten;
+        if (auto *Args = TC->getTemplateArgsAsWritten())
+          for (const auto &ArgLoc : Args->arguments())
+            CanonArgsAsWritten.addArgument(
+                TemplateArgumentLoc(ArgLoc.getArgument(),
+                                    TemplateArgumentLocInfo()));
         NewTTP->setTypeConstraint(
             NestedNameSpecifierLoc(),
             DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),
                                 SourceLocation()), /*FoundDecl=*/nullptr,
             // Actually canonicalizing a TemplateArgumentLoc is difficult so we
             // simply omit the ArgsAsWritten
-            CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
+            TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
       }
       CanonParams.push_back(NewTTP);
     } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
@@ -839,6 +849,13 @@
                                                 NTTP->isParameterPack(),
                                                 TInfo);
       }
+      if (AutoType *AT = T->getContainedAutoType()) {
+        if (AT->isConstrained()) {
+          Param->setPlaceholderTypeConstraint(
+              canonicalizeImmediatelyDeclaredConstraint(
+                  *this, NTTP->getPlaceholderTypeConstraint(), T));
+        }
+      }
       CanonParams.push_back(Param);
 
     } else
@@ -943,7 +960,7 @@
                        Builtin::Context &builtins)
     : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
       TemplateSpecializationTypes(this_()),
-      DependentTemplateSpecializationTypes(this_()),
+      DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),
       SubstTemplateTemplateParmPacks(this_()),
       CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
       SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
@@ -5124,21 +5141,29 @@
 /// getAutoType - Return the uniqued reference to the 'auto' type which has been
 /// deduced to the given type, or to the canonical undeduced 'auto' type, or the
 /// canonical deduced-but-dependent 'auto' type.
-QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
-                                 bool IsDependent, bool IsPack) const {
+QualType
+ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
+                        bool IsDependent, bool IsPack,
+                        ConceptDecl *TypeConstraintConcept,
+                        ArrayRef<TemplateArgument> TypeConstraintArgs) const {
   assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
-  if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent)
+  if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
+      !TypeConstraintConcept && !IsDependent)
     return getAutoDeductType();
 
   // Look in the folding set for an existing type.
   void *InsertPos = nullptr;
   llvm::FoldingSetNodeID ID;
-  AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack);
+  AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent,
+                    TypeConstraintConcept, TypeConstraintArgs);
   if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
     return QualType(AT, 0);
 
-  auto *AT = new (*this, TypeAlignment)
-      AutoType(DeducedType, Keyword, IsDependent, IsPack);
+  void *Mem = Allocate(sizeof(AutoType) +
+                       sizeof(TemplateArgument) * TypeConstraintArgs.size(),
+                       TypeAlignment);
+  auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack,
+                                TypeConstraintConcept, TypeConstraintArgs);
   Types.push_back(AT);
   if (InsertPos)
     AutoTypes.InsertNode(AT, InsertPos);
@@ -5200,7 +5225,8 @@
   if (AutoDeductTy.isNull())
     AutoDeductTy = QualType(
       new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
-                                          /*dependent*/false, /*pack*/false),
+                                          /*dependent*/false, /*pack*/false,
+                                          /*concept*/nullptr, /*args*/{}),
       0);
   return AutoDeductTy;
 }
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index b67d101..9dd20e2 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1366,9 +1366,21 @@
   if (!ToDeducedTypeOrErr)
     return ToDeducedTypeOrErr.takeError();
 
-  return Importer.getToContext().getAutoType(*ToDeducedTypeOrErr,
-                                             T->getKeyword(),
-                                             /*IsDependent*/false);
+  ExpectedDecl ToTypeConstraintConcept = import(T->getTypeConstraintConcept());
+  if (!ToTypeConstraintConcept)
+    return ToTypeConstraintConcept.takeError();
+
+  SmallVector<TemplateArgument, 2> ToTemplateArgs;
+  ArrayRef<TemplateArgument> FromTemplateArgs = T->getTypeConstraintArguments();
+  if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(),
+                                          FromTemplateArgs.size(),
+                                          ToTemplateArgs))
+    return std::move(Err);
+
+  return Importer.getToContext().getAutoType(
+      *ToDeducedTypeOrErr, T->getKeyword(), /*IsDependent*/false,
+      /*IsPack=*/false, cast_or_null<ConceptDecl>(*ToTypeConstraintConcept),
+      ToTemplateArgs);
 }
 
 ExpectedType ASTNodeImporter::VisitInjectedClassNameType(
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index db48405..91a2f3a 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -729,11 +729,31 @@
       return false;
     break;
 
-  case Type::Auto:
-    if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(),
-                                  cast<AutoType>(T2)->getDeducedType()))
+  case Type::Auto: {
+    auto *Auto1 = cast<AutoType>(T1);
+    auto *Auto2 = cast<AutoType>(T2);
+    if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),
+                                  Auto2->getDeducedType()))
       return false;
+    if (Auto1->isConstrained() != Auto2->isConstrained())
+      return false;
+    if (Auto1->isConstrained()) {
+      if (Auto1->getTypeConstraintConcept() !=
+          Auto2->getTypeConstraintConcept())
+        return false;
+      ArrayRef<TemplateArgument> Auto1Args =
+          Auto1->getTypeConstraintArguments();
+      ArrayRef<TemplateArgument> Auto2Args =
+          Auto2->getTypeConstraintArguments();
+      if (Auto1Args.size() != Auto2Args.size())
+        return false;
+      for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
+        if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
+          return false;
+      }
+    }
     break;
+  }
 
   case Type::DeducedTemplateSpecialization: {
     const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 58ce49a..9bd3b64 100755
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -164,10 +164,15 @@
 void TemplateParameterList::
 getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
   if (HasConstrainedParameters)
-    for (const NamedDecl *Param : *this)
-      if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+    for (const NamedDecl *Param : *this) {
+      if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
         if (const auto *TC = TTP->getTypeConstraint())
           AC.push_back(TC->getImmediatelyDeclaredConstraint());
+      } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+        if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
+          AC.push_back(E);
+      }
+    }
   if (HasRequiresClause)
     AC.push_back(getRequiresClause());
 }
@@ -687,8 +692,14 @@
                                 unsigned D, unsigned P, IdentifierInfo *Id,
                                 QualType T, bool ParameterPack,
                                 TypeSourceInfo *TInfo) {
-  return new (C, DC) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
-                                             T, ParameterPack, TInfo);
+  AutoType *AT =
+      C.getLangOpts().ConceptsTS ? T->getContainedAutoType() : nullptr;
+  return new (C, DC,
+              additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+                                    Expr *>(0,
+                                            AT && AT->isConstrained() ? 1 : 0))
+      NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack,
+                              TInfo);
 }
 
 NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
@@ -696,26 +707,34 @@
     SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
     QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
     ArrayRef<TypeSourceInfo *> ExpandedTInfos) {
+  AutoType *AT = TInfo->getType()->getContainedAutoType();
   return new (C, DC,
-              additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
-                  ExpandedTypes.size()))
+              additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+                                    Expr *>(
+                  ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0))
       NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo,
                               ExpandedTypes, ExpandedTInfos);
 }
 
 NonTypeTemplateParmDecl *
-NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
-  return new (C, ID) NonTypeTemplateParmDecl(nullptr, SourceLocation(),
-                                             SourceLocation(), 0, 0, nullptr,
-                                             QualType(), false, nullptr);
+NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+                                            bool HasTypeConstraint) {
+  return new (C, ID, additionalSizeToAlloc<std::pair<QualType,
+                                                     TypeSourceInfo *>,
+                                           Expr *>(0,
+                                                   HasTypeConstraint ? 1 : 0))
+          NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
+                                  0, 0, nullptr, QualType(), false, nullptr);
 }
 
 NonTypeTemplateParmDecl *
 NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
-                                            unsigned NumExpandedTypes) {
+                                            unsigned NumExpandedTypes,
+                                            bool HasTypeConstraint) {
   auto *NTTP =
-      new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
-                      NumExpandedTypes))
+      new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+                                        Expr *>(
+                      NumExpandedTypes, HasTypeConstraint ? 1 : 0))
           NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
                                   0, 0, nullptr, QualType(), nullptr, None,
                                   None);
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 27fdca1..1f9ff9e 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -857,6 +857,13 @@
 
   void VisitAutoType(const AutoType *T) {
     ID.AddInteger((unsigned)T->getKeyword());
+    ID.AddInteger(T->isConstrained());
+    if (T->isConstrained()) {
+      AddDecl(T->getTypeConstraintConcept());
+      ID.AddInteger(T->getNumArgs());
+      for (const auto &TA : T->getTypeConstraintArguments())
+        Hash.AddTemplateArgument(TA);
+    }
     VisitDeducedType(T);
   }
 
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index db16c2a..6f0ebf2 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -561,7 +561,7 @@
 }
 
 const ASTTemplateArgumentListInfo *
-ASTTemplateArgumentListInfo::Create(ASTContext &C,
+ASTTemplateArgumentListInfo::Create(const ASTContext &C,
                                     const TemplateArgumentListInfo &List) {
   std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size());
   void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo));
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 965ad17..c9b5718 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1201,6 +1201,11 @@
     OS << " decltype(auto)";
   if (!T->isDeduced())
     OS << " undeduced";
+  if (T->isConstrained()) {
+    dumpDeclRef(T->getTypeConstraintConcept());
+    for (const auto &Arg : T->getTypeConstraintArguments())
+      VisitTemplateArgument(Arg);
+  }
 }
 
 void TextNodeDumper::VisitTemplateSpecializationType(
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index c5ad711..5099494 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1114,7 +1114,9 @@
       return QualType(T, 0);
 
     return Ctx.getAutoType(deducedType, T->getKeyword(),
-                           T->isDependentType());
+                           T->isDependentType(), /*IsPack=*/false,
+                           T->getTypeConstraintConcept(),
+                           T->getTypeConstraintArguments());
   }
 
   // FIXME: Non-trivial to implement, but important for C++
@@ -4158,3 +4160,35 @@
                              /*HasUnsignedPadding=*/false);
   APFixedPoint(Val, FXSema).toString(Str);
 }
+
+AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
+                   bool IsDeducedAsDependent, bool IsDeducedAsPack,
+                   ConceptDecl *TypeConstraintConcept,
+                   ArrayRef<TemplateArgument> TypeConstraintArgs)
+    : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
+                  IsDeducedAsDependent, IsDeducedAsPack) {
+  AutoTypeBits.Keyword = (unsigned)Keyword;
+  AutoTypeBits.NumArgs = TypeConstraintArgs.size();
+  this->TypeConstraintConcept = TypeConstraintConcept;
+  if (TypeConstraintConcept) {
+    TemplateArgument *ArgBuffer = getArgBuffer();
+    for (const TemplateArgument &Arg : TypeConstraintArgs) {
+      if (Arg.containsUnexpandedParameterPack())
+        setContainsUnexpandedParameterPack();
+
+      new (ArgBuffer++) TemplateArgument(Arg);
+    }
+  }
+}
+
+void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+                      QualType Deduced, AutoTypeKeyword Keyword,
+                      bool IsDependent, ConceptDecl *CD,
+                      ArrayRef<TemplateArgument> Arguments) {
+  ID.AddPointer(Deduced.getAsOpaquePtr());
+  ID.AddInteger((unsigned)Keyword);
+  ID.AddBoolean(IsDependent);
+  ID.AddPointer(CD);
+  for (const TemplateArgument &Arg : Arguments)
+    Arg.Profile(ID, Context);
+}
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index 6e67ca8..665a86f 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/AST/TypeLoc.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Expr.h"
@@ -589,3 +590,97 @@
     }
   }
 }
+
+DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const {
+  return DeclarationNameInfo(getNamedConcept()->getDeclName(),
+                             getLocalData()->ConceptNameLoc);
+}
+
+void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
+  setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
+  setTemplateKWLoc(Loc);
+  setConceptNameLoc(Loc);
+  setFoundDecl(nullptr);
+  setRAngleLoc(Loc);
+  setLAngleLoc(Loc);
+  TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
+                                                   getTypePtr()->getArgs(),
+                                                   getArgInfos(), Loc);
+  setNameLoc(Loc);
+}
+
+
+namespace {
+
+  class GetContainedAutoTypeLocVisitor :
+    public TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc> {
+  public:
+    using TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc>::Visit;
+
+    TypeLoc VisitAutoTypeLoc(AutoTypeLoc TL) {
+      return TL;
+    }
+
+    // Only these types can contain the desired 'auto' type.
+
+    TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) {
+      return Visit(T.getNamedTypeLoc());
+    }
+
+    TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) {
+      return Visit(T.getUnqualifiedLoc());
+    }
+
+    TypeLoc VisitPointerTypeLoc(PointerTypeLoc T) {
+      return Visit(T.getPointeeLoc());
+    }
+
+    TypeLoc VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) {
+      return Visit(T.getPointeeLoc());
+    }
+
+    TypeLoc VisitReferenceTypeLoc(ReferenceTypeLoc T) {
+      return Visit(T.getPointeeLoc());
+    }
+
+    TypeLoc VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) {
+      return Visit(T.getPointeeLoc());
+    }
+
+    TypeLoc VisitArrayTypeLoc(ArrayTypeLoc T) {
+      return Visit(T.getElementLoc());
+    }
+
+    TypeLoc VisitFunctionTypeLoc(FunctionTypeLoc T) {
+      return Visit(T.getReturnLoc());
+    }
+
+    TypeLoc VisitParenTypeLoc(ParenTypeLoc T) {
+      return Visit(T.getInnerLoc());
+    }
+
+    TypeLoc VisitAttributedTypeLoc(AttributedTypeLoc T) {
+      return Visit(T.getModifiedLoc());
+    }
+
+    TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) {
+      return Visit(T.getInnerLoc());
+    }
+
+    TypeLoc VisitAdjustedTypeLoc(AdjustedTypeLoc T) {
+      return Visit(T.getOriginalLoc());
+    }
+
+    TypeLoc VisitPackExpansionTypeLoc(PackExpansionTypeLoc T) {
+      return Visit(T.getPatternLoc());
+    }
+  };
+
+} // namespace
+
+AutoTypeLoc TypeLoc::getContainedAutoTypeLoc() const {
+  TypeLoc Res = GetContainedAutoTypeLocVisitor().Visit(*this);
+  if (Res.isNull())
+    return AutoTypeLoc();
+  return Res.getAs<AutoTypeLoc>();
+}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 3a00a6c..1495162 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1046,6 +1046,13 @@
   if (!T->getDeducedType().isNull()) {
     printBefore(T->getDeducedType(), OS);
   } else {
+    if (T->isConstrained()) {
+      OS << T->getTypeConstraintConcept()->getName();
+      auto Args = T->getTypeConstraintArguments();
+      if (!Args.empty())
+        printTemplateArgumentList(OS, Args, Policy);
+      OS << ' ';
+    }
     switch (T->getKeyword()) {
     case AutoTypeKeyword::Auto: OS << "auto"; break;
     case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break;
@@ -1234,20 +1241,18 @@
 
 void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
                                               raw_ostream &OS) {
-  if (IdentifierInfo *Id = T->getIdentifier())
-    OS << Id->getName();
-  else {
-    bool IsLambdaAutoParam = false;
-    if (auto D = T->getDecl()) {
-      if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
-        IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
+  TemplateTypeParmDecl *D = T->getDecl();
+  if (D && D->isImplicit()) {
+    if (auto *TC = D->getTypeConstraint()) {
+      TC->print(OS, Policy);
+      OS << ' ';
     }
+    OS << "auto";
+  } else if (IdentifierInfo *Id = T->getIdentifier())
+    OS << Id->getName();
+  else
+    OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
 
-    if (IsLambdaAutoParam)
-      OS << "auto";
-    else
-      OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
-  }
   spaceBeforePlaceHolder(OS);
 }