[libcxx-commits] [libcxx] 6438a52 - Revert "[clang] retain type sugar in auto / template argument deduction"

Matheus Izvekov via libcxx-commits libcxx-commits at lists.llvm.org
Sun Nov 14 15:30:01 PST 2021


Author: Matheus Izvekov
Date: 2021-11-15T00:29:05+01:00
New Revision: 6438a52df1c7f36952b6126ff7b978861b76ad45

URL: https://github.com/llvm/llvm-project/commit/6438a52df1c7f36952b6126ff7b978861b76ad45
DIFF: https://github.com/llvm/llvm-project/commit/6438a52df1c7f36952b6126ff7b978861b76ad45.diff

LOG: Revert "[clang] retain type sugar in auto / template argument deduction"

This reverts commit 4d8fff477e024698facd89741cc6cf996708d598.

Added: 
    libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp
    libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp

Modified: 
    clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
    clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
    clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
    clang-tools-extra/clangd/FindTarget.cpp
    clang-tools-extra/clangd/InlayHints.cpp
    clang-tools-extra/clangd/unittests/ASTTests.cpp
    clang-tools-extra/clangd/unittests/HoverTests.cpp
    clang-tools-extra/clangd/unittests/InlayHintTests.cpp
    clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
    clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
    clang/include/clang/AST/ASTContext.h
    clang/include/clang/AST/Type.h
    clang/include/clang/ASTMatchers/ASTMatchersInternal.h
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/ASTImporter.cpp
    clang/lib/AST/Type.cpp
    clang/lib/Sema/SemaCXXScopeSpec.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaExprCXX.cpp
    clang/lib/Sema/SemaInit.cpp
    clang/lib/Sema/SemaLambda.cpp
    clang/lib/Sema/SemaStmt.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/lib/Sema/SemaType.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
    clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
    clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
    clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
    clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
    clang/test/Index/print-type.cpp
    clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
    clang/test/SemaCXX/cxx1z-decomposition.cpp
    clang/test/SemaCXX/deduced-return-type-cxx14.cpp
    clang/test/SemaCXX/friend.cpp
    clang/test/SemaCXX/recovery-expr-type.cpp
    clang/test/SemaCXX/sizeless-1.cpp
    clang/test/SemaTemplate/attributes.cpp
    clang/test/SemaTemplate/friend.cpp
    clang/test/SemaTemplate/operator-template.cpp
    lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp

Removed: 
    clang/test/SemaCXX/sugared-auto.cpp
    libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.verify.cpp
    libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.verify.cpp


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
index b87c33dd10bda..13bb7246fd43a 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
@@ -134,9 +134,14 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
   // Matching on initialization operations where the initial value is a newly
   // created owner, but the LHS is not an owner.
   Finder->addMatcher(
-      traverse(TK_AsIs, namedDecl(varDecl(allOf(hasInitializer(CreatesOwner),
-                                                unless(IsOwnerType)))
-                                      .bind("bad_owner_creation_variable"))),
+      traverse(
+          TK_AsIs,
+          namedDecl(
+              varDecl(eachOf(allOf(hasInitializer(CreatesOwner),
+                                   unless(IsOwnerType)),
+                             allOf(hasInitializer(ConsideredOwner),
+                                   hasType(autoType().bind("deduced_type")))))
+                  .bind("bad_owner_creation_variable"))),
       this);
 
   // Match on all function calls that expect owners as arguments, but didn't
@@ -319,6 +324,13 @@ bool OwningMemoryCheck::handleAssignmentFromNewOwner(const BoundNodes &Nodes) {
 
     // FIXME: FixitHint to rewrite the type of the initialized variable
     // as 'gsl::owner<OriginalType>'
+
+    // If the type of the variable was deduced, the wrapping owner typedef is
+    // eliminated, therefore the check emits a special note for that case.
+    if (Nodes.getNodeAs<AutoType>("deduced_type")) {
+      diag(BadOwnerInitialization->getBeginLoc(),
+           "type deduction did not result in an owner", DiagnosticIDs::Note);
+    }
     return true;
   }
 

diff  --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
index 5b88da658f082..680b337874460 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
@@ -20,11 +20,9 @@ void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) {
   if (!getLangOpts().CPlusPlus)
     return;
 
-  const auto AllPointerTypes =
-      anyOf(hasType(pointerType()),
-            hasType(autoType(
-                hasDeducedType(hasUnqualifiedDesugaredType(pointerType())))),
-            hasType(decltypeType(hasUnderlyingType(pointerType()))));
+  const auto AllPointerTypes = anyOf(
+      hasType(pointerType()), hasType(autoType(hasDeducedType(pointerType()))),
+      hasType(decltypeType(hasUnderlyingType(pointerType()))));
 
   // Flag all operators +, -, +=, -=, ++, -- that result in a pointer
   Finder->addMatcher(

diff  --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
index c564b5adcbbf8..95380069f5274 100644
--- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
@@ -125,22 +125,18 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) {
       };
 
   auto IsBoundToType = refersToType(equalsBoundNode("type"));
-  auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType()));
-  auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) {
-    return autoType(hasDeducedType(
-        hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...)))));
-  };
 
   Finder->addMatcher(
-      ExplicitSingleVarDecl(hasType(IsAutoDeducedToPointer(UnlessFunctionType)),
+      ExplicitSingleVarDecl(hasType(autoType(hasDeducedType(
+                                pointerType(pointee(unless(functionType())))))),
                             "auto"),
       this);
 
   Finder->addMatcher(
       ExplicitSingleVarDeclInTemplate(
-          allOf(hasType(IsAutoDeducedToPointer(
-                    hasUnqualifiedType(qualType().bind("type")),
-                    UnlessFunctionType)),
+          allOf(hasType(autoType(hasDeducedType(pointerType(
+                    pointee(hasUnqualifiedType(qualType().bind("type")),
+                            unless(functionType())))))),
                 anyOf(hasAncestor(
                           functionDecl(hasAnyTemplateArgument(IsBoundToType))),
                       hasAncestor(classTemplateSpecializationDecl(

diff  --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index 70e1d423f5422..82e4dfeccf43d 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -374,7 +374,7 @@ struct TargetFinder {
       void VisitDeducedType(const DeducedType *DT) {
         // FIXME: In practice this doesn't work: the AutoType you find inside
         // TypeLoc never has a deduced type. https://llvm.org/PR42914
-        Outer.add(DT->getDeducedType(), Flags);
+        Outer.add(DT->getDeducedType(), Flags | Rel::Underlying);
       }
       void VisitDeducedTemplateSpecializationType(
           const DeducedTemplateSpecializationType *DTST) {

diff  --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 6b9c8b1eee54f..73864b7849345 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -38,9 +38,10 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
     // For structured bindings, print canonical types. This is important because
     // for bindings that use the tuple_element protocol, the non-canonical types
     // would be "tuple_element<I, A>::type".
-    // For "auto", we often prefer sugared types.
-    // Not setting PrintCanonicalTypes for "auto" allows
-    // SuppressDefaultTemplateArgs (set by default) to have an effect.
+    // For "auto", we often prefer sugared types, but the AST doesn't currently
+    // retain them in DeducedType. However, not setting PrintCanonicalTypes for
+    // "auto" at least allows SuppressDefaultTemplateArgs (set by default) to
+    // have an effect.
     StructuredBindingPolicy = TypeHintPolicy;
     StructuredBindingPolicy.PrintCanonicalTypes = true;
   }

diff  --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp
index 44dc8f0c69cf5..df42a28d5ebe2 100644
--- a/clang-tools-extra/clangd/unittests/ASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp
@@ -43,7 +43,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
               namespace ns1 { struct S {}; }
               ^auto v = ns1::S{};
           )cpp",
-          "ns1::S",
+          "struct ns1::S",
       },
       {
           R"cpp( // decltype on struct
@@ -63,7 +63,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
             ns1::S& j = i;
             ^decltype(auto) k = j;
           )cpp",
-          "ns1::S &",
+          "struct ns1::S &",
       },
       {
           R"cpp( // auto on template class
@@ -71,7 +71,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
               template<typename T> class Foo {};
               ^auto v = Foo<X>();
           )cpp",
-          "Foo<class X>",
+          "class Foo<class X>",
       },
       {
           R"cpp( // auto on initializer list.
@@ -177,7 +177,8 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
             using Bar = Foo;
             ^auto x = Bar();
           )cpp",
-          "Bar",
+          // FIXME: it'd be nice if this resolved to the alias instead
+          "struct Foo",
       },
   };
   for (Test T : Tests) {

diff  --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 79510ceefa1b3..53df965fef2fa 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -461,7 +461,7 @@ class Foo {})cpp";
        [](HoverInfo &HI) {
          HI.Name = "auto";
          HI.Kind = index::SymbolKind::TypeAlias;
-         HI.Definition = "Foo<int>";
+         HI.Definition = "class Foo<int>";
        }},
       // auto on specialized template
       {R"cpp(
@@ -474,7 +474,7 @@ class Foo {})cpp";
        [](HoverInfo &HI) {
          HI.Name = "auto";
          HI.Kind = index::SymbolKind::TypeAlias;
-         HI.Definition = "Foo<int>";
+         HI.Definition = "class Foo<int>";
        }},
 
       // macro
@@ -648,7 +648,7 @@ class Foo {})cpp";
           [](HoverInfo &HI) {
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
-            HI.Definition = "Foo<X>";
+            HI.Definition = "class Foo<X>";
           }},
       {// Falls back to primary template, when the type is not instantiated.
        R"cpp(
@@ -2024,7 +2024,7 @@ TEST(Hover, All) {
           [](HoverInfo &HI) {
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
-            HI.Definition = "int_type";
+            HI.Definition = "int";
           }},
       {
           R"cpp(// auto on alias
@@ -2035,7 +2035,7 @@ TEST(Hover, All) {
           [](HoverInfo &HI) {
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
-            HI.Definition = "cls_type";
+            HI.Definition = "struct cls";
             HI.Documentation = "auto on alias";
           }},
       {
@@ -2047,7 +2047,7 @@ TEST(Hover, All) {
           [](HoverInfo &HI) {
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
-            HI.Definition = "templ<int>";
+            HI.Definition = "struct templ<int>";
             HI.Documentation = "auto on alias";
           }},
       {

diff  --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index b6c6dd17dbe3b..1c69d504ec6dc 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -466,14 +466,7 @@ TEST(TypeHints, NoQualifiers) {
       }
     }
   )cpp",
-                  ExpectedHint{": S1", "x"},
-                  // FIXME: We want to suppress scope specifiers
-                  //        here because we are into the whole
-                  //        brevity thing, but the ElaboratedType
-                  //        printer does not honor the SuppressScope
-                  //        flag by design, so we need to extend the
-                  //        PrintingPolicy to support this use case.
-                  ExpectedHint{": S2::Inner<int>", "y"});
+                  ExpectedHint{": S1", "x"}, ExpectedHint{": Inner<int>", "y"});
 }
 
 TEST(TypeHints, Lambda) {

diff  --git a/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
index 96574a67b5a46..1b784f63f59cf 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
@@ -57,7 +57,7 @@ TEST_F(ExpandAutoTypeTest, Test) {
   EXPECT_UNAVAILABLE("au^to x = []{};");
   // inline namespaces
   EXPECT_EQ(apply("au^to x = inl_ns::Visible();"),
-            "inl_ns::Visible x = inl_ns::Visible();");
+            "Visible x = inl_ns::Visible();");
   // local class
   EXPECT_EQ(apply("namespace x { void y() { struct S{}; ^auto z = S(); } }"),
             "namespace x { void y() { struct S{}; S z = S(); } }");
@@ -67,9 +67,8 @@ TEST_F(ExpandAutoTypeTest, Test) {
 
   EXPECT_EQ(apply("ns::Class * foo() { au^to c = foo(); }"),
             "ns::Class * foo() { ns::Class * c = foo(); }");
-  EXPECT_EQ(
-      apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"),
-      "void ns::Func() { ns::Class::Nested * x = new ns::Class::Nested{}; }");
+  EXPECT_EQ(apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"),
+            "void ns::Func() { Class::Nested * x = new ns::Class::Nested{}; }");
 
   EXPECT_UNAVAILABLE("dec^ltype(au^to) x = 10;");
   // expanding types in structured bindings is syntactically invalid.

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
index 6bf5af82d6556..72b13801cf1eb 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
@@ -91,9 +91,13 @@ void test_assignment_and_initialization() {
   // FIXME:, flow analysis for the case of reassignment. Value must be released before
   owned_int6 = owned_int3; // BAD, because reassignment without resource release
 
-  auto owned_int7 = returns_owner1(); // Ok, since type deduction does not eliminate the owner wrapper
+  auto owned_int7 = returns_owner1(); // Bad, since type deduction eliminates the owner wrapper
+  // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+  // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
 
-  const auto owned_int8 = returns_owner2(); // Ok, since type deduction does not eliminate the owner wrapper
+  const auto owned_int8 = returns_owner2(); // Bad, since type deduction eliminates the owner wrapper
+  // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *const' with a newly created 'gsl::owner<>'
+  // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
 
   gsl::owner<int *> owned_int9 = returns_owner1(); // Ok
   int *unowned_int3 = returns_owner1();            // Bad
@@ -281,12 +285,15 @@ void test_class_with_owner() {
   ClassWithOwner C2{A};                                                // Bad, since the owner would be initialized with an non-owner, but catched in the class
   ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok
 
-  const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner<ArbitraryClass *> const
+  const auto Owner1 = C3.buggy_but_returns_owner(); // BAD, deduces Owner1 to ArbitraryClass *const
+  // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *const' with a newly created 'gsl::owner<>'
+  // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
 
-  auto Owner2 = C2.buggy_but_returns_owner(); //Ok, deduces Owner2 to owner<ArbitraryClass *>
+  auto Owner2 = C2.buggy_but_returns_owner(); // BAD, deduces Owner2 to ArbitraryClass *
+  // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *' with a newly created 'gsl::owner<>'
+  // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
 
-  Owner2 = &A; // BAD, since type deduction resulted in owner<ArbitraryClass *>
-  // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
+  Owner2 = &A; // Ok, since type deduction did NOT result in owner<int*>
 
   gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner
   Owner3 = &A;                                                        // Bad, since assignment of non-owner to owner

diff  --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index d336342e4cda6..b9aa2d2cfadb5 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1531,12 +1531,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
   QualType getFunctionTypeInternal(QualType ResultTy, ArrayRef<QualType> Args,
                                    const FunctionProtoType::ExtProtoInfo &EPI,
                                    bool OnlyWantCanonical) const;
-  QualType
-  getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword,
-                      bool IsDependent, bool IsPack = false,
-                      ConceptDecl *TypeConstraintConcept = nullptr,
-                      ArrayRef<TemplateArgument> TypeConstraintArgs = {},
-                      bool IsCanon = false) const;
 
 public:
   /// Return the unique reference to the type for the specified type

diff  --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index fd25ec25d4f21..722add6cd8777 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -4944,29 +4944,29 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
 /// type-dependent, there is no deduced type and the type is canonical. In
 /// the latter case, it is also a dependent type.
 class DeducedType : public Type {
-  QualType DeducedAsType;
-
 protected:
   DeducedType(TypeClass TC, QualType DeducedAsType,
-              TypeDependence ExtraDependence, QualType Canon)
-      : Type(TC, Canon,
+              TypeDependence ExtraDependence)
+      : Type(TC,
+             // FIXME: Retain the sugared deduced type?
+             DeducedAsType.isNull() ? QualType(this, 0)
+                                    : DeducedAsType.getCanonicalType(),
              ExtraDependence | (DeducedAsType.isNull()
                                     ? TypeDependence::None
                                     : DeducedAsType->getDependence() &
-                                          ~TypeDependence::VariablyModified)),
-        DeducedAsType(DeducedAsType) {}
+                                          ~TypeDependence::VariablyModified)) {}
 
 public:
-  bool isSugared() const { return !DeducedAsType.isNull(); }
-  QualType desugar() const {
-    return isSugared() ? DeducedAsType : QualType(this, 0);
-  }
+  bool isSugared() const { return !isCanonicalUnqualified(); }
+  QualType desugar() const { return getCanonicalTypeInternal(); }
 
-  /// Get the type deduced for this placeholder type, or null if it
-  /// has not been deduced.
-  QualType getDeducedType() const { return DeducedAsType; }
+  /// Get the type deduced for this placeholder type, or null if it's
+  /// either not been deduced or was deduced to a dependent type.
+  QualType getDeducedType() const {
+    return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType();
+  }
   bool isDeduced() const {
-    return !DeducedAsType.isNull() || isDependentType();
+    return !isCanonicalUnqualified() || isDependentType();
   }
 
   static bool classof(const Type *T) {
@@ -4983,7 +4983,7 @@ class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode {
   ConceptDecl *TypeConstraintConcept;
 
   AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
-           TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD,
+           TypeDependence ExtraDependence, ConceptDecl *CD,
            ArrayRef<TemplateArgument> TypeConstraintArgs);
 
   const TemplateArgument *getArgBuffer() const {
@@ -5057,9 +5057,7 @@ class DeducedTemplateSpecializationType : public DeducedType,
                     toTypeDependence(Template.getDependence()) |
                         (IsDeducedAsDependent
                              ? TypeDependence::DependentInstantiation
-                             : TypeDependence::None),
-                    DeducedAsType.isNull() ? QualType(this, 0)
-                                           : DeducedAsType.getCanonicalType()),
+                             : TypeDependence::None)),
         Template(Template) {}
 
 public:

diff  --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index a77611001fb14..f84582c06f780 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1027,29 +1027,31 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
                           BoundNodesTreeBuilder *Builder) const {
     // DeducedType does not have declarations of its own, so
     // match the deduced type instead.
+    const Type *EffectiveType = &Node;
     if (const auto *S = dyn_cast<DeducedType>(&Node)) {
-      QualType DT = S->getDeducedType();
-      return !DT.isNull() ? matchesSpecialized(*DT, Finder, Builder) : false;
+      EffectiveType = S->getDeducedType().getTypePtrOrNull();
+      if (!EffectiveType)
+        return false;
     }
 
     // First, for any types that have a declaration, extract the declaration and
     // match on it.
-    if (const auto *S = dyn_cast<TagType>(&Node)) {
+    if (const auto *S = dyn_cast<TagType>(EffectiveType)) {
       return matchesDecl(S->getDecl(), Finder, Builder);
     }
-    if (const auto *S = dyn_cast<InjectedClassNameType>(&Node)) {
+    if (const auto *S = dyn_cast<InjectedClassNameType>(EffectiveType)) {
       return matchesDecl(S->getDecl(), Finder, Builder);
     }
-    if (const auto *S = dyn_cast<TemplateTypeParmType>(&Node)) {
+    if (const auto *S = dyn_cast<TemplateTypeParmType>(EffectiveType)) {
       return matchesDecl(S->getDecl(), Finder, Builder);
     }
-    if (const auto *S = dyn_cast<TypedefType>(&Node)) {
+    if (const auto *S = dyn_cast<TypedefType>(EffectiveType)) {
       return matchesDecl(S->getDecl(), Finder, Builder);
     }
-    if (const auto *S = dyn_cast<UnresolvedUsingType>(&Node)) {
+    if (const auto *S = dyn_cast<UnresolvedUsingType>(EffectiveType)) {
       return matchesDecl(S->getDecl(), Finder, Builder);
     }
-    if (const auto *S = dyn_cast<ObjCObjectType>(&Node)) {
+    if (const auto *S = dyn_cast<ObjCObjectType>(EffectiveType)) {
       return matchesDecl(S->getInterface(), Finder, Builder);
     }
 
@@ -1061,14 +1063,14 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
     //   template<typename T> struct X { T t; } class A {}; X<A> a;
     // The following matcher will match, which otherwise would not:
     //   fieldDecl(hasType(pointerType())).
-    if (const auto *S = dyn_cast<SubstTemplateTypeParmType>(&Node)) {
+    if (const auto *S = dyn_cast<SubstTemplateTypeParmType>(EffectiveType)) {
       return matchesSpecialized(S->getReplacementType(), Finder, Builder);
     }
 
     // For template specialization types, we want to match the template
     // declaration, as long as the type is still dependent, and otherwise the
     // declaration of the instantiated tag type.
-    if (const auto *S = dyn_cast<TemplateSpecializationType>(&Node)) {
+    if (const auto *S = dyn_cast<TemplateSpecializationType>(EffectiveType)) {
       if (!S->isTypeAlias() && S->isSugared()) {
         // If the template is non-dependent, we want to match the instantiated
         // tag type.
@@ -1087,7 +1089,7 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
     // FIXME: We desugar elaborated types. This makes the assumption that users
     // do never want to match on whether a type is elaborated - there are
     // arguments for both sides; for now, continue desugaring.
-    if (const auto *S = dyn_cast<ElaboratedType>(&Node)) {
+    if (const auto *S = dyn_cast<ElaboratedType>(EffectiveType)) {
       return matchesSpecialized(S->desugar(), Finder, Builder);
     }
     return false;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5f5755ef13435..c7a6d04ce8f8c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2359,13 +2359,11 @@ class Sema final {
                              const CXXScopeSpec &SS, QualType T,
                              TagDecl *OwnedTagDecl = nullptr);
 
-  // Returns the underlying type of a decltype with the given expression.
-  QualType getDecltypeForExpr(Expr *E);
-
-  QualType BuildTypeofExprType(Expr *E);
+  QualType BuildTypeofExprType(Expr *E, SourceLocation Loc);
   /// If AsUnevaluated is false, E is treated as though it were an evaluated
   /// context, such as when building a type for decltype(auto).
-  QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true);
+  QualType BuildDecltypeType(Expr *E, SourceLocation Loc,
+                             bool AsUnevaluated = true);
   QualType BuildUnaryTransformType(QualType BaseType,
                                    UnaryTransformType::UTTKind UKind,
                                    SourceLocation Loc);
@@ -3504,7 +3502,7 @@ class Sema final {
   bool IsFunctionConversion(QualType FromType, QualType ToType,
                             QualType &ResultTy);
   bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
-  bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg);
+  bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg);
 
   bool CanPerformAggregateInitializationForOverloadResolution(
       const InitializedEntity &Entity, InitListExpr *From);
@@ -8567,14 +8565,6 @@ class Sema final {
   /// Substitute Replacement for auto in TypeWithAuto
   TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
                                           QualType Replacement);
-
-  // Substitute auto in TypeWithAuto for a Dependent auto type
-  QualType SubstAutoTypeDependent(QualType TypeWithAuto);
-
-  // Substitute auto in TypeWithAuto for a Dependent auto type
-  TypeSourceInfo *
-  SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto);
-
   /// Completely replace the \c auto in \p TypeWithAuto by
   /// \p Replacement. This does not retain any \c auto type sugar.
   QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement);

diff  --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index f0b931bdc9050..391a0c0b338e6 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4815,23 +4815,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
   return QualType(Spec, 0);
 }
 
-static bool
-getCanonicalTemplateArguments(const ASTContext &C,
-                              ArrayRef<TemplateArgument> OrigArgs,
-                              SmallVectorImpl<TemplateArgument> &CanonArgs) {
-  bool AnyNonCanonArgs = false;
-  unsigned NumArgs = OrigArgs.size();
-  CanonArgs.resize(NumArgs);
-  for (unsigned I = 0; I != NumArgs; ++I) {
-    const TemplateArgument &OrigArg = OrigArgs[I];
-    TemplateArgument &CanonArg = CanonArgs[I];
-    CanonArg = C.getCanonicalTemplateArgument(OrigArg);
-    if (!CanonArg.structurallyEquals(OrigArg))
-      AnyNonCanonArgs = true;
-  }
-  return AnyNonCanonArgs;
-}
-
 QualType ASTContext::getCanonicalTemplateSpecializationType(
     TemplateName Template, ArrayRef<TemplateArgument> Args) const {
   assert(!Template.getAsDependentTemplateName() &&
@@ -4844,7 +4827,10 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
   // Build the canonical template specialization type.
   TemplateName CanonTemplate = getCanonicalTemplateName(Template);
   SmallVector<TemplateArgument, 4> CanonArgs;
-  ::getCanonicalTemplateArguments(*this, Args, CanonArgs);
+  unsigned NumArgs = Args.size();
+  CanonArgs.reserve(NumArgs);
+  for (const TemplateArgument &Arg : Args)
+    CanonArgs.push_back(getCanonicalTemplateArgument(Arg));
 
   // Determine whether this canonical template specialization type already
   // exists.
@@ -4859,7 +4845,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
   if (!Spec) {
     // Allocate a new canonical template specialization type.
     void *Mem = Allocate((sizeof(TemplateSpecializationType) +
-                          sizeof(TemplateArgument) * CanonArgs.size()),
+                          sizeof(TemplateArgument) * NumArgs),
                          TypeAlignment);
     Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
                                                 CanonArgs,
@@ -5001,9 +4987,14 @@ ASTContext::getDependentTemplateSpecializationType(
   ElaboratedTypeKeyword CanonKeyword = Keyword;
   if (Keyword == ETK_None) CanonKeyword = ETK_Typename;
 
-  SmallVector<TemplateArgument, 16> CanonArgs;
-  bool AnyNonCanonArgs =
-      ::getCanonicalTemplateArguments(*this, Args, CanonArgs);
+  bool AnyNonCanonArgs = false;
+  unsigned NumArgs = Args.size();
+  SmallVector<TemplateArgument, 16> CanonArgs(NumArgs);
+  for (unsigned I = 0; I != NumArgs; ++I) {
+    CanonArgs[I] = getCanonicalTemplateArgument(Args[I]);
+    if (!CanonArgs[I].structurallyEquals(Args[I]))
+      AnyNonCanonArgs = true;
+  }
 
   QualType Canon;
   if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) {
@@ -5016,7 +5007,7 @@ ASTContext::getDependentTemplateSpecializationType(
   }
 
   void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) +
-                        sizeof(TemplateArgument) * Args.size()),
+                        sizeof(TemplateArgument) * NumArgs),
                        TypeAlignment);
   T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS,
                                                     Name, Args, Canon);
@@ -5598,10 +5589,15 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
   return QualType(ut, 0);
 }
 
-QualType ASTContext::getAutoTypeInternal(
-    QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent,
-    bool IsPack, ConceptDecl *TypeConstraintConcept,
-    ArrayRef<TemplateArgument> TypeConstraintArgs, bool IsCanon) const {
+/// 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,
+                        ConceptDecl *TypeConstraintConcept,
+                        ArrayRef<TemplateArgument> TypeConstraintArgs) const {
+  assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
   if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
       !TypeConstraintConcept && !IsDependent)
     return getAutoDeductType();
@@ -5614,52 +5610,21 @@ QualType ASTContext::getAutoTypeInternal(
   if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
     return QualType(AT, 0);
 
-  QualType Canon;
-  if (!IsCanon) {
-    if (DeducedType.isNull()) {
-      SmallVector<TemplateArgument, 4> CanonArgs;
-      bool AnyNonCanonArgs =
-          ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs);
-      if (AnyNonCanonArgs) {
-        Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
-                                    TypeConstraintConcept, CanonArgs, true);
-        // Find the insert position again.
-        AutoTypes.FindNodeOrInsertPos(ID, InsertPos);
-      }
-    } else {
-      Canon = DeducedType.getCanonicalType();
-    }
-  }
-
   void *Mem = Allocate(sizeof(AutoType) +
-                           sizeof(TemplateArgument) * TypeConstraintArgs.size(),
+                       sizeof(TemplateArgument) * TypeConstraintArgs.size(),
                        TypeAlignment);
   auto *AT = new (Mem) AutoType(
       DeducedType, Keyword,
       (IsDependent ? TypeDependence::DependentInstantiation
                    : TypeDependence::None) |
           (IsPack ? TypeDependence::UnexpandedPack : TypeDependence::None),
-      Canon, TypeConstraintConcept, TypeConstraintArgs);
+      TypeConstraintConcept, TypeConstraintArgs);
   Types.push_back(AT);
-  AutoTypes.InsertNode(AT, InsertPos);
+  if (InsertPos)
+    AutoTypes.InsertNode(AT, InsertPos);
   return QualType(AT, 0);
 }
 
-/// 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,
-                        ConceptDecl *TypeConstraintConcept,
-                        ArrayRef<TemplateArgument> TypeConstraintArgs) const {
-  assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
-  assert((!IsDependent || DeducedType.isNull()) &&
-         "A dependent auto should be undeduced");
-  return getAutoTypeInternal(DeducedType, Keyword, IsDependent, IsPack,
-                             TypeConstraintConcept, TypeConstraintArgs);
-}
-
 /// Return the uniqued reference to the deduced template specialization type
 /// which has been deduced to the given type, or to the canonical undeduced
 /// such type, or the canonical deduced-but-dependent such type.
@@ -5677,7 +5642,8 @@ QualType ASTContext::getDeducedTemplateSpecializationType(
   auto *DTST = new (*this, TypeAlignment)
       DeducedTemplateSpecializationType(Template, DeducedType, IsDependent);
   Types.push_back(DTST);
-  DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos);
+  if (InsertPos)
+    DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos);
   return QualType(DTST, 0);
 }
 
@@ -5714,7 +5680,7 @@ QualType ASTContext::getAutoDeductType() const {
   if (AutoDeductTy.isNull())
     AutoDeductTy = QualType(new (*this, TypeAlignment)
                                 AutoType(QualType(), AutoTypeKeyword::Auto,
-                                         TypeDependence::None, QualType(),
+                                         TypeDependence::None,
                                          /*concept*/ nullptr, /*args*/ {}),
                             0);
   return AutoDeductTy;

diff  --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 710e40bbb4b72..8062b4fcab532 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3172,14 +3172,13 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
 
 bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
   QualType FromTy = D->getType();
-  const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
+  const FunctionProtoType *FromFPT = FromTy->getAs<FunctionProtoType>();
   assert(FromFPT && "Must be called on FunctionProtoType");
-  if (const AutoType *AutoT =
-          FromFPT->getReturnType()->getContainedAutoType()) {
+  if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) {
     QualType DeducedT = AutoT->getDeducedType();
-    if (const auto *RecordT =
-            !DeducedT.isNull() ? DeducedT->getAs<RecordType>() : nullptr) {
-      const RecordDecl *RD = RecordT->getDecl();
+    if (const RecordType *RecordT =
+            DeducedT.isNull() ? nullptr : dyn_cast<RecordType>(DeducedT)) {
+      RecordDecl *RD = RecordT->getDecl();
       assert(RD);
       if (isAncestorDeclContextOf(D, RD)) {
         assert(RD->getLexicalDeclContext() == RD->getDeclContext());
@@ -3187,8 +3186,9 @@ bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
       }
     }
   }
-  if (const auto *TypedefT = FromFPT->getReturnType()->getAs<TypedefType>()) {
-    const TypedefNameDecl *TD = TypedefT->getDecl();
+  if (const TypedefType *TypedefT =
+          dyn_cast<TypedefType>(FromFPT->getReturnType())) {
+    TypedefNameDecl *TD = TypedefT->getDecl();
     assert(TD);
     if (isAncestorDeclContextOf(D, TD)) {
       assert(TD->getLexicalDeclContext() == TD->getDeclContext());

diff  --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index e0ac3f5b1351d..a48df089ea86f 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4400,10 +4400,10 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
 }
 
 AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
-                   TypeDependence ExtraDependence, QualType Canon,
+                   TypeDependence ExtraDependence,
                    ConceptDecl *TypeConstraintConcept,
                    ArrayRef<TemplateArgument> TypeConstraintArgs)
-    : DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) {
+    : DeducedType(Auto, DeducedAsType, ExtraDependence) {
   AutoTypeBits.Keyword = (unsigned)Keyword;
   AutoTypeBits.NumArgs = TypeConstraintArgs.size();
   this->TypeConstraintConcept = TypeConstraintConcept;

diff  --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index c4826b5a6e8f9..7f8d030081592 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -865,7 +865,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
 
   assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
 
-  QualType T = BuildDecltypeType(DS.getRepAsExpr());
+  QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
   if (T.isNull())
     return true;
 

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4fcc01012d44d..d16ec45e7c416 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3613,14 +3613,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
       // defined, copy the deduced value from the old declaration.
       AutoType *OldAT = Old->getReturnType()->getContainedAutoType();
       if (OldAT && OldAT->isDeduced()) {
-        QualType DT = OldAT->getDeducedType();
-        if (DT.isNull()) {
-          New->setType(SubstAutoTypeDependent(New->getType()));
-          NewQType = Context.getCanonicalType(SubstAutoTypeDependent(NewQType));
-        } else {
-          New->setType(SubstAutoType(New->getType(), DT));
-          NewQType = Context.getCanonicalType(SubstAutoType(NewQType, DT));
-        }
+        New->setType(
+            SubstAutoType(New->getType(),
+                          OldAT->isDependentType() ? Context.DependentTy
+                                                   : OldAT->getDeducedType()));
+        NewQType = Context.getCanonicalType(
+            SubstAutoType(NewQType,
+                          OldAT->isDependentType() ? Context.DependentTy
+                                                   : OldAT->getDeducedType()));
       }
     }
 
@@ -9258,7 +9258,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
       // a friend yet, so 'isDependentContext' on the FD doesn't work.
       const FunctionProtoType *FPT =
           NewFD->getType()->castAs<FunctionProtoType>();
-      QualType Result = SubstAutoTypeDependent(FPT->getReturnType());
+      QualType Result =
+          SubstAutoType(FPT->getReturnType(), Context.DependentTy);
       NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(),
                                              FPT->getExtProtoInfo()));
     }
@@ -12349,7 +12350,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
                                    /*TreatUnavailableAsInvalid=*/false);
     ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
     if (Result.isInvalid()) {
-      // If the provided initializer fails to initialize the var decl,
+      // If the provied initializer fails to initialize the var decl,
       // we attach a recovery expr for better recovery.
       auto RecoveryExpr =
           CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args);

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 46b41a7b0f430..d67e039dd26cc 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4219,7 +4219,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
     if (BaseType.isNull())
       return true;
   } else if (DS.getTypeSpecType() == TST_decltype) {
-    BaseType = BuildDecltypeType(DS.getRepAsExpr());
+    BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
   } else if (DS.getTypeSpecType() == TST_decltype_auto) {
     Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
     return true;

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 891909c443ccd..571b790b31eaa 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -468,7 +468,7 @@ ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS,
 
   assert(DS.getTypeSpecType() == DeclSpec::TST_decltype &&
          "unexpected type in getDestructorType");
-  QualType T = BuildDecltypeType(DS.getRepAsExpr());
+  QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
 
   // If we know the type of the object, check that the correct destructor
   // type was named now; we can give better diagnostics this way.
@@ -7761,7 +7761,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
     return true;
   }
 
-  QualType T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false);
+  QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(),
+                                 false);
 
   TypeLocBuilder TLB;
   DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);

diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 8e435d9cb41f5..75686e2947041 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -9972,7 +9972,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
 
   auto TemplateName = DeducedTST->getTemplateName();
   if (TemplateName.isDependent())
-    return SubstAutoTypeDependent(TSInfo->getType());
+    return SubstAutoType(TSInfo->getType(), Context.DependentTy);
 
   // We can only perform deduction for class templates.
   auto *Template =
@@ -9991,7 +9991,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
     Diag(TSInfo->getTypeLoc().getBeginLoc(),
          diag::warn_cxx14_compat_class_template_argument_deduction)
         << TSInfo->getTypeLoc().getSourceRange() << 0;
-    return SubstAutoTypeDependent(TSInfo->getType());
+    return SubstAutoType(TSInfo->getType(), Context.DependentTy);
   }
 
   // FIXME: Perform "exact type" matching first, per CWG discussion?

diff  --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index b05e0b5cc0f12..c4a8b3487ab98 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -373,7 +373,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
     const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
     QualType Result = FPT->getReturnType();
     if (Result->isUndeducedType()) {
-      Result = SubstAutoTypeDependent(Result);
+      Result = SubstAutoType(Result, Context.DependentTy);
       MethodType = Context.getFunctionType(Result, FPT->getParamTypes(),
                                            FPT->getExtProtoInfo());
     }

diff  --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 3c820829864d0..dc564e318d82d 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2759,7 +2759,7 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
       if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
         for (auto *Binding : DD->bindings())
           Binding->setType(Context.DependentTy);
-      LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType()));
+      LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
     }
   } else if (!BeginDeclStmt.get()) {
     SourceLocation RangeLoc = RangeVar->getLocation();

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f4fd2ea5aa8e9..e682dc7da66e9 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1259,15 +1259,15 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP,
       BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, NTTP->getLocation());
   if (!Ref)
     return true;
-  ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint(
-      *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
-      TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
-      BuildDecltypeType(Ref), NTTP->getLocation(),
-      [&](TemplateArgumentListInfo &ConstraintArgs) {
-        for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
-          ConstraintArgs.addArgument(TL.getArgLoc(I));
-      },
-      EllipsisLoc);
+  ExprResult ImmediatelyDeclaredConstraint =
+      formImmediatelyDeclaredConstraint(
+          *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
+          TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
+          BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(),
+          [&] (TemplateArgumentListInfo &ConstraintArgs) {
+            for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
+              ConstraintArgs.addArgument(TL.getArgLoc(I));
+          }, EllipsisLoc);
   if (ImmediatelyDeclaredConstraint.isInvalid() ||
      !ImmediatelyDeclaredConstraint.isUsable())
     return true;
@@ -1289,7 +1289,7 @@ QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
     //    - an identifier associated by name lookup with a non-type
     //      template-parameter declared with a type that contains a
     //      placeholder type (7.1.7.4),
-    TSI = SubstAutoTypeSourceInfoDependent(TSI);
+    TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy);
   }
 
   return CheckNonTypeTemplateParameterType(TSI->getType(), Loc);
@@ -10873,7 +10873,7 @@ bool Sema::RebuildTemplateParamsInCurrentInstantiation(
       //    - an identifier associated by name lookup with a non-type
       //      template-parameter declared with a type that contains a
       //      placeholder type (7.1.7.4),
-      NewTSI = SubstAutoTypeSourceInfoDependent(NewTSI);
+      NewTSI = SubstAutoTypeSourceInfo(NewTSI, Context.DependentTy);
     }
 
     if (NewTSI != NTTP->getTypeSourceInfo()) {

diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index f4bb88188021d..facd3e0998e8f 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -131,16 +131,30 @@ static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) {
   return X == Y;
 }
 
-static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
-    Sema &S, TemplateParameterList *TemplateParams, QualType Param,
-    QualType Arg, TemplateDeductionInfo &Info,
-    SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
-    bool PartialOrdering = false, bool DeducedFromArrayBound = false);
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(Sema &S,
+                        TemplateParameterList *TemplateParams,
+                        const TemplateArgument &Param,
+                        TemplateArgument Arg,
+                        TemplateDeductionInfo &Info,
+                        SmallVectorImpl<DeducedTemplateArgument> &Deduced);
+
+static Sema::TemplateDeductionResult
+DeduceTemplateArgumentsByTypeMatch(Sema &S,
+                                   TemplateParameterList *TemplateParams,
+                                   QualType Param,
+                                   QualType Arg,
+                                   TemplateDeductionInfo &Info,
+                                   SmallVectorImpl<DeducedTemplateArgument> &
+                                                      Deduced,
+                                   unsigned TDF,
+                                   bool PartialOrdering = false,
+                                   bool DeducedFromArrayBound = false);
 
 static Sema::TemplateDeductionResult
 DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
-                        ArrayRef<TemplateArgument> Ps,
-                        ArrayRef<TemplateArgument> As,
+                        ArrayRef<TemplateArgument> Params,
+                        ArrayRef<TemplateArgument> Args,
                         TemplateDeductionInfo &Info,
                         SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                         bool NumberOfArgumentsMustMatch);
@@ -545,62 +559,70 @@ DeduceTemplateArguments(Sema &S,
 /// "success" result means that template argument deduction has not yet failed,
 /// but it may still fail, later, for other reasons.
 static Sema::TemplateDeductionResult
-DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
-                            const QualType P, QualType A,
-                            TemplateDeductionInfo &Info,
-                            SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
-  QualType UP = P;
-  if (const auto *IP = P->getAs<InjectedClassNameType>())
-    UP = IP->getInjectedSpecializationType();
-  // FIXME: Try to preserve type sugar here, which is hard
-  // because of the unresolved template arguments.
-  const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>();
-  ArrayRef<TemplateArgument> PResolved = TP->template_arguments();
-
-  QualType UA = A;
+DeduceTemplateArguments(Sema &S,
+                        TemplateParameterList *TemplateParams,
+                        const TemplateSpecializationType *Param,
+                        QualType Arg,
+                        TemplateDeductionInfo &Info,
+                        SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+  assert(Arg.isCanonical() && "Argument type must be canonical");
+
   // Treat an injected-class-name as its underlying template-id.
-  if (const auto *Injected = A->getAs<InjectedClassNameType>())
-    UA = Injected->getInjectedSpecializationType();
+  if (auto *Injected = dyn_cast<InjectedClassNameType>(Arg))
+    Arg = Injected->getInjectedSpecializationType();
 
   // Check whether the template argument is a dependent template-id.
-  // FIXME: Should not lose sugar here.
-  if (const auto *SA =
-          dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) {
+  if (const TemplateSpecializationType *SpecArg
+        = dyn_cast<TemplateSpecializationType>(Arg)) {
     // Perform template argument deduction for the template name.
-    if (auto Result =
-            DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(),
-                                    SA->getTemplateName(), Info, Deduced))
+    if (Sema::TemplateDeductionResult Result
+          = DeduceTemplateArguments(S, TemplateParams,
+                                    Param->getTemplateName(),
+                                    SpecArg->getTemplateName(),
+                                    Info, Deduced))
       return Result;
+
+
     // Perform template argument deduction on each template
     // argument. Ignore any missing/extra arguments, since they could be
     // filled in by default arguments.
-    return DeduceTemplateArguments(S, TemplateParams, PResolved,
-                                   SA->template_arguments(), Info, Deduced,
+    return DeduceTemplateArguments(S, TemplateParams,
+                                   Param->template_arguments(),
+                                   SpecArg->template_arguments(), Info, Deduced,
                                    /*NumberOfArgumentsMustMatch=*/false);
   }
 
   // If the argument type is a class template specialization, we
   // perform template argument deduction using its template
   // arguments.
-  const auto *RA = UA->getAs<RecordType>();
-  const auto *SA =
-      RA ? dyn_cast<ClassTemplateSpecializationDecl>(RA->getDecl()) : nullptr;
-  if (!SA) {
-    Info.FirstArg = TemplateArgument(P);
-    Info.SecondArg = TemplateArgument(A);
+  const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
+  if (!RecordArg) {
+    Info.FirstArg = TemplateArgument(QualType(Param, 0));
+    Info.SecondArg = TemplateArgument(Arg);
+    return Sema::TDK_NonDeducedMismatch;
+  }
+
+  ClassTemplateSpecializationDecl *SpecArg
+    = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
+  if (!SpecArg) {
+    Info.FirstArg = TemplateArgument(QualType(Param, 0));
+    Info.SecondArg = TemplateArgument(Arg);
     return Sema::TDK_NonDeducedMismatch;
   }
 
   // Perform template argument deduction for the template name.
-  if (auto Result = DeduceTemplateArguments(
-          S, TemplateParams, TP->getTemplateName(),
-          TemplateName(SA->getSpecializedTemplate()), Info, Deduced))
+  if (Sema::TemplateDeductionResult Result
+        = DeduceTemplateArguments(S,
+                                  TemplateParams,
+                                  Param->getTemplateName(),
+                               TemplateName(SpecArg->getSpecializedTemplate()),
+                                  Info, Deduced))
     return Result;
 
   // Perform template argument deduction for the template arguments.
-  return DeduceTemplateArguments(S, TemplateParams, PResolved,
-                                 SA->getTemplateArgs().asArray(), Info, Deduced,
-                                 /*NumberOfArgumentsMustMatch=*/true);
+  return DeduceTemplateArguments(S, TemplateParams, Param->template_arguments(),
+                                 SpecArg->getTemplateArgs().asArray(), Info,
+                                 Deduced, /*NumberOfArgumentsMustMatch=*/true);
 }
 
 /// Determines whether the given type is an opaque type that
@@ -1025,12 +1047,11 @@ DeduceTemplateArguments(Sema &S,
         return Sema::TDK_MiscellaneousDeductionFailure;
       }
 
-      if (Sema::TemplateDeductionResult Result =
-              DeduceTemplateArgumentsByTypeMatch(
-                  S, TemplateParams, Params[ParamIdx].getUnqualifiedType(),
-                  Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF,
-                  PartialOrdering,
-                  /*DeducedFromArrayBound=*/false))
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                                 Params[ParamIdx], Args[ArgIdx],
+                                                 Info, Deduced, TDF,
+                                                 PartialOrdering))
         return Result;
 
       ++ArgIdx;
@@ -1052,11 +1073,10 @@ DeduceTemplateArguments(Sema &S,
     if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) {
       for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) {
         // Deduce template arguments from the pattern.
-        if (Sema::TemplateDeductionResult Result =
-                DeduceTemplateArgumentsByTypeMatch(
-                    S, TemplateParams, Pattern.getUnqualifiedType(),
-                    Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF,
-                    PartialOrdering, /*DeducedFromArrayBound=*/false))
+        if (Sema::TemplateDeductionResult Result
+              = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern,
+                                                   Args[ArgIdx], Info, Deduced,
+                                                   TDF, PartialOrdering))
           return Result;
 
         PackScope.nextPackElement();
@@ -1135,25 +1155,26 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType,
 /// function types (noreturn adjustment, implicit calling conventions). If any
 /// of parameter and argument is not a function, just perform type comparison.
 ///
-/// \param P the template parameter type.
+/// \param Param the template parameter type.
 ///
-/// \param A the argument type.
-bool Sema::isSameOrCompatibleFunctionType(QualType P, QualType A) {
-  const FunctionType *PF = P->getAs<FunctionType>(),
-                     *AF = A->getAs<FunctionType>();
+/// \param Arg the argument type.
+bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
+                                          CanQualType Arg) {
+  const FunctionType *ParamFunction = Param->getAs<FunctionType>(),
+                     *ArgFunction   = Arg->getAs<FunctionType>();
 
   // Just compare if not functions.
-  if (!PF || !AF)
-    return Context.hasSameType(P, A);
+  if (!ParamFunction || !ArgFunction)
+    return Param == Arg;
 
   // Noreturn and noexcept adjustment.
   QualType AdjustedParam;
-  if (IsFunctionConversion(P, A, AdjustedParam))
-    return Context.hasSameType(AdjustedParam, A);
+  if (IsFunctionConversion(Param, Arg, AdjustedParam))
+    return Arg == Context.getCanonicalType(AdjustedParam);
 
   // FIXME: Compatible calling conventions.
 
-  return Context.hasSameType(P, A);
+  return Param == Arg;
 }
 
 /// Get the index of the first template parameter that was originally from the
@@ -1182,11 +1203,6 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
   return false;
 }
 
-static CXXRecordDecl *getCanonicalRD(QualType T) {
-  return cast<CXXRecordDecl>(
-      T->castAs<RecordType>()->getDecl()->getCanonicalDecl());
-}
-
 ///  Attempt to deduce the template arguments by checking the base types
 ///  according to (C++20 [temp.deduct.call] p4b3.
 ///
@@ -1205,11 +1221,10 @@ static CXXRecordDecl *getCanonicalRD(QualType T) {
 /// \returns the result of template argument deduction with the bases. "invalid"
 /// means no matches, "success" found a single item, and the
 /// "MiscellaneousDeductionFailure" result happens when the match is ambiguous.
-static Sema::TemplateDeductionResult
-DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
-                    TemplateParameterList *TemplateParams, QualType P,
-                    TemplateDeductionInfo &Info,
-                    SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult DeduceTemplateBases(
+    Sema &S, const RecordType *RecordT, TemplateParameterList *TemplateParams,
+    const TemplateSpecializationType *SpecParam, TemplateDeductionInfo &Info,
+    SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   // C++14 [temp.deduct.call] p4b3:
   //   If P is a class and P has the form simple-template-id, then the
   //   transformed A can be a derived class of the deduced A. Likewise if
@@ -1229,44 +1244,45 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
   // visited, while ToVisit is our stack of records that we still need to
   // visit.  Matches contains a list of matches that have yet to be
   // disqualified.
-  llvm::SmallPtrSet<const CXXRecordDecl *, 8> Visited;
-  SmallVector<QualType, 8> ToVisit;
+  llvm::SmallPtrSet<const RecordType *, 8> Visited;
+  SmallVector<const RecordType *, 8> ToVisit;
   // We iterate over this later, so we have to use MapVector to ensure
   // determinism.
-  llvm::MapVector<const CXXRecordDecl *,
-                  SmallVector<DeducedTemplateArgument, 8>>
+  llvm::MapVector<const RecordType *, SmallVector<DeducedTemplateArgument, 8>>
       Matches;
 
-  auto AddBases = [&Visited, &ToVisit](const CXXRecordDecl *RD) {
+  auto AddBases = [&Visited, &ToVisit](const RecordType *RT) {
+    CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
     for (const auto &Base : RD->bases()) {
-      QualType T = Base.getType();
-      assert(T->isRecordType() && "Base class that isn't a record?");
-      if (Visited.insert(::getCanonicalRD(T)).second)
-        ToVisit.push_back(T);
+      assert(Base.getType()->isRecordType() &&
+             "Base class that isn't a record?");
+      const RecordType *RT = Base.getType()->getAs<RecordType>();
+      if (Visited.insert(RT).second)
+        ToVisit.push_back(Base.getType()->getAs<RecordType>());
     }
   };
 
   // Set up the loop by adding all the bases.
-  AddBases(RD);
+  AddBases(RecordT);
 
   // Search each path of bases until we either run into a successful match
   // (where all bases of it are invalid), or we run out of bases.
   while (!ToVisit.empty()) {
-    QualType NextT = ToVisit.pop_back_val();
+    const RecordType *NextT = ToVisit.pop_back_val();
 
     SmallVector<DeducedTemplateArgument, 8> DeducedCopy(Deduced.begin(),
                                                         Deduced.end());
     TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info);
-    Sema::TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments(
-        S, TemplateParams, P, NextT, BaseInfo, DeducedCopy);
+    Sema::TemplateDeductionResult BaseResult =
+        DeduceTemplateArguments(S, TemplateParams, SpecParam,
+                                QualType(NextT, 0), BaseInfo, DeducedCopy);
 
     // If this was a successful deduction, add it to the list of matches,
     // otherwise we need to continue searching its bases.
-    const CXXRecordDecl *RD = ::getCanonicalRD(NextT);
     if (BaseResult == Sema::TDK_Success)
-      Matches.insert({RD, DeducedCopy});
+      Matches.insert({NextT, DeducedCopy});
     else
-      AddBases(RD);
+      AddBases(NextT);
   }
 
   // At this point, 'Matches' contains a list of seemingly valid bases, however
@@ -1283,12 +1299,12 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
     // We can give up once we have a single item (or have run out of things to
     // search) since cyclical inheritance isn't valid.
     while (Matches.size() > 1 && !ToVisit.empty()) {
-      const CXXRecordDecl *RD = ::getCanonicalRD(ToVisit.pop_back_val());
-      Matches.erase(RD);
+      const RecordType *NextT = ToVisit.pop_back_val();
+      Matches.erase(NextT);
 
       // Always add all bases, since the inheritance tree can contain
       // disqualifications for multiple matches.
-      AddBases(RD);
+      AddBases(NextT);
     }
   }
 
@@ -1325,26 +1341,41 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
 /// \returns the result of template argument deduction so far. Note that a
 /// "success" result means that template argument deduction has not yet failed,
 /// but it may still fail, later, for other reasons.
-static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
-    Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A,
-    TemplateDeductionInfo &Info,
-    SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
-    bool PartialOrdering, bool DeducedFromArrayBound) {
+static Sema::TemplateDeductionResult
+DeduceTemplateArgumentsByTypeMatch(Sema &S,
+                                   TemplateParameterList *TemplateParams,
+                                   QualType ParamIn, QualType ArgIn,
+                                   TemplateDeductionInfo &Info,
+                            SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+                                   unsigned TDF,
+                                   bool PartialOrdering,
+                                   bool DeducedFromArrayBound) {
+  // We only want to look at the canonical types, since typedefs and
+  // sugar are not part of template argument deduction.
+  QualType Param = S.Context.getCanonicalType(ParamIn);
+  QualType Arg = S.Context.getCanonicalType(ArgIn);
+
+  // If the argument type is a pack expansion, look at its pattern.
+  // This isn't explicitly called out
+  if (const PackExpansionType *ArgExpansion
+                                            = dyn_cast<PackExpansionType>(Arg))
+    Arg = ArgExpansion->getPattern();
+
   if (PartialOrdering) {
     // C++11 [temp.deduct.partial]p5:
     //   Before the partial ordering is done, certain transformations are
     //   performed on the types used for partial ordering:
     //     - If P is a reference type, P is replaced by the type referred to.
-    const ReferenceType *PRef = P->getAs<ReferenceType>();
-    if (PRef)
-      P = PRef->getPointeeType();
+    const ReferenceType *ParamRef = Param->getAs<ReferenceType>();
+    if (ParamRef)
+      Param = ParamRef->getPointeeType();
 
     //     - If A is a reference type, A is replaced by the type referred to.
-    const ReferenceType *ARef = A->getAs<ReferenceType>();
-    if (ARef)
-      A = A->getPointeeType();
+    const ReferenceType *ArgRef = Arg->getAs<ReferenceType>();
+    if (ArgRef)
+      Arg = ArgRef->getPointeeType();
 
-    if (PRef && ARef && S.Context.hasSameUnqualifiedType(P, A)) {
+    if (ParamRef && ArgRef && S.Context.hasSameUnqualifiedType(Param, Arg)) {
       // C++11 [temp.deduct.partial]p9:
       //   If, for a given type, deduction succeeds in both directions (i.e.,
       //   the types are identical after the transformations above) and both
@@ -1364,26 +1395,29 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
       // succeeds, so we model this as a deduction failure. Note that
       // [the first type] is P and [the other type] is A here; the standard
       // gets this backwards.
-      Qualifiers PQuals = P.getQualifiers(), AQuals = A.getQualifiers();
-      if ((PRef->isLValueReferenceType() && !ARef->isLValueReferenceType()) ||
-          PQuals.isStrictSupersetOf(AQuals) ||
-          (PQuals.hasNonTrivialObjCLifetime() &&
-           AQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
-           PQuals.withoutObjCLifetime() == AQuals.withoutObjCLifetime())) {
-        Info.FirstArg = TemplateArgument(P);
-        Info.SecondArg = TemplateArgument(A);
+      Qualifiers ParamQuals = Param.getQualifiers();
+      Qualifiers ArgQuals = Arg.getQualifiers();
+      if ((ParamRef->isLValueReferenceType() &&
+           !ArgRef->isLValueReferenceType()) ||
+          ParamQuals.isStrictSupersetOf(ArgQuals) ||
+          (ParamQuals.hasNonTrivialObjCLifetime() &&
+           ArgQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
+           ParamQuals.withoutObjCLifetime() ==
+               ArgQuals.withoutObjCLifetime())) {
+        Info.FirstArg = TemplateArgument(ParamIn);
+        Info.SecondArg = TemplateArgument(ArgIn);
         return Sema::TDK_NonDeducedMismatch;
       }
     }
-    Qualifiers DiscardedQuals;
+
     // C++11 [temp.deduct.partial]p7:
     //   Remove any top-level cv-qualifiers:
     //     - If P is a cv-qualified type, P is replaced by the cv-unqualified
     //       version of P.
-    P = S.Context.getUnqualifiedArrayType(P, DiscardedQuals);
+    Param = Param.getUnqualifiedType();
     //     - If A is a cv-qualified type, A is replaced by the cv-unqualified
     //       version of A.
-    A = S.Context.getUnqualifiedArrayType(A, DiscardedQuals);
+    Arg = Arg.getUnqualifiedType();
   } else {
     // C++0x [temp.deduct.call]p4 bullet 1:
     //   - If the original P is a reference type, the deduced A (i.e., the type
@@ -1391,12 +1425,13 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     //     transformed A.
     if (TDF & TDF_ParamWithReferenceType) {
       Qualifiers Quals;
-      QualType UnqualP = S.Context.getUnqualifiedArrayType(P, Quals);
-      Quals.setCVRQualifiers(Quals.getCVRQualifiers() & A.getCVRQualifiers());
-      P = S.Context.getQualifiedType(UnqualP, Quals);
+      QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals);
+      Quals.setCVRQualifiers(Quals.getCVRQualifiers() &
+                             Arg.getCVRQualifiers());
+      Param = S.Context.getQualifiedType(UnqualParam, Quals);
     }
 
-    if ((TDF & TDF_TopLevelParameterTypeList) && !P->isFunctionType()) {
+    if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) {
       // C++0x [temp.deduct.type]p10:
       //   If P and A are function types that originated from deduction when
       //   taking the address of a function template (14.8.2.2) or when deducing
@@ -1409,9 +1444,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
       //   Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be
       //   deduced as X&. - end note ]
       TDF &= ~TDF_TopLevelParameterTypeList;
-      if (isForwardingReference(P, /*FirstInnerIndex=*/0) &&
-          A->isLValueReferenceType())
-        P = P->getPointeeType();
+      if (isForwardingReference(Param, 0) && Arg->isLValueReferenceType())
+        Param = Param->getPointeeType();
     }
   }
 
@@ -1422,48 +1456,53 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
   //
   //     T
   //     cv-list T
-  if (const auto *TTP = P->getAs<TemplateTypeParmType>()) {
+  if (const TemplateTypeParmType *TemplateTypeParm
+        = Param->getAs<TemplateTypeParmType>()) {
     // Just skip any attempts to deduce from a placeholder type or a parameter
     // at a 
diff erent depth.
-    if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth())
+    if (Arg->isPlaceholderType() ||
+        Info.getDeducedDepth() != TemplateTypeParm->getDepth())
       return Sema::TDK_Success;
 
-    unsigned Index = TTP->getIndex();
+    unsigned Index = TemplateTypeParm->getIndex();
+    bool RecanonicalizeArg = false;
 
     // If the argument type is an array type, move the qualifiers up to the
     // top level, so they can be matched with the qualifiers on the parameter.
-    if (A->isArrayType()) {
+    if (isa<ArrayType>(Arg)) {
       Qualifiers Quals;
-      A = S.Context.getUnqualifiedArrayType(A, Quals);
-      if (Quals)
-        A = S.Context.getQualifiedType(A, Quals);
+      Arg = S.Context.getUnqualifiedArrayType(Arg, Quals);
+      if (Quals) {
+        Arg = S.Context.getQualifiedType(Arg, Quals);
+        RecanonicalizeArg = true;
+      }
     }
 
     // The argument type can not be less qualified than the parameter
     // type.
     if (!(TDF & TDF_IgnoreQualifiers) &&
-        hasInconsistentOrSupersetQualifiersOf(P, A)) {
+        hasInconsistentOrSupersetQualifiersOf(Param, Arg)) {
       Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
-      Info.FirstArg = TemplateArgument(P);
-      Info.SecondArg = TemplateArgument(A);
+      Info.FirstArg = TemplateArgument(Param);
+      Info.SecondArg = TemplateArgument(Arg);
       return Sema::TDK_Underqualified;
     }
 
     // Do not match a function type with a cv-qualified type.
     // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584
-    if (A->isFunctionType() && P.hasQualifiers())
+    if (Arg->isFunctionType() && Param.hasQualifiers()) {
       return Sema::TDK_NonDeducedMismatch;
+    }
 
-    assert(TTP->getDepth() == Info.getDeducedDepth() &&
+    assert(TemplateTypeParm->getDepth() == Info.getDeducedDepth() &&
            "saw template type parameter with wrong depth");
-    assert(A->getCanonicalTypeInternal() != S.Context.OverloadTy &&
-           "Unresolved overloaded function");
-    QualType DeducedType = A;
+    assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function");
+    QualType DeducedType = Arg;
 
     // Remove any qualifiers on the parameter from the deduced type.
     // We checked the qualifiers for consistency above.
     Qualifiers DeducedQs = DeducedType.getQualifiers();
-    Qualifiers ParamQs = P.getQualifiers();
+    Qualifiers ParamQs = Param.getQualifiers();
     DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers());
     if (ParamQs.hasObjCGCAttr())
       DeducedQs.removeObjCGCAttr();
@@ -1478,24 +1517,29 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() &&
         !DeducedType->isDependentType()) {
       Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
-      Info.FirstArg = TemplateArgument(P);
-      Info.SecondArg = TemplateArgument(A);
+      Info.FirstArg = TemplateArgument(Param);
+      Info.SecondArg = TemplateArgument(Arg);
       return Sema::TDK_Underqualified;
     }
 
     // Objective-C ARC:
     //   If template deduction would produce an argument type with lifetime type
     //   but no lifetime qualifier, the __strong lifetime qualifier is inferred.
-    if (S.getLangOpts().ObjCAutoRefCount && DeducedType->isObjCLifetimeType() &&
+    if (S.getLangOpts().ObjCAutoRefCount &&
+        DeducedType->isObjCLifetimeType() &&
         !DeducedQs.hasObjCLifetime())
       DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong);
 
-    DeducedType =
-        S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs);
+    DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(),
+                                             DeducedQs);
+
+    if (RecanonicalizeArg)
+      DeducedType = S.Context.getCanonicalType(DeducedType);
 
     DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound);
-    DeducedTemplateArgument Result =
-        checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced);
+    DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
+                                                                 Deduced[Index],
+                                                                   NewDeduced);
     if (Result.isNull()) {
       Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
       Info.FirstArg = Deduced[Index];
@@ -1508,57 +1552,69 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
   }
 
   // Set up the template argument deduction information for a failure.
-  Info.FirstArg = TemplateArgument(P);
-  Info.SecondArg = TemplateArgument(A);
+  Info.FirstArg = TemplateArgument(ParamIn);
+  Info.SecondArg = TemplateArgument(ArgIn);
 
   // If the parameter is an already-substituted template parameter
   // pack, do nothing: we don't know which of its arguments to look
   // at, so we have to wait until all of the parameter packs in this
   // expansion have arguments.
-  if (P->getAs<SubstTemplateTypeParmPackType>())
+  if (isa<SubstTemplateTypeParmPackType>(Param))
     return Sema::TDK_Success;
 
   // Check the cv-qualifiers on the parameter and argument types.
+  CanQualType CanParam = S.Context.getCanonicalType(Param);
+  CanQualType CanArg = S.Context.getCanonicalType(Arg);
   if (!(TDF & TDF_IgnoreQualifiers)) {
     if (TDF & TDF_ParamWithReferenceType) {
-      if (hasInconsistentOrSupersetQualifiersOf(P, A))
+      if (hasInconsistentOrSupersetQualifiersOf(Param, Arg))
         return Sema::TDK_NonDeducedMismatch;
     } else if (TDF & TDF_ArgWithReferenceType) {
       // C++ [temp.deduct.conv]p4:
       //   If the original A is a reference type, A can be more cv-qualified
       //   than the deduced A
-      if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers()))
+      if (!Arg.getQualifiers().compatiblyIncludes(Param.getQualifiers()))
         return Sema::TDK_NonDeducedMismatch;
 
       // Strip out all extra qualifiers from the argument to figure out the
       // type we're converting to, prior to the qualification conversion.
       Qualifiers Quals;
-      A = S.Context.getUnqualifiedArrayType(A, Quals);
-      A = S.Context.getQualifiedType(A, P.getQualifiers());
-    } else if (!IsPossiblyOpaquelyQualifiedType(P)) {
-      if (P.getCVRQualifiers() != A.getCVRQualifiers())
+      Arg = S.Context.getUnqualifiedArrayType(Arg, Quals);
+      Arg = S.Context.getQualifiedType(Arg, Param.getQualifiers());
+    } else if (!IsPossiblyOpaquelyQualifiedType(Param)) {
+      if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
         return Sema::TDK_NonDeducedMismatch;
     }
-  }
 
-  // If the parameter type is not dependent, there is nothing to deduce.
-  if (!P->isDependentType()) {
-    if (TDF & TDF_SkipNonDependent)
-      return Sema::TDK_Success;
-    if ((TDF & TDF_IgnoreQualifiers) ? S.Context.hasSameUnqualifiedType(P, A)
-                                     : S.Context.hasSameType(P, A))
+    // If the parameter type is not dependent, there is nothing to deduce.
+    if (!Param->isDependentType()) {
+      if (!(TDF & TDF_SkipNonDependent)) {
+        bool NonDeduced =
+            (TDF & TDF_AllowCompatibleFunctionType)
+                ? !S.isSameOrCompatibleFunctionType(CanParam, CanArg)
+                : Param != Arg;
+        if (NonDeduced) {
+          return Sema::TDK_NonDeducedMismatch;
+        }
+      }
       return Sema::TDK_Success;
-    if (TDF & TDF_AllowCompatibleFunctionType &&
-        S.isSameOrCompatibleFunctionType(P, A))
+    }
+  } else if (!Param->isDependentType()) {
+    if (!(TDF & TDF_SkipNonDependent)) {
+      CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
+                  ArgUnqualType = CanArg.getUnqualifiedType();
+      bool Success =
+          (TDF & TDF_AllowCompatibleFunctionType)
+              ? S.isSameOrCompatibleFunctionType(ParamUnqualType, ArgUnqualType)
+              : ParamUnqualType == ArgUnqualType;
+      if (Success)
+        return Sema::TDK_Success;
+    } else {
       return Sema::TDK_Success;
-    if (!(TDF & TDF_IgnoreQualifiers))
-      return Sema::TDK_NonDeducedMismatch;
-    // Otherwise, when ignoring qualifiers, the types not having the same
-    // unqualified type does not mean they do not match, so in this case we
-    // must keep going and analyze with a non-dependent parameter type.
+    }
   }
 
-  switch (P.getCanonicalType()->getTypeClass()) {
+  switch (Param->getTypeClass()) {
     // Non-canonical types cannot appear here.
 #define NON_CANONICAL_TYPE(Class, Base) \
   case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class);
@@ -1569,11 +1625,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     case Type::SubstTemplateTypeParmPack:
       llvm_unreachable("Type nodes handled above");
 
-    case Type::Auto:
-      // FIXME: Implement deduction in dependent case.
-      if (P->isDependentType())
-        return Sema::TDK_Success;
-      LLVM_FALLTHROUGH;
+    // These types cannot be dependent, so simply check whether the types are
+    // the same.
     case Type::Builtin:
     case Type::VariableArray:
     case Type::Vector:
@@ -1584,115 +1637,134 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     case Type::ObjCInterface:
     case Type::ObjCObjectPointer:
     case Type::ExtInt:
-      return (TDF & TDF_SkipNonDependent) ||
-                     ((TDF & TDF_IgnoreQualifiers)
-                          ? S.Context.hasSameUnqualifiedType(P, A)
-                          : S.Context.hasSameType(P, A))
-                 ? Sema::TDK_Success
-                 : Sema::TDK_NonDeducedMismatch;
+      if (TDF & TDF_SkipNonDependent)
+        return Sema::TDK_Success;
+
+      if (TDF & TDF_IgnoreQualifiers) {
+        Param = Param.getUnqualifiedType();
+        Arg = Arg.getUnqualifiedType();
+      }
+
+      return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch;
 
     //     _Complex T   [placeholder extension]
-    case Type::Complex: {
-      const auto *CP = P->castAs<ComplexType>(), *CA = A->getAs<ComplexType>();
-      if (!CA)
-        return Sema::TDK_NonDeducedMismatch;
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, CP->getElementType(), CA->getElementType(), Info,
-          Deduced, TDF);
-    }
+    case Type::Complex:
+      if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>())
+        return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                    cast<ComplexType>(Param)->getElementType(),
+                                    ComplexArg->getElementType(),
+                                    Info, Deduced, TDF);
+
+      return Sema::TDK_NonDeducedMismatch;
 
     //     _Atomic T   [extension]
-    case Type::Atomic: {
-      const auto *PA = P->castAs<AtomicType>(), *AA = A->getAs<AtomicType>();
-      if (!AA)
-        return Sema::TDK_NonDeducedMismatch;
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, PA->getValueType(), AA->getValueType(), Info,
-          Deduced, TDF);
-    }
+    case Type::Atomic:
+      if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>())
+        return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                       cast<AtomicType>(Param)->getValueType(),
+                                       AtomicArg->getValueType(),
+                                       Info, Deduced, TDF);
+
+      return Sema::TDK_NonDeducedMismatch;
 
     //     T *
     case Type::Pointer: {
       QualType PointeeType;
-      if (const auto *PA = A->getAs<PointerType>()) {
-        PointeeType = PA->getPointeeType();
-      } else if (const auto *PA = A->getAs<ObjCObjectPointerType>()) {
-        PointeeType = PA->getPointeeType();
+      if (const PointerType *PointerArg = Arg->getAs<PointerType>()) {
+        PointeeType = PointerArg->getPointeeType();
+      } else if (const ObjCObjectPointerType *PointerArg
+                   = Arg->getAs<ObjCObjectPointerType>()) {
+        PointeeType = PointerArg->getPointeeType();
       } else {
         return Sema::TDK_NonDeducedMismatch;
       }
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, P->castAs<PointerType>()->getPointeeType(),
-          PointeeType, Info, Deduced,
-          TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass));
+
+      unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
+      return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                     cast<PointerType>(Param)->getPointeeType(),
+                                     PointeeType,
+                                     Info, Deduced, SubTDF);
     }
 
     //     T &
     case Type::LValueReference: {
-      const auto *RP = P->castAs<LValueReferenceType>(),
-                 *RA = A->getAs<LValueReferenceType>();
-      if (!RA)
+      const LValueReferenceType *ReferenceArg =
+          Arg->getAs<LValueReferenceType>();
+      if (!ReferenceArg)
         return Sema::TDK_NonDeducedMismatch;
 
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info,
-          Deduced, 0);
+      return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                           cast<LValueReferenceType>(Param)->getPointeeType(),
+                           ReferenceArg->getPointeeType(), Info, Deduced, 0);
     }
 
     //     T && [C++0x]
     case Type::RValueReference: {
-      const auto *RP = P->castAs<RValueReferenceType>(),
-                 *RA = A->getAs<RValueReferenceType>();
-      if (!RA)
+      const RValueReferenceType *ReferenceArg =
+          Arg->getAs<RValueReferenceType>();
+      if (!ReferenceArg)
         return Sema::TDK_NonDeducedMismatch;
 
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info,
-          Deduced, 0);
+      return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                             cast<RValueReferenceType>(Param)->getPointeeType(),
+                             ReferenceArg->getPointeeType(),
+                             Info, Deduced, 0);
     }
 
     //     T [] (implied, but not stated explicitly)
     case Type::IncompleteArray: {
-      const auto *IAA = S.Context.getAsIncompleteArrayType(A);
-      if (!IAA)
+      const IncompleteArrayType *IncompleteArrayArg =
+        S.Context.getAsIncompleteArrayType(Arg);
+      if (!IncompleteArrayArg)
         return Sema::TDK_NonDeducedMismatch;
 
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams,
-          S.Context.getAsIncompleteArrayType(P)->getElementType(),
-          IAA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers);
+      unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
+      return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                    S.Context.getAsIncompleteArrayType(Param)->getElementType(),
+                    IncompleteArrayArg->getElementType(),
+                    Info, Deduced, SubTDF);
     }
 
     //     T [integer-constant]
     case Type::ConstantArray: {
-      const auto *CAA = S.Context.getAsConstantArrayType(A),
-                 *CAP = S.Context.getAsConstantArrayType(P);
-      assert(CAP);
-      if (!CAA || CAA->getSize() != CAP->getSize())
+      const ConstantArrayType *ConstantArrayArg =
+        S.Context.getAsConstantArrayType(Arg);
+      if (!ConstantArrayArg)
         return Sema::TDK_NonDeducedMismatch;
 
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info,
-          Deduced, TDF & TDF_IgnoreQualifiers);
+      const ConstantArrayType *ConstantArrayParm =
+        S.Context.getAsConstantArrayType(Param);
+      if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
+        return Sema::TDK_NonDeducedMismatch;
+
+      unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
+      return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                           ConstantArrayParm->getElementType(),
+                                           ConstantArrayArg->getElementType(),
+                                           Info, Deduced, SubTDF);
     }
 
     //     type [i]
     case Type::DependentSizedArray: {
-      const auto *AA = S.Context.getAsArrayType(A);
-      if (!AA)
+      const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg);
+      if (!ArrayArg)
         return Sema::TDK_NonDeducedMismatch;
 
+      unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
+
       // Check the element type of the arrays
-      const auto *DAP = S.Context.getAsDependentSizedArrayType(P);
-      assert(DAP);
-      if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-              S, TemplateParams, DAP->getElementType(), AA->getElementType(),
-              Info, Deduced, TDF & TDF_IgnoreQualifiers))
+      const DependentSizedArrayType *DependentArrayParm
+        = S.Context.getAsDependentSizedArrayType(Param);
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                          DependentArrayParm->getElementType(),
+                                          ArrayArg->getElementType(),
+                                          Info, Deduced, SubTDF))
         return Result;
 
       // Determine the array bound is something we can deduce.
-      const NonTypeTemplateParmDecl *NTTP =
-          getDeducedParameterFromExpr(Info, DAP->getSizeExpr());
+      const NonTypeTemplateParmDecl *NTTP
+        = getDeducedParameterFromExpr(Info, DependentArrayParm->getSizeExpr());
       if (!NTTP)
         return Sema::TDK_Success;
 
@@ -1700,16 +1772,20 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
       // template parameter.
       assert(NTTP->getDepth() == Info.getDeducedDepth() &&
              "saw non-type template parameter with wrong depth");
-      if (const auto *CAA = dyn_cast<ConstantArrayType>(AA)) {
-        llvm::APSInt Size(CAA->getSize());
-        return DeduceNonTypeTemplateArgument(
-            S, TemplateParams, NTTP, Size, S.Context.getSizeType(),
-            /*ArrayBound=*/true, Info, Deduced);
+      if (const ConstantArrayType *ConstantArrayArg
+            = dyn_cast<ConstantArrayType>(ArrayArg)) {
+        llvm::APSInt Size(ConstantArrayArg->getSize());
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Size,
+                                             S.Context.getSizeType(),
+                                             /*ArrayBound=*/true,
+                                             Info, Deduced);
       }
-      if (const auto *DAA = dyn_cast<DependentSizedArrayType>(AA))
-        if (DAA->getSizeExpr())
-          return DeduceNonTypeTemplateArgument(
-              S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, Deduced);
+      if (const DependentSizedArrayType *DependentArrayArg
+            = dyn_cast<DependentSizedArrayType>(ArrayArg))
+        if (DependentArrayArg->getSizeExpr())
+          return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+                                               DependentArrayArg->getSizeExpr(),
+                                               Info, Deduced);
 
       // Incomplete type does not match a dependently-sized array type
       return Sema::TDK_NonDeducedMismatch;
@@ -1719,29 +1795,34 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     //     T(*)()
     //     T(*)(T)
     case Type::FunctionProto: {
-      const auto *FPP = P->castAs<FunctionProtoType>(),
-                 *FPA = A->getAs<FunctionProtoType>();
-      if (!FPA)
+      unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList;
+      const FunctionProtoType *FunctionProtoArg =
+        dyn_cast<FunctionProtoType>(Arg);
+      if (!FunctionProtoArg)
         return Sema::TDK_NonDeducedMismatch;
 
-      if (FPP->getMethodQuals() != FPA->getMethodQuals() ||
-          FPP->getRefQualifier() != FPA->getRefQualifier() ||
-          FPP->isVariadic() != FPA->isVariadic())
+      const FunctionProtoType *FunctionProtoParam =
+        cast<FunctionProtoType>(Param);
+
+      if (FunctionProtoParam->getMethodQuals()
+            != FunctionProtoArg->getMethodQuals() ||
+          FunctionProtoParam->getRefQualifier()
+            != FunctionProtoArg->getRefQualifier() ||
+          FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
         return Sema::TDK_NonDeducedMismatch;
 
       // Check return types.
       if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-              S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(),
-              Info, Deduced, 0,
-              /*PartialOrdering=*/false,
-              /*DeducedFromArrayBound=*/false))
+              S, TemplateParams, FunctionProtoParam->getReturnType(),
+              FunctionProtoArg->getReturnType(), Info, Deduced, 0))
         return Result;
 
       // Check parameter types.
       if (auto Result = DeduceTemplateArguments(
-              S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(),
-              FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced,
-              TDF & TDF_TopLevelParameterTypeList))
+              S, TemplateParams, FunctionProtoParam->param_type_begin(),
+              FunctionProtoParam->getNumParams(),
+              FunctionProtoArg->param_type_begin(),
+              FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF))
         return Result;
 
       if (TDF & TDF_AllowCompatibleFunctionType)
@@ -1750,15 +1831,15 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
       // FIXME: Per core-2016/10/1019 (no corresponding core issue yet), permit
       // deducing through the noexcept-specifier if it's part of the canonical
       // type. libstdc++ relies on this.
-      Expr *NoexceptExpr = FPP->getNoexceptExpr();
+      Expr *NoexceptExpr = FunctionProtoParam->getNoexceptExpr();
       if (const NonTypeTemplateParmDecl *NTTP =
-              NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
-                           : nullptr) {
+          NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
+                       : nullptr) {
         assert(NTTP->getDepth() == Info.getDeducedDepth() &&
                "saw non-type template parameter with wrong depth");
 
         llvm::APSInt Noexcept(1);
-        switch (FPA->canThrow()) {
+        switch (FunctionProtoArg->canThrow()) {
         case CT_Cannot:
           Noexcept = 1;
           LLVM_FALLTHROUGH;
@@ -1768,10 +1849,10 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
           // FIXME: Should we?
           return DeduceNonTypeTemplateArgument(
               S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy,
-              /*DeducedFromArrayBound=*/true, Info, Deduced);
+              /*ArrayBound*/true, Info, Deduced);
 
         case CT_Dependent:
-          if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr())
+          if (Expr *ArgNoexceptExpr = FunctionProtoArg->getNoexceptExpr())
             return DeduceNonTypeTemplateArgument(
                 S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced);
           // Can't deduce anything from throw(T...).
@@ -1789,6 +1870,11 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     case Type::InjectedClassName:
       // Treat a template's injected-class-name as if the template
       // specialization type had been used.
+      Param = cast<InjectedClassNameType>(Param)
+        ->getInjectedSpecializationType();
+      assert(isa<TemplateSpecializationType>(Param) &&
+             "injected class name is not a template specialization type");
+      LLVM_FALLTHROUGH;
 
     //     template-name<T> (where template-name refers to a class template)
     //     template-name<i>
@@ -1796,33 +1882,41 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     //     TT<i>
     //     TT<>
     case Type::TemplateSpecialization: {
+      const TemplateSpecializationType *SpecParam =
+          cast<TemplateSpecializationType>(Param);
+
       // When Arg cannot be a derived class, we can just try to deduce template
       // arguments from the template-id.
-      if (!(TDF & TDF_DerivedClass) || !A->isRecordType())
-        return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info,
-                                           Deduced);
+      const RecordType *RecordT = Arg->getAs<RecordType>();
+      if (!(TDF & TDF_DerivedClass) || !RecordT)
+        return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info,
+                                       Deduced);
 
       SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(),
                                                           Deduced.end());
 
-      auto Result =
-          DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, Deduced);
+      Sema::TemplateDeductionResult Result = DeduceTemplateArguments(
+          S, TemplateParams, SpecParam, Arg, Info, Deduced);
+
       if (Result == Sema::TDK_Success)
         return Result;
 
       // We cannot inspect base classes as part of deduction when the type
       // is incomplete, so either instantiate any templates necessary to
       // complete the type, or skip over it if it cannot be completed.
-      if (!S.isCompleteType(Info.getLocation(), A))
+      if (!S.isCompleteType(Info.getLocation(), Arg))
         return Result;
 
       // Reset the incorrectly deduced argument from above.
       Deduced = DeducedOrig;
 
       // Check bases according to C++14 [temp.deduct.call] p4b3:
-      auto BaseResult = DeduceTemplateBases(S, getCanonicalRD(A),
-                                            TemplateParams, P, Info, Deduced);
-      return BaseResult != Sema::TDK_Invalid ? BaseResult : Result;
+      Sema::TemplateDeductionResult BaseResult = DeduceTemplateBases(
+          S, RecordT, TemplateParams, SpecParam, Info, Deduced);
+
+      if (BaseResult != Sema::TDK_Invalid)
+        return BaseResult;
+      return Result;
     }
 
     //     T type::*
@@ -1835,27 +1929,33 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     //     T (T::*)()
     //     T (T::*)(T)
     case Type::MemberPointer: {
-      const auto *MPP = P->castAs<MemberPointerType>(),
-                 *MPA = A->getAs<MemberPointerType>();
-      if (!MPA)
+      const MemberPointerType *MemPtrParam = cast<MemberPointerType>(Param);
+      const MemberPointerType *MemPtrArg = dyn_cast<MemberPointerType>(Arg);
+      if (!MemPtrArg)
         return Sema::TDK_NonDeducedMismatch;
 
-      QualType PPT = MPP->getPointeeType();
-      if (PPT->isFunctionType())
-        S.adjustMemberFunctionCC(PPT, /*IsStatic=*/true,
+      QualType ParamPointeeType = MemPtrParam->getPointeeType();
+      if (ParamPointeeType->isFunctionType())
+        S.adjustMemberFunctionCC(ParamPointeeType, /*IsStatic=*/true,
                                  /*IsCtorOrDtor=*/false, Info.getLocation());
-      QualType APT = MPA->getPointeeType();
-      if (APT->isFunctionType())
-        S.adjustMemberFunctionCC(APT, /*IsStatic=*/true,
+      QualType ArgPointeeType = MemPtrArg->getPointeeType();
+      if (ArgPointeeType->isFunctionType())
+        S.adjustMemberFunctionCC(ArgPointeeType, /*IsStatic=*/true,
                                  /*IsCtorOrDtor=*/false, Info.getLocation());
 
-      unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
-      if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-              S, TemplateParams, PPT, APT, Info, Deduced, SubTDF))
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                                 ParamPointeeType,
+                                                 ArgPointeeType,
+                                                 Info, Deduced,
+                                                 TDF & TDF_IgnoreQualifiers))
         return Result;
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, QualType(MPP->getClass(), 0),
-          QualType(MPA->getClass(), 0), Info, Deduced, SubTDF);
+
+      return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                           QualType(MemPtrParam->getClass(), 0),
+                                           QualType(MemPtrArg->getClass(), 0),
+                                           Info, Deduced,
+                                           TDF & TDF_IgnoreQualifiers);
     }
 
     //     (clang extension)
@@ -1864,58 +1964,70 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     //     T(^)()
     //     T(^)(T)
     case Type::BlockPointer: {
-      const auto *BPP = P->castAs<BlockPointerType>(),
-                 *BPA = A->getAs<BlockPointerType>();
-      if (!BPA)
+      const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(Param);
+      const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg);
+
+      if (!BlockPtrArg)
         return Sema::TDK_NonDeducedMismatch;
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info,
-          Deduced, 0);
+
+      return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                                BlockPtrParam->getPointeeType(),
+                                                BlockPtrArg->getPointeeType(),
+                                                Info, Deduced, 0);
     }
 
     //     (clang extension)
     //
     //     T __attribute__(((ext_vector_type(<integral constant>))))
     case Type::ExtVector: {
-      const auto *VP = P->castAs<ExtVectorType>();
-      QualType ElementType;
-      if (const auto *VA = A->getAs<ExtVectorType>()) {
+      const ExtVectorType *VectorParam = cast<ExtVectorType>(Param);
+      if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
         // Make sure that the vectors have the same number of elements.
-        if (VP->getNumElements() != VA->getNumElements())
+        if (VectorParam->getNumElements() != VectorArg->getNumElements())
           return Sema::TDK_NonDeducedMismatch;
-        ElementType = VA->getElementType();
-      } else if (const auto *VA = A->getAs<DependentSizedExtVectorType>()) {
+
+        // Perform deduction on the element types.
+        return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                                  VectorParam->getElementType(),
+                                                  VectorArg->getElementType(),
+                                                  Info, Deduced, TDF);
+      }
+
+      if (const DependentSizedExtVectorType *VectorArg
+                                = dyn_cast<DependentSizedExtVectorType>(Arg)) {
         // We can't check the number of elements, since the argument has a
         // dependent number of elements. This can only occur during partial
         // ordering.
-        ElementType = VA->getElementType();
-      } else {
-        return Sema::TDK_NonDeducedMismatch;
+
+        // Perform deduction on the element types.
+        return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                                  VectorParam->getElementType(),
+                                                  VectorArg->getElementType(),
+                                                  Info, Deduced, TDF);
       }
-      // Perform deduction on the element types.
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced,
-          TDF);
+
+      return Sema::TDK_NonDeducedMismatch;
     }
 
     case Type::DependentVector: {
-      const auto *VP = P->castAs<DependentVectorType>();
+      const auto *VectorParam = cast<DependentVectorType>(Param);
 
-      if (const auto *VA = A->getAs<VectorType>()) {
+      if (const auto *VectorArg = dyn_cast<VectorType>(Arg)) {
         // Perform deduction on the element types.
-        if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-                S, TemplateParams, VP->getElementType(), VA->getElementType(),
-                Info, Deduced, TDF))
+        if (Sema::TemplateDeductionResult Result =
+                DeduceTemplateArgumentsByTypeMatch(
+                    S, TemplateParams, VectorParam->getElementType(),
+                    VectorArg->getElementType(), Info, Deduced, TDF))
           return Result;
 
         // Perform deduction on the vector size, if we can.
         const NonTypeTemplateParmDecl *NTTP =
-            getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+            getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr());
         if (!NTTP)
           return Sema::TDK_Success;
 
         llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
-        ArgSize = VA->getNumElements();
+        ArgSize = VectorArg->getNumElements();
         // Note that we use the "array bound" rules here; just like in that
         // case, we don't have any particular type for the vector size, but
         // we can provide one if necessary.
@@ -1924,21 +2036,22 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
                                              Info, Deduced);
       }
 
-      if (const auto *VA = A->getAs<DependentVectorType>()) {
+      if (const auto *VectorArg = dyn_cast<DependentVectorType>(Arg)) {
         // Perform deduction on the element types.
-        if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-                S, TemplateParams, VP->getElementType(), VA->getElementType(),
-                Info, Deduced, TDF))
+        if (Sema::TemplateDeductionResult Result =
+                DeduceTemplateArgumentsByTypeMatch(
+                    S, TemplateParams, VectorParam->getElementType(),
+                    VectorArg->getElementType(), Info, Deduced, TDF))
           return Result;
 
         // Perform deduction on the vector size, if we can.
-        const NonTypeTemplateParmDecl *NTTP =
-            getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+        const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+            Info, VectorParam->getSizeExpr());
         if (!NTTP)
           return Sema::TDK_Success;
 
-        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
-                                             VA->getSizeExpr(), Info, Deduced);
+        return DeduceNonTypeTemplateArgument(
+            S, TemplateParams, NTTP, VectorArg->getSizeExpr(), Info, Deduced);
       }
 
       return Sema::TDK_NonDeducedMismatch;
@@ -1948,23 +2061,26 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     //
     //     T __attribute__(((ext_vector_type(N))))
     case Type::DependentSizedExtVector: {
-      const auto *VP = P->castAs<DependentSizedExtVectorType>();
+      const DependentSizedExtVectorType *VectorParam
+        = cast<DependentSizedExtVectorType>(Param);
 
-      if (const auto *VA = A->getAs<ExtVectorType>()) {
+      if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
         // Perform deduction on the element types.
-        if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-                S, TemplateParams, VP->getElementType(), VA->getElementType(),
-                Info, Deduced, TDF))
+        if (Sema::TemplateDeductionResult Result
+              = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                                  VectorParam->getElementType(),
+                                                   VectorArg->getElementType(),
+                                                   Info, Deduced, TDF))
           return Result;
 
         // Perform deduction on the vector size, if we can.
         const NonTypeTemplateParmDecl *NTTP =
-            getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+            getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr());
         if (!NTTP)
           return Sema::TDK_Success;
 
         llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
-        ArgSize = VA->getNumElements();
+        ArgSize = VectorArg->getNumElements();
         // Note that we use the "array bound" rules here; just like in that
         // case, we don't have any particular type for the vector size, but
         // we can provide one if necessary.
@@ -1973,21 +2089,25 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
                                              Deduced);
       }
 
-      if (const auto *VA = A->getAs<DependentSizedExtVectorType>()) {
+      if (const DependentSizedExtVectorType *VectorArg
+                                = dyn_cast<DependentSizedExtVectorType>(Arg)) {
         // Perform deduction on the element types.
-        if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-                S, TemplateParams, VP->getElementType(), VA->getElementType(),
-                Info, Deduced, TDF))
+        if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                                 VectorParam->getElementType(),
+                                                 VectorArg->getElementType(),
+                                                 Info, Deduced, TDF))
           return Result;
 
         // Perform deduction on the vector size, if we can.
         const NonTypeTemplateParmDecl *NTTP =
-            getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+            getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr());
         if (!NTTP)
           return Sema::TDK_Success;
 
         return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
-                                             VA->getSizeExpr(), Info, Deduced);
+                                             VectorArg->getSizeExpr(),
+                                             Info, Deduced);
       }
 
       return Sema::TDK_NonDeducedMismatch;
@@ -1998,55 +2118,57 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     //     T __attribute__((matrix_type(<integral constant>,
     //                                  <integral constant>)))
     case Type::ConstantMatrix: {
-      const auto *MP = P->castAs<ConstantMatrixType>(),
-                 *MA = A->getAs<ConstantMatrixType>();
-      if (!MA)
+      const ConstantMatrixType *MatrixArg = dyn_cast<ConstantMatrixType>(Arg);
+      if (!MatrixArg)
         return Sema::TDK_NonDeducedMismatch;
 
+      const ConstantMatrixType *MatrixParam = cast<ConstantMatrixType>(Param);
       // Check that the dimensions are the same
-      if (MP->getNumRows() != MA->getNumRows() ||
-          MP->getNumColumns() != MA->getNumColumns()) {
+      if (MatrixParam->getNumRows() != MatrixArg->getNumRows() ||
+          MatrixParam->getNumColumns() != MatrixArg->getNumColumns()) {
         return Sema::TDK_NonDeducedMismatch;
       }
       // Perform deduction on element types.
       return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, MP->getElementType(), MA->getElementType(), Info,
-          Deduced, TDF);
+          S, TemplateParams, MatrixParam->getElementType(),
+          MatrixArg->getElementType(), Info, Deduced, TDF);
     }
 
     case Type::DependentSizedMatrix: {
-      const auto *MP = P->castAs<DependentSizedMatrixType>();
-      const auto *MA = A->getAs<MatrixType>();
-      if (!MA)
+      const MatrixType *MatrixArg = dyn_cast<MatrixType>(Arg);
+      if (!MatrixArg)
         return Sema::TDK_NonDeducedMismatch;
 
       // Check the element type of the matrixes.
-      if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-              S, TemplateParams, MP->getElementType(), MA->getElementType(),
-              Info, Deduced, TDF))
+      const DependentSizedMatrixType *MatrixParam =
+          cast<DependentSizedMatrixType>(Param);
+      if (Sema::TemplateDeductionResult Result =
+              DeduceTemplateArgumentsByTypeMatch(
+                  S, TemplateParams, MatrixParam->getElementType(),
+                  MatrixArg->getElementType(), Info, Deduced, TDF))
         return Result;
 
       // Try to deduce a matrix dimension.
       auto DeduceMatrixArg =
           [&S, &Info, &Deduced, &TemplateParams](
-              Expr *ParamExpr, const MatrixType *A,
+              Expr *ParamExpr, const MatrixType *Arg,
               unsigned (ConstantMatrixType::*GetArgDimension)() const,
               Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) {
-            const auto *ACM = dyn_cast<ConstantMatrixType>(A);
-            const auto *ADM = dyn_cast<DependentSizedMatrixType>(A);
+            const auto *ArgConstMatrix = dyn_cast<ConstantMatrixType>(Arg);
+            const auto *ArgDepMatrix = dyn_cast<DependentSizedMatrixType>(Arg);
             if (!ParamExpr->isValueDependent()) {
               Optional<llvm::APSInt> ParamConst =
                   ParamExpr->getIntegerConstantExpr(S.Context);
               if (!ParamConst)
                 return Sema::TDK_NonDeducedMismatch;
 
-              if (ACM) {
-                if ((ACM->*GetArgDimension)() == *ParamConst)
+              if (ArgConstMatrix) {
+                if ((ArgConstMatrix->*GetArgDimension)() == *ParamConst)
                   return Sema::TDK_Success;
                 return Sema::TDK_NonDeducedMismatch;
               }
 
-              Expr *ArgExpr = (ADM->*GetArgDimensionExpr)();
+              Expr *ArgExpr = (ArgDepMatrix->*GetArgDimensionExpr)();
               if (Optional<llvm::APSInt> ArgConst =
                       ArgExpr->getIntegerConstantExpr(S.Context))
                 if (*ArgConst == *ParamConst)
@@ -2059,26 +2181,27 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
             if (!NTTP)
               return Sema::TDK_Success;
 
-            if (ACM) {
+            if (ArgConstMatrix) {
               llvm::APSInt ArgConst(
                   S.Context.getTypeSize(S.Context.getSizeType()));
-              ArgConst = (ACM->*GetArgDimension)();
+              ArgConst = (ArgConstMatrix->*GetArgDimension)();
               return DeduceNonTypeTemplateArgument(
                   S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(),
                   /*ArrayBound=*/true, Info, Deduced);
             }
 
-            return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
-                                                 (ADM->*GetArgDimensionExpr)(),
-                                                 Info, Deduced);
+            return DeduceNonTypeTemplateArgument(
+                S, TemplateParams, NTTP, (ArgDepMatrix->*GetArgDimensionExpr)(),
+                Info, Deduced);
           };
 
-      if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA,
-                                        &ConstantMatrixType::getNumRows,
-                                        &DependentSizedMatrixType::getRowExpr))
+      auto Result = DeduceMatrixArg(MatrixParam->getRowExpr(), MatrixArg,
+                                    &ConstantMatrixType::getNumRows,
+                                    &DependentSizedMatrixType::getRowExpr);
+      if (Result)
         return Result;
 
-      return DeduceMatrixArg(MP->getColumnExpr(), MA,
+      return DeduceMatrixArg(MatrixParam->getColumnExpr(), MatrixArg,
                              &ConstantMatrixType::getNumColumns,
                              &DependentSizedMatrixType::getColumnExpr);
     }
@@ -2087,39 +2210,44 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     //
     //     T __attribute__(((address_space(N))))
     case Type::DependentAddressSpace: {
-      const auto *ASP = P->castAs<DependentAddressSpaceType>();
+      const DependentAddressSpaceType *AddressSpaceParam =
+          cast<DependentAddressSpaceType>(Param);
 
-      if (const auto *ASA = A->getAs<DependentAddressSpaceType>()) {
+      if (const DependentAddressSpaceType *AddressSpaceArg =
+              dyn_cast<DependentAddressSpaceType>(Arg)) {
         // Perform deduction on the pointer type.
-        if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-                S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(),
-                Info, Deduced, TDF))
+        if (Sema::TemplateDeductionResult Result =
+                DeduceTemplateArgumentsByTypeMatch(
+                    S, TemplateParams, AddressSpaceParam->getPointeeType(),
+                    AddressSpaceArg->getPointeeType(), Info, Deduced, TDF))
           return Result;
 
         // Perform deduction on the address space, if we can.
-        const NonTypeTemplateParmDecl *NTTP =
-            getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
+        const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+            Info, AddressSpaceParam->getAddrSpaceExpr());
         if (!NTTP)
           return Sema::TDK_Success;
 
         return DeduceNonTypeTemplateArgument(
-            S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, Deduced);
+            S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info,
+            Deduced);
       }
 
-      if (isTargetAddressSpace(A.getAddressSpace())) {
+      if (isTargetAddressSpace(Arg.getAddressSpace())) {
         llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy),
                                      false);
-        ArgAddressSpace = toTargetAddressSpace(A.getAddressSpace());
+        ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace());
 
         // Perform deduction on the pointer types.
-        if (auto Result = DeduceTemplateArgumentsByTypeMatch(
-                S, TemplateParams, ASP->getPointeeType(),
-                S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF))
+        if (Sema::TemplateDeductionResult Result =
+                DeduceTemplateArgumentsByTypeMatch(
+                    S, TemplateParams, AddressSpaceParam->getPointeeType(),
+                    S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF))
           return Result;
 
         // Perform deduction on the address space, if we can.
-        const NonTypeTemplateParmDecl *NTTP =
-            getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
+        const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+            Info, AddressSpaceParam->getAddrSpaceExpr());
         if (!NTTP)
           return Sema::TDK_Success;
 
@@ -2131,31 +2259,30 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
       return Sema::TDK_NonDeducedMismatch;
     }
     case Type::DependentExtInt: {
-      const auto *IP = P->castAs<DependentExtIntType>();
+      const auto *IntParam = cast<DependentExtIntType>(Param);
 
-      if (const auto *IA = A->getAs<ExtIntType>()) {
-        if (IP->isUnsigned() != IA->isUnsigned())
+      if (const auto *IntArg = dyn_cast<ExtIntType>(Arg)){
+        if (IntParam->isUnsigned() != IntArg->isUnsigned())
           return Sema::TDK_NonDeducedMismatch;
 
         const NonTypeTemplateParmDecl *NTTP =
-            getDeducedParameterFromExpr(Info, IP->getNumBitsExpr());
+            getDeducedParameterFromExpr(Info, IntParam->getNumBitsExpr());
         if (!NTTP)
           return Sema::TDK_Success;
 
         llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
-        ArgSize = IA->getNumBits();
+        ArgSize = IntArg->getNumBits();
 
         return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
                                              S.Context.IntTy, true, Info,
                                              Deduced);
       }
 
-      if (const auto *IA = A->getAs<DependentExtIntType>()) {
-        if (IP->isUnsigned() != IA->isUnsigned())
+      if (const auto *IntArg = dyn_cast<DependentExtIntType>(Arg)) {
+        if (IntParam->isUnsigned() != IntArg->isUnsigned())
           return Sema::TDK_NonDeducedMismatch;
         return Sema::TDK_Success;
       }
-
       return Sema::TDK_NonDeducedMismatch;
     }
 
@@ -2165,103 +2292,125 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
     case Type::UnresolvedUsing:
     case Type::Decltype:
     case Type::UnaryTransform:
+    case Type::Auto:
     case Type::DeducedTemplateSpecialization:
     case Type::DependentTemplateSpecialization:
     case Type::PackExpansion:
     case Type::Pipe:
       // No template argument deduction for these types
       return Sema::TDK_Success;
-    }
+  }
 
   llvm_unreachable("Invalid Type Class!");
 }
 
 static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
-                        const TemplateArgument &P, TemplateArgument A,
+DeduceTemplateArguments(Sema &S,
+                        TemplateParameterList *TemplateParams,
+                        const TemplateArgument &Param,
+                        TemplateArgument Arg,
                         TemplateDeductionInfo &Info,
                         SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   // If the template argument is a pack expansion, perform template argument
   // deduction against the pattern of that expansion. This only occurs during
   // partial ordering.
-  if (A.isPackExpansion())
-    A = A.getPackExpansionPattern();
+  if (Arg.isPackExpansion())
+    Arg = Arg.getPackExpansionPattern();
 
-  switch (P.getKind()) {
+  switch (Param.getKind()) {
   case TemplateArgument::Null:
     llvm_unreachable("Null template argument in parameter list");
 
   case TemplateArgument::Type:
-    if (A.getKind() == TemplateArgument::Type)
-      return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0);
-    Info.FirstArg = P;
-    Info.SecondArg = A;
+    if (Arg.getKind() == TemplateArgument::Type)
+      return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+                                                Param.getAsType(),
+                                                Arg.getAsType(),
+                                                Info, Deduced, 0);
+    Info.FirstArg = Param;
+    Info.SecondArg = Arg;
     return Sema::TDK_NonDeducedMismatch;
 
   case TemplateArgument::Template:
-    if (A.getKind() == TemplateArgument::Template)
-      return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(),
-                                     A.getAsTemplate(), Info, Deduced);
-    Info.FirstArg = P;
-    Info.SecondArg = A;
+    if (Arg.getKind() == TemplateArgument::Template)
+      return DeduceTemplateArguments(S, TemplateParams,
+                                     Param.getAsTemplate(),
+                                     Arg.getAsTemplate(), Info, Deduced);
+    Info.FirstArg = Param;
+    Info.SecondArg = Arg;
     return Sema::TDK_NonDeducedMismatch;
 
   case TemplateArgument::TemplateExpansion:
     llvm_unreachable("caller should handle pack expansions");
 
   case TemplateArgument::Declaration:
-    if (A.getKind() == TemplateArgument::Declaration &&
-        isSameDeclaration(P.getAsDecl(), A.getAsDecl()))
+    if (Arg.getKind() == TemplateArgument::Declaration &&
+        isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()))
       return Sema::TDK_Success;
 
-    Info.FirstArg = P;
-    Info.SecondArg = A;
+    Info.FirstArg = Param;
+    Info.SecondArg = Arg;
     return Sema::TDK_NonDeducedMismatch;
 
   case TemplateArgument::NullPtr:
-    if (A.getKind() == TemplateArgument::NullPtr &&
-        S.Context.hasSameType(P.getNullPtrType(), A.getNullPtrType()))
+    if (Arg.getKind() == TemplateArgument::NullPtr &&
+        S.Context.hasSameType(Param.getNullPtrType(), Arg.getNullPtrType()))
       return Sema::TDK_Success;
 
-    Info.FirstArg = P;
-    Info.SecondArg = A;
+    Info.FirstArg = Param;
+    Info.SecondArg = Arg;
     return Sema::TDK_NonDeducedMismatch;
 
   case TemplateArgument::Integral:
-    if (A.getKind() == TemplateArgument::Integral) {
-      if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral()))
+    if (Arg.getKind() == TemplateArgument::Integral) {
+      if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
         return Sema::TDK_Success;
+
+      Info.FirstArg = Param;
+      Info.SecondArg = Arg;
+      return Sema::TDK_NonDeducedMismatch;
     }
-    Info.FirstArg = P;
-    Info.SecondArg = A;
+
+    if (Arg.getKind() == TemplateArgument::Expression) {
+      Info.FirstArg = Param;
+      Info.SecondArg = Arg;
+      return Sema::TDK_NonDeducedMismatch;
+    }
+
+    Info.FirstArg = Param;
+    Info.SecondArg = Arg;
     return Sema::TDK_NonDeducedMismatch;
 
   case TemplateArgument::Expression:
     if (const NonTypeTemplateParmDecl *NTTP =
-            getDeducedParameterFromExpr(Info, P.getAsExpr())) {
-      if (A.getKind() == TemplateArgument::Integral)
-        return DeduceNonTypeTemplateArgument(
-            S, TemplateParams, NTTP, A.getAsIntegral(), A.getIntegralType(),
-            /*ArrayBound=*/false, Info, Deduced);
-      if (A.getKind() == TemplateArgument::NullPtr)
+            getDeducedParameterFromExpr(Info, Param.getAsExpr())) {
+      if (Arg.getKind() == TemplateArgument::Integral)
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+                                             Arg.getAsIntegral(),
+                                             Arg.getIntegralType(),
+                                             /*ArrayBound=*/false,
+                                             Info, Deduced);
+      if (Arg.getKind() == TemplateArgument::NullPtr)
         return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP,
-                                             A.getNullPtrType(), Info, Deduced);
-      if (A.getKind() == TemplateArgument::Expression)
+                                             Arg.getNullPtrType(),
+                                             Info, Deduced);
+      if (Arg.getKind() == TemplateArgument::Expression)
         return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
-                                             A.getAsExpr(), Info, Deduced);
-      if (A.getKind() == TemplateArgument::Declaration)
-        return DeduceNonTypeTemplateArgument(
-            S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(),
-            Info, Deduced);
+                                             Arg.getAsExpr(), Info, Deduced);
+      if (Arg.getKind() == TemplateArgument::Declaration)
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+                                             Arg.getAsDecl(),
+                                             Arg.getParamTypeForDecl(),
+                                             Info, Deduced);
 
-      Info.FirstArg = P;
-      Info.SecondArg = A;
+      Info.FirstArg = Param;
+      Info.SecondArg = Arg;
       return Sema::TDK_NonDeducedMismatch;
     }
 
     // Can't deduce anything, but that's okay.
     return Sema::TDK_Success;
+
   case TemplateArgument::Pack:
     llvm_unreachable("Argument packs should be expanded by the caller!");
   }
@@ -2314,8 +2463,8 @@ static bool hasPackExpansionBeforeEnd(ArrayRef<TemplateArgument> Args) {
 
 static Sema::TemplateDeductionResult
 DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
-                        ArrayRef<TemplateArgument> Ps,
-                        ArrayRef<TemplateArgument> As,
+                        ArrayRef<TemplateArgument> Params,
+                        ArrayRef<TemplateArgument> Args,
                         TemplateDeductionInfo &Info,
                         SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                         bool NumberOfArgumentsMustMatch) {
@@ -2323,7 +2472,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
   //   If the template argument list of P contains a pack expansion that is not
   //   the last template argument, the entire template argument list is a
   //   non-deduced context.
-  if (hasPackExpansionBeforeEnd(Ps))
+  if (hasPackExpansionBeforeEnd(Params))
     return Sema::TDK_Success;
 
   // C++0x [temp.deduct.type]p9:
@@ -2331,13 +2480,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
   //   respective template argument list P is compared with the corresponding
   //   argument Ai of the corresponding template argument list of A.
   unsigned ArgIdx = 0, ParamIdx = 0;
-  for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) {
-    const TemplateArgument &P = Ps[ParamIdx];
-    if (!P.isPackExpansion()) {
+  for (; hasTemplateArgumentForDeduction(Params, ParamIdx); ++ParamIdx) {
+    if (!Params[ParamIdx].isPackExpansion()) {
       // The simple case: deduce template arguments by matching Pi and Ai.
 
       // Check whether we have enough arguments.
-      if (!hasTemplateArgumentForDeduction(As, ArgIdx))
+      if (!hasTemplateArgumentForDeduction(Args, ArgIdx))
         return NumberOfArgumentsMustMatch
                    ? Sema::TDK_MiscellaneousDeductionFailure
                    : Sema::TDK_Success;
@@ -2345,12 +2493,14 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
       // C++1z [temp.deduct.type]p9:
       //   During partial ordering, if Ai was originally a pack expansion [and]
       //   Pi is not a pack expansion, template argument deduction fails.
-      if (As[ArgIdx].isPackExpansion())
+      if (Args[ArgIdx].isPackExpansion())
         return Sema::TDK_MiscellaneousDeductionFailure;
 
       // Perform deduction for this Pi/Ai pair.
-      if (auto Result = DeduceTemplateArguments(S, TemplateParams, P,
-                                                As[ArgIdx], Info, Deduced))
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArguments(S, TemplateParams,
+                                      Params[ParamIdx], Args[ArgIdx],
+                                      Info, Deduced))
         return Result;
 
       // Move to the next argument.
@@ -2365,7 +2515,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
     //   each remaining argument in the template argument list of A. Each
     //   comparison deduces template arguments for subsequent positions in the
     //   template parameter packs expanded by Pi.
-    TemplateArgument Pattern = P.getPackExpansionPattern();
+    TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern();
 
     // Prepare to deduce the packs within the pattern.
     PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
@@ -2373,12 +2523,13 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
     // Keep track of the deduced template arguments for each parameter pack
     // expanded by this pack expansion (the outer index) and for each
     // template argument (the inner SmallVectors).
-    for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
+    for (; hasTemplateArgumentForDeduction(Args, ArgIdx) &&
            PackScope.hasNextElement();
          ++ArgIdx) {
       // Deduce template arguments from the pattern.
-      if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern,
-                                                As[ArgIdx], Info, Deduced))
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx],
+                                      Info, Deduced))
         return Result;
 
       PackScope.nextPackElement();
@@ -2394,14 +2545,15 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
 }
 
 static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
+DeduceTemplateArguments(Sema &S,
+                        TemplateParameterList *TemplateParams,
                         const TemplateArgumentList &ParamList,
                         const TemplateArgumentList &ArgList,
                         TemplateDeductionInfo &Info,
                         SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   return DeduceTemplateArguments(S, TemplateParams, ParamList.asArray(),
                                  ArgList.asArray(), Info, Deduced,
-                                 /*NumberOfArgumentsMustMatch=*/false);
+                                 /*NumberOfArgumentsMustMatch*/false);
 }
 
 /// Determine whether two template arguments are the same.
@@ -4204,7 +4356,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
   bool HasDeducedReturnType = false;
   if (getLangOpts().CPlusPlus14 && IsAddressOfFunction &&
       Function->getReturnType()->getContainedAutoType()) {
-    FunctionType = SubstAutoTypeDependent(FunctionType);
+    FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
     HasDeducedReturnType = true;
   }
 
@@ -4638,8 +4790,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
       ExprResult ER = CheckPlaceholderExpr(Init);
       if (ER.isInvalid())
         return DAR_FailedAlreadyDiagnosed;
-      QualType Deduced = getDecltypeForExpr(ER.get());
-      assert(!Deduced.isNull());
+      Init = ER.get();
+      QualType Deduced = BuildDecltypeType(Init, Init->getBeginLoc(), false);
+      if (Deduced.isNull())
+        return DAR_FailedAlreadyDiagnosed;
+      // FIXME: Support a non-canonical deduced type for 'auto'.
+      Deduced = Context.getCanonicalType(Deduced);
       if (AT->isConstrained() && !IgnoreConstraints) {
         auto ConstraintsResult =
             CheckDeducedPlaceholderConstraints(*this, *AT,
@@ -4674,7 +4830,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
       Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
 
   QualType FuncParam =
-      SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true)
+      SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
           .Apply(Type);
   assert(!FuncParam.isNull() &&
          "substituting template parameter for 'auto' failed");
@@ -4788,29 +4944,27 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
 
 QualType Sema::SubstAutoType(QualType TypeWithAuto,
                              QualType TypeToReplaceAuto) {
-  assert(TypeToReplaceAuto != Context.DependentTy);
+  if (TypeToReplaceAuto->isDependentType())
+    return SubstituteDeducedTypeTransform(
+               *this, DependentAuto{
+                          TypeToReplaceAuto->containsUnexpandedParameterPack()})
+        .TransformType(TypeWithAuto);
   return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
       .TransformType(TypeWithAuto);
 }
 
 TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
                                               QualType TypeToReplaceAuto) {
-  assert(TypeToReplaceAuto != Context.DependentTy);
+  if (TypeToReplaceAuto->isDependentType())
+    return SubstituteDeducedTypeTransform(
+               *this,
+               DependentAuto{
+                   TypeToReplaceAuto->containsUnexpandedParameterPack()})
+        .TransformType(TypeWithAuto);
   return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
       .TransformType(TypeWithAuto);
 }
 
-QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) {
-  return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
-      .TransformType(TypeWithAuto);
-}
-
-TypeSourceInfo *
-Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) {
-  return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
-      .TransformType(TypeWithAuto);
-}
-
 QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
                                QualType TypeToReplaceAuto) {
   return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto,
@@ -5005,7 +5159,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
       Args2.resize(NumComparedArguments);
     if (Reversed)
       std::reverse(Args2.begin(), Args2.end());
-
     if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
                                 Args1.data(), Args1.size(), Info, Deduced,
                                 TDF_None, /*PartialOrdering=*/true))

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index d2ee669debd0c..32ee61cc58659 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1622,7 +1622,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
     Expr *E = DS.getRepAsExpr();
     assert(E && "Didn't get an expression for typeof?");
     // TypeQuals handled by caller.
-    Result = S.BuildTypeofExprType(E);
+    Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc());
     if (Result.isNull()) {
       Result = Context.IntTy;
       declarator.setInvalidType(true);
@@ -1633,7 +1633,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
     Expr *E = DS.getRepAsExpr();
     assert(E && "Didn't get an expression for decltype?");
     // TypeQuals handled by caller.
-    Result = S.BuildDecltypeType(E);
+    Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc());
     if (Result.isNull()) {
       Result = Context.IntTy;
       declarator.setInvalidType(true);
@@ -8925,7 +8925,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
   return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl);
 }
 
-QualType Sema::BuildTypeofExprType(Expr *E) {
+QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
   assert(!E->hasPlaceholderType() && "unexpected placeholder");
 
   if (!getLangOpts().CPlusPlus && E->refersToBitField())
@@ -8942,9 +8942,9 @@ QualType Sema::BuildTypeofExprType(Expr *E) {
 /// getDecltypeForExpr - Given an expr, will return the decltype for
 /// that expression, according to the rules in C++11
 /// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18.
-QualType Sema::getDecltypeForExpr(Expr *E) {
+static QualType getDecltypeForExpr(Sema &S, Expr *E) {
   if (E->isTypeDependent())
-    return Context.DependentTy;
+    return S.Context.DependentTy;
 
   Expr *IDExpr = E;
   if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E))
@@ -8961,7 +8961,7 @@ QualType Sema::getDecltypeForExpr(Expr *E) {
   // parameter object. This rule makes no 
diff erence before C++20 so we apply
   // it unconditionally.
   if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(IDExpr))
-    return SNTTPE->getParameterType(Context);
+    return SNTTPE->getParameterType(S.Context);
 
   //     - if e is an unparenthesized id-expression or an unparenthesized class
   //       member access (5.2.5), decltype(e) is the type of the entity named
@@ -8969,21 +8969,22 @@ QualType Sema::getDecltypeForExpr(Expr *E) {
   //       functions, the program is ill-formed;
   //
   // We apply the same rules for Objective-C ivar and property references.
-  if (const auto *DRE = dyn_cast<DeclRefExpr>(IDExpr)) {
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr)) {
     const ValueDecl *VD = DRE->getDecl();
-    QualType T = VD->getType();
-    return isa<TemplateParamObjectDecl>(VD) ? T.getUnqualifiedType() : T;
-  }
-  if (const auto *ME = dyn_cast<MemberExpr>(IDExpr)) {
-    if (const auto *VD = ME->getMemberDecl())
+    if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(VD))
+      return TPO->getType().getUnqualifiedType();
+    return VD->getType();
+  } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(IDExpr)) {
+    if (const ValueDecl *VD = ME->getMemberDecl())
       if (isa<FieldDecl>(VD) || isa<VarDecl>(VD))
         return VD->getType();
-  } else if (const auto *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
+  } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
     return IR->getDecl()->getType();
-  } else if (const auto *PR = dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
+  } else if (const ObjCPropertyRefExpr *PR =
+                 dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
     if (PR->isExplicitProperty())
       return PR->getExplicitProperty()->getType();
-  } else if (const auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) {
+  } else if (auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) {
     return PE->getType();
   }
 
@@ -8994,20 +8995,24 @@ QualType Sema::getDecltypeForExpr(Expr *E) {
   //   access to a corresponding data member of the closure type that
   //   would have been declared if x were an odr-use of the denoted
   //   entity.
-  if (getCurLambda() && isa<ParenExpr>(IDExpr)) {
-    if (auto *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) {
-      if (auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
-        QualType T = getCapturedDeclRefType(Var, DRE->getLocation());
-        if (!T.isNull())
-          return Context.getLValueReferenceType(T);
+  using namespace sema;
+  if (S.getCurLambda()) {
+    if (isa<ParenExpr>(IDExpr)) {
+      if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) {
+        if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+          QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation());
+          if (!T.isNull())
+            return S.Context.getLValueReferenceType(T);
+        }
       }
     }
   }
 
-  return Context.getReferenceQualifiedType(E);
+  return S.Context.getReferenceQualifiedType(E);
 }
 
-QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
+QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc,
+                                 bool AsUnevaluated) {
   assert(!E->hasPlaceholderType() && "unexpected placeholder");
 
   if (AsUnevaluated && CodeSynthesisContexts.empty() &&
@@ -9018,7 +9023,8 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
     // used to build SFINAE gadgets.
     Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
   }
-  return Context.getDecltypeType(E, getDecltypeForExpr(E));
+
+  return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
 }
 
 QualType Sema::BuildUnaryTransformType(QualType BaseType,

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 442b4819b808c..c1e9890094fde 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -6586,7 +6586,7 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
       T->isDependentType() || T->isConstrained()) {
     // FIXME: Maybe don't rebuild if all template arguments are the same.
     llvm::SmallVector<TemplateArgument, 4> NewArgList;
-    NewArgList.reserve(NewTemplateArgs.size());
+    NewArgList.reserve(NewArgList.size());
     for (const auto &ArgLoc : NewTemplateArgs.arguments())
       NewArgList.push_back(ArgLoc.getArgument());
     Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD,
@@ -14501,10 +14501,10 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc,
   return SemaRef.Context.getTypeDeclType(Ty);
 }
 
-template <typename Derived>
+template<typename Derived>
 QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E,
-                                                       SourceLocation) {
-  return SemaRef.BuildTypeofExprType(E);
+                                                       SourceLocation Loc) {
+  return SemaRef.BuildTypeofExprType(E, Loc);
 }
 
 template<typename Derived>
@@ -14512,9 +14512,10 @@ QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) {
   return SemaRef.Context.getTypeOfType(Underlying);
 }
 
-template <typename Derived>
-QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, SourceLocation) {
-  return SemaRef.BuildDecltypeType(E);
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E,
+                                                     SourceLocation Loc) {
+  return SemaRef.BuildDecltypeType(E, Loc);
 }
 
 template<typename Derived>

diff  --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
index 594654730d071..cb9407b1db88b 100644
--- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
+++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
@@ -36,7 +36,7 @@ namespace std {
 
 namespace p0702r1 {
   template<typename T> struct X { // expected-note {{candidate}}
-    X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'std::initializer_list<T>' against 'p0702r1::Z'}}
+    X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'initializer_list<type-parameter-0-0>' against 'p0702r1::Z'}}
   };
 
   X xi = {0};

diff  --git a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 751ad58ad820b..0963dd23724a8 100644
--- a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -321,14 +321,14 @@ namespace p0962r1 {
 
   namespace NE {
     struct E {
-      void begin(); // expected-note {{member is not a candidate because range type 'NE::E' has no 'end' member}}
+      void begin(); // expected-note {{member is not a candidate because range type 'p0962r1::NE::E' has no 'end' member}}
     };
     int *end(E);
   }
 
   namespace NF {
     struct F {
-      void end(); // expected-note {{member is not a candidate because range type 'NF::F' has no 'begin' member}}
+      void end(); // expected-note {{member is not a candidate because range type 'p0962r1::NF::F' has no 'begin' member}}
     };
     int *begin(F);
   }
@@ -336,9 +336,9 @@ namespace p0962r1 {
   void use(NA::A a, NB::B b, NC::C c, ND::D d, NE::E e, NF::F f) {
     for (auto x : a) {}
     for (auto x : b) {}
-    for (auto x : c) {} // expected-error {{invalid range expression of type 'NC::C'; no viable 'end' function available}}
-    for (auto x : d) {} // expected-error {{invalid range expression of type 'ND::D'; no viable 'begin' function available}}
-    for (auto x : e) {} // expected-error {{invalid range expression of type 'NE::E'; no viable 'begin' function available}}
-    for (auto x : f) {} // expected-error {{invalid range expression of type 'NF::F'; no viable 'end' function available}}
+    for (auto x : c) {} // expected-error {{invalid range expression of type 'p0962r1::NC::C'; no viable 'end' function available}}
+    for (auto x : d) {} // expected-error {{invalid range expression of type 'p0962r1::ND::D'; no viable 'begin' function available}}
+    for (auto x : e) {} // expected-error {{invalid range expression of type 'p0962r1::NE::E'; no viable 'begin' function available}}
+    for (auto x : f) {} // expected-error {{invalid range expression of type 'p0962r1::NF::F'; no viable 'end' function available}}
   }
 }

diff  --git a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index 30e7c65dac91c..46fc91325880c 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -284,7 +284,7 @@ namespace PR13386 {
     void g(U &&...u, T &&...t) {} // expected-note {{candidate}}
     template<typename...U>
     void h(tuple<T, U> &&...) {}
-    // expected-note at -1 {{candidate template ignored: could not match 'tuple<T, U>' against 'int'}}
+    // expected-note at -1 {{candidate template ignored: could not match 'tuple<type-parameter-0-0, type-parameter-0-0>' against 'int'}}
     // expected-note at -2 {{candidate template ignored: substitution failure: deduced incomplete pack <(no value)> for template parameter 'U'}}
 
     template<typename...U>

diff  --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
index 1da599ed3c27a..081bba2b8dffc 100644
--- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
+++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
@@ -53,8 +53,9 @@ void test_simple_ref_deduction(int *ip, float *fp, double *dp) {
 }
 
 
+// FIXME: Use the template parameter names in this diagnostic.
 template<typename ...Args1, typename ...Args2>
-typename get_nth_type<0, Args1...>::type first_arg_pair(pair<Args1, Args2>...); // expected-note{{candidate template ignored: could not match 'pair<Args1, Args2>' against 'int'}}
+typename get_nth_type<0, Args1...>::type first_arg_pair(pair<Args1, Args2>...); // expected-note{{candidate template ignored: could not match 'pair<type-parameter-0-0, type-parameter-0-1>' against 'int'}}
 
 template<typename ...Args1, typename ...Args2>
 typename get_nth_type<1, Args1...>::type second_arg_pair(pair<Args1, Args2>...);

diff  --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
index fe0af399f7b9c..357ea664037df 100644
--- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
+++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
@@ -18,12 +18,6 @@ namespace PR12132 {
   void foo() {
     fun(&A::x);
   }
-  struct B { char* x; };
-  void bar() {
-    fun(&B::x);
-    // expected-error at -1 {{no matching function for call to 'fun'}}
-    // expected-note at -9  {{candidate template ignored: could not match 'const int' against 'char'}}
-  }
 }
 
 #if __cplusplus > 201402L
@@ -58,4 +52,6 @@ namespace noexcept_conversion {
   int i1 = i(g1);
   int i2 = i(g2);
 }
+#else
+// expected-no-diagnostics
 #endif

diff  --git a/clang/test/Index/print-type.cpp b/clang/test/Index/print-type.cpp
index 458acc42ef3e0..f52ee8092e8f3 100644
--- a/clang/test/Index/print-type.cpp
+++ b/clang/test/Index/print-type.cpp
@@ -199,7 +199,7 @@ inline namespace InlineNS {}
 // CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization<Specialization<bool> &>] [typekind=Record] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
 // CHECK: DeclRefExpr=templRefParam:71:40 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
 // CHECK: TypeAliasDecl=baz:76:7 (Definition) [type=baz] [typekind=Typedef] [templateargs/1= [type=A<void>] [typekind=Unexposed]] [canonicaltype=A<void>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=void] [typekind=Void]] [isPOD=0]
-// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization<Specialization<bool> &> *] [typekind=Auto] [canonicaltype=Specialization<Specialization<bool> &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization<Specialization<bool> &>] [pointeekind=Auto]
+// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization<Specialization<bool> &> *] [typekind=Auto] [canonicaltype=Specialization<Specialization<bool> &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization<Specialization<bool> &>] [pointeekind=Record]
 // CHECK: CallExpr=Bar:17:3 [type=outer::inner::Bar] [typekind=Elaborated] [canonicaltype=outer::inner::Bar] [canonicaltypekind=Record] [args= [outer::Foo<bool> *] [Pointer]] [isPOD=0] [nbFields=3]
 // CHECK: StructDecl=:84:3 (Definition) [type=X::(anonymous struct at {{.*}}print-type.cpp:84:3)] [typekind=Record] [isPOD=1] [nbFields=1] [isAnon=1]
 // CHECK: ClassDecl=:85:3 (Definition) [type=X::(anonymous class at {{.*}}print-type.cpp:85:3)] [typekind=Record] [isPOD=1] [nbFields=1] [isAnon=1]

diff  --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 5a49f28ef9a1d..84b3a542dcaad 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -569,52 +569,6 @@ namespace PR52139 {
     virtual void f() = 0;
   };
 }
-
-namespace function_prototypes {
-  template<class T> using fptr1 = void (*) (T);
-  template<class T> using fptr2 = fptr1<fptr1<T>>;
-
-  template<class T> void foo0(fptr1<T>) {
-    static_assert(__is_same(T, const char*));
-  }
-  void bar0(const char *const volatile __restrict);
-  void t0() { foo0(&bar0); }
-
-  template<class T> void foo1(fptr1<const T *>) {
-     static_assert(__is_same(T, char));  
-  }
-  void bar1(const char * __restrict);
-  void t1() { foo1(&bar1); }
-
-  template<class T> void foo2(fptr2<const T *>) {
-    static_assert(__is_same(T, char));
-  }
-  void bar2(fptr1<const char * __restrict>);
-  void t2() { foo2(&bar2); }
-
-  template<class T> void foo3(fptr1<const T *>) {}
-  void bar3(char * __restrict);
-  void t3() { foo3(&bar3); }
-  // expected-error at -1 {{no matching function for call to 'foo3'}}
-  // expected-note at -4  {{candidate template ignored: cannot deduce a type for 'T' that would make 'const T' equal 'char'}}
-
-  template<class T> void foo4(fptr2<const T *>) {}
-  void bar4(fptr1<char * __restrict>);
-  void t4() { foo4(&bar4); }
-  // expected-error at -1 {{no matching function for call to 'foo4'}}
-  // expected-note at -4  {{candidate template ignored: cannot deduce a type for 'T' that would make 'const T' equal 'char'}}
-
-  template<typename T> void foo5(T(T)) {}
-  const int bar5(int);
-  void t5() { foo5(bar5); }
-  // expected-error at -1 {{no matching function for call to 'foo5'}}
-  // expected-note at -4  {{candidate template ignored: deduced conflicting types for parameter 'T' ('const int' vs. 'int')}}
-
-  struct Foo6 {};
-  template<typename T> void foo6(void(*)(struct Foo6, T)) {}
-  void bar6(Foo6, int);
-  void t6() { foo6(bar6); }
-}
 #else
 
 // expected-no-diagnostics

diff  --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp
index 4c8c64177ed13..f97c5b033e9c7 100644
--- a/clang/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp
@@ -9,7 +9,7 @@ void num_elems() {
   int a1[1], a2[2];
 
   auto [] = a0; // expected-warning {{does not allow a decomposition group to be empty}}
-  auto [v1] = a0; // expected-error {{type 'struct A0' decomposes into 0 elements, but 1 name was provided}}
+  auto [v1] = a0; // expected-error {{type 'A0' decomposes into 0 elements, but 1 name was provided}}
   auto [] = a1; // expected-error {{type 'int[1]' decomposes into 1 element, but no names were provided}} expected-warning {{empty}}
   auto [v2] = a1;
   auto [v3, v4] = a1; // expected-error {{type 'int[1]' decomposes into 1 element, but 2 names were provided}}
@@ -70,7 +70,7 @@ void enclosing() {
 void bitfield() {
   struct { int a : 3, : 4, b : 5; } a;
   auto &[x, y] = a;
-  auto &[p, q, r] = a; // expected-error-re {{type 'struct (unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}}
+  auto &[p, q, r] = a; // expected-error-re {{type '(unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}}
 }
 
 void for_range() {

diff  --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
index da2f5f54b2476..030a329697efc 100644
--- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
+++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
@@ -300,7 +300,7 @@ namespace Constexpr {
   }
   struct NonLiteral { ~NonLiteral(); } nl; // cxx14-note {{user-provided destructor}}
   // cxx20_2b-note at -1 {{'NonLiteral' is not literal because its destructor is not constexpr}}
-  constexpr auto f2(int n) { return nl; } // expected-error {{return type 'struct NonLiteral' is not a literal type}}
+  constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}}
 }
 
 // It's not really clear whether these are valid, but this matches g++.

diff  --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp
index 367d6a6c1807c..822b1de39a1e3 100644
--- a/clang/test/SemaCXX/friend.cpp
+++ b/clang/test/SemaCXX/friend.cpp
@@ -415,7 +415,7 @@ namespace PR33222 {
 
 namespace qualified_friend_no_match {
   void f(int); // expected-note {{type mismatch at 1st parameter}}
-  template<typename T> void f(T*); // expected-note {{could not match 'T *' against 'double'}}
+  template<typename T> void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' against 'double'}}
   struct X {
     friend void qualified_friend_no_match::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in namespace 'qualified_friend_no_match'}}
     friend void qualified_friend_no_match::g(); // expected-error {{friend declaration of 'g' does not match any declaration in namespace 'qualified_friend_no_match'}}
@@ -423,7 +423,7 @@ namespace qualified_friend_no_match {
 
   struct Y {
     void f(int); // expected-note {{type mismatch at 1st parameter}}
-    template<typename T> void f(T*); // expected-note {{could not match 'T *' against 'double'}}
+    template<typename T> void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' against 'double'}}
   };
   struct Z {
     friend void Y::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in 'qualified_friend_no_match::Y'}}

diff  --git a/clang/test/SemaCXX/recovery-expr-type.cpp b/clang/test/SemaCXX/recovery-expr-type.cpp
index 94b275c9a362f..2fdbd0d3b6c30 100644
--- a/clang/test/SemaCXX/recovery-expr-type.cpp
+++ b/clang/test/SemaCXX/recovery-expr-type.cpp
@@ -133,7 +133,7 @@ struct S { // expected-note {{candidate}}
 template <typename T> S(T t) -> S<void *>;
 
 void baz() {
-  bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'S<void *>'}}
+  bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'test11::S<>'}}
 }
 } // namespace test11
 

diff  --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp
index 026c610a60e17..ee3ef51435d53 100644
--- a/clang/test/SemaCXX/sizeless-1.cpp
+++ b/clang/test/SemaCXX/sizeless-1.cpp
@@ -581,7 +581,7 @@ void cxx_only(int sel) {
   auto auto_int8 = local_int8;
   auto auto_int16 = local_int16;
 #if __cplusplus >= 201703L
-  auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type 'svint8_t' (aka '__SVInt8_t')}}
+  auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type '__SVInt8_t'}}
 #endif
 #endif
 
@@ -600,7 +600,7 @@ void cxx_only(int sel) {
   auto fn1 = [&local_int8](svint8_t x) { local_int8 = x; };
   auto fn2 = [&local_int8](svint8_t *ptr) { *ptr = local_int8; };
 #if __cplusplus >= 201703L
-  auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type 'svint8_t' (aka '__SVInt8_t')}}
+  auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type '__SVInt8_t'}}
 #endif
   auto fn4 = [local_int8](svint8_t *ptr) { *ptr = local_int8; }; // expected-error {{by-copy capture of variable 'local_int8' with sizeless type 'svint8_t'}}
 

diff  --git a/clang/test/SemaCXX/sugared-auto.cpp b/clang/test/SemaCXX/sugared-auto.cpp
deleted file mode 100644
index d63b0bccb2ed1..0000000000000
--- a/clang/test/SemaCXX/sugared-auto.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20
-
-enum class N {};
-
-using Animal = int;
-
-using AnimalPtr = Animal *;
-
-using Man = Animal;
-using Dog = Animal;
-
-namespace variable {
-
-auto x1 = Animal();
-N t1 = x1; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
-
-auto x2 = AnimalPtr();
-N t2 = x2; // expected-error {{lvalue of type 'AnimalPtr' (aka 'int *')}}
-
-auto *x3 = AnimalPtr();
-N t3 = x3; // expected-error {{lvalue of type 'Animal *' (aka 'int *')}}
-
-// Each variable deduces separately.
-auto x4 = Man(), x5 = Dog();
-N t4 = x4; // expected-error {{lvalue of type 'Man' (aka 'int')}}
-N t5 = x5; // expected-error {{lvalue of type 'Dog' (aka 'int')}}
-
-} // namespace variable
-
-namespace function_basic {
-
-auto f1() { return Animal(); }
-auto x1 = f1();
-N t1 = x1; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
-
-decltype(auto) f2() { return Animal(); }
-auto x2 = f2();
-N t2 = x2; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
-
-auto x3 = [a = Animal()] { return a; }();
-N t3 = x3; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
-
-} // namespace function_basic

diff  --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp
index b34794968ae89..b0bcca566dd9b 100644
--- a/clang/test/SemaTemplate/attributes.cpp
+++ b/clang/test/SemaTemplate/attributes.cpp
@@ -124,8 +124,7 @@ namespace preferred_name {
     struct [[clang::preferred_name(iterator),
              clang::preferred_name(const_iterator)]] Iter {};
   };
-  template<typename T> T desugar(T);
-  auto it = desugar(MemberTemplate<int>::Iter<const int>());
+  auto it = MemberTemplate<int>::Iter<const int>();
   int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}}
 
   template<int A, int B, typename ...T> struct Foo;

diff  --git a/clang/test/SemaTemplate/friend.cpp b/clang/test/SemaTemplate/friend.cpp
index 1427db093ec94..fc6cd42a3ba26 100644
--- a/clang/test/SemaTemplate/friend.cpp
+++ b/clang/test/SemaTemplate/friend.cpp
@@ -50,7 +50,7 @@ C<int> c;
 
 namespace qualified_friend {
   void f(int); // expected-note 2{{type mismatch at 1st parameter}}
-  template<typename T> void f(T*); // expected-note 2{{could not match 'T *' against 'double'}}
+  template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
   template<typename T> void nondep();
 
   template<typename> struct X1 {
@@ -66,7 +66,7 @@ namespace qualified_friend {
 
   struct Y {
     void f(int); // expected-note 2{{type mismatch at 1st parameter}}
-    template<typename T> void f(T*); // expected-note 2{{could not match 'T *' against 'double'}}
+    template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
     template<typename T> void nondep();
   };
 

diff  --git a/clang/test/SemaTemplate/operator-template.cpp b/clang/test/SemaTemplate/operator-template.cpp
index cf604691b943c..e60216ff96319 100644
--- a/clang/test/SemaTemplate/operator-template.cpp
+++ b/clang/test/SemaTemplate/operator-template.cpp
@@ -2,7 +2,7 @@
 
 // Make sure we accept this
 template<class X>struct A{typedef X Y;};
-template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: could not match 'A<X>' against 'B<int> *'}}
+template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: could not match 'A<type-parameter-0-0>' against 'B<int> *'}}
 
 int a(A<int> x) { return operator==(x,1); }
 

diff  --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.verify.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp
similarity index 81%
rename from libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.verify.cpp
rename to libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp
index a28e3fc9d1d78..234efc83423bb 100644
--- a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.verify.cpp
+++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp
@@ -18,13 +18,6 @@
 
 // Try and cast away const.
 
-// This test only checks that we static_assert in any_cast when the
-// constraints are not respected, however Clang will sometimes emit
-// additional errors while trying to instantiate the rest of any_cast
-// following the static_assert. We ignore unexpected errors in
-// clang-verify to make the test more robust to changes in Clang.
-// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error
-
 #include <any>
 
 struct TestType {};
@@ -37,15 +30,19 @@ int main(int, char**)
 
     any a;
 
+    // expected-error at any:* {{drops 'const' qualifier}}
     // expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
     any_cast<TestType &>(static_cast<any const&>(a)); // expected-note {{requested here}}
 
+    // expected-error at any:* {{cannot cast from lvalue of type 'const TestType' to rvalue reference type 'TestType &&'; types are not compatible}}
     // expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
     any_cast<TestType &&>(static_cast<any const&>(a)); // expected-note {{requested here}}
 
+    // expected-error at any:* {{drops 'const' qualifier}}
     // expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
     any_cast<TestType2 &>(static_cast<any const&&>(a)); // expected-note {{requested here}}
 
+    // expected-error at any:* {{cannot cast from lvalue of type 'const TestType2' to rvalue reference type 'TestType2 &&'; types are not compatible}}
     // expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
     any_cast<TestType2 &&>(static_cast<any const&&>(a)); // expected-note {{requested here}}
 

diff  --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.verify.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp
similarity index 81%
rename from libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.verify.cpp
rename to libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp
index ec40eeeec11b4..44a67f7aa03dc 100644
--- a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.verify.cpp
+++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp
@@ -24,13 +24,6 @@
 
 // Test instantiating the any_cast with a non-copyable type.
 
-// This test only checks that we static_assert in any_cast when the
-// constraints are not respected, however Clang will sometimes emit
-// additional errors while trying to instantiate the rest of any_cast
-// following the static_assert. We ignore unexpected errors in
-// clang-verify to make the test more robust to changes in Clang.
-// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error
-
 #include <any>
 
 using std::any;
@@ -52,14 +45,17 @@ struct no_move {
 int main(int, char**) {
     any a;
     // expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be an lvalue reference or a CopyConstructible type"}}
+    // expected-error at any:* {{static_cast from 'no_copy' to 'no_copy' uses deleted function}}
     any_cast<no_copy>(static_cast<any&>(a)); // expected-note {{requested here}}
 
     // expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
+    // expected-error at any:* {{static_cast from 'const no_copy' to 'no_copy' uses deleted function}}
     any_cast<no_copy>(static_cast<any const&>(a)); // expected-note {{requested here}}
 
     any_cast<no_copy>(static_cast<any &&>(a)); // OK
 
     // expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be an rvalue reference or a CopyConstructible type"}}
+    // expected-error at any:* {{static_cast from 'typename remove_reference<no_move &>::type' (aka 'no_move') to 'no_move' uses deleted function}}
     any_cast<no_move>(static_cast<any &&>(a));
 
   return 0;

diff  --git a/lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp b/lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp
index 69d8d17179fe9..75f9a029d448c 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp
@@ -118,7 +118,7 @@ auto aab = &unary<int(*)[5]>;
 auto aac = &unary<int(&&)[5]>;
 // CHECK: (void (*)(int (&&)[5])) aac = {{.*}}
 auto aad = &unary<int(*const)[5]>;
-// CHECK: (void (*)(int (*const)[5])) aad = {{.*}}
+// CHECK: (void (*)(int (*)[5])) aad = {{.*}}
 
 
 // same test cases with return values, note we can't overload on return type


        


More information about the libcxx-commits mailing list