Index: test/Misc/diag-template-diffing-color.cpp
===================================================================
--- test/Misc/diag-template-diffing-color.cpp	(revision 162297)
+++ test/Misc/diag-template-diffing-color.cpp	(working copy)
@@ -17,3 +17,56 @@
 // TREE: non-const lvalue reference cannot bind to a value of unrelated type
 // TREE:   foo<
 // TREE:     [{{.}}[0;1;36mdouble{{.}}[0m{{.}}[1m != {{.}}[0;1;36mint{{.}}[0m{{.}}[1m]>{{.}}[0m
+
+template<typename> class vector {};
+
+void set15(vector<const vector<int> >) {}
+void test15() {
+  set15(vector<const vector<const int> >());
+}
+// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<const vector<{{.}}[0;1;36mconst int{{.}}[0m>>' to 'vector<const vector<{{.}}[0;1;36mint{{.}}[0m>>' for 1st argument
+// TREE: {{.*}}candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE:   vector<
+// TREE:     const vector<
+// TREE:       [{{.}}[0;1;36mconst int{{.}}[0m != {{.}}[0;1;36mint{{.}}[0m]>>
+
+void set16(vector<vector<int> >) {}
+void test16() {
+  set16(vector<const vector<int> >());
+}
+// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' to 'vector<{{.}}[0;1;36m(missing const){{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// TREE: {{.*}}candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE:   vector<
+// TREE:     [{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36m(no qualifiers){{ ?.}}[0m]{{ ?}}vector<
+// TREE:       [...]>>
+
+void set17(vector<const vector<int> >) {}
+void test17() {
+  set17(vector<vector<int> >());
+}
+// CHECK: candidate function not viable: no known conversion from 'vector<{{.}}[0;1;36m(missing const){{ ?.}}[0m{{ ?}}vector<[...]>>' to 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE:   vector<
+// TREE:     [{{.}}[0;1;36m(no qualifiers){{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36mconst{{.}}[0m] vector<
+// TREE:       [...]>>
+
+void set18(vector<volatile vector<int> >) {}
+void test18() {
+  set18(vector<const vector<int> >());
+}
+// CHECK: candidate function not viable: no known conversion from 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}{{.}}[0;1;36m(missing volatile){{ ?.}}[0m{{ ?}}vector<[...]>>' to 'vector<{{.}}[0;1;36mvolatile{{ ?.}}[0m{{ ?}}{{.}}[0;1;36m(missing const){{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// TREE: no matching function for call to 'set18'
+// TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE:   vector<
+// TREE:     [{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36mvolatile{{.}}[0m] vector<
+// TREE:       [...]>>
+
+void set19(vector<const volatile vector<int> >) {}
+void test19() {
+  set19(vector<const vector<int> >());
+}
+// CHECK: candidate function not viable: no known conversion from 'vector<const {{.}}[0;1;36m(missing volatile){{ ?.}}[0m{{ ?}}vector<[...]>>' to 'vector<const {{.}}[0;1;36mvolatile{{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE:   vector<
+// TREE:     [const != const {{.}}[0;1;36mvolatile{{.}}[0m] vector<
+// TREE:       [...]>>
Index: test/Misc/diag-template-diffing.cpp
===================================================================
--- test/Misc/diag-template-diffing.cpp	(revision 162297)
+++ test/Misc/diag-template-diffing.cpp	(working copy)
@@ -426,7 +426,150 @@
 // CHECK-NOELIDE-TREE:     &b13, 
 // CHECK-NOELIDE-TREE:     [&d13 != (no argument)]>
 
+//template<class> class vector{};
+void set14(vector<vector<int>>) {}
+void test14() {
+  set14(vector<vector<int>>());
+}
+// no error here
 
+void set15(vector<const vector<int>>) {}
+void test15() {
+  set15(vector<const vector<const int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set15'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<const int>>' to 'vector<const vector<int>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set15'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<const int>>' to 'vector<const vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set15'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE:   vector<
+// CHECK-ELIDE-TREE:     const vector<
+// CHECK-ELIDE-TREE:       [const int != int]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set15'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE:   vector<
+// CHECK-NOELIDE-TREE:     const vector<
+// CHECK-NOELIDE-TREE:       [const int != int]>>
+
+void set16(vector<vector<int>>) {}
+void test16() {
+  set16(vector<const vector<int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set16'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<[...]>>' to 'vector<(missing const) vector<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set16'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<int>>' to 'vector<(missing const) vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set16'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE:   vector<
+// CHECK-ELIDE-TREE:     [const != (no qualifiers)] vector<
+// CHECK-ELIDE-TREE:       [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set16'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE:   vector<
+// CHECK-NOELIDE-TREE:     [const != (no qualifiers)] vector<
+// CHECK-NOELIDE-TREE:       int>>
+
+void set17(vector<const vector<int>>) {}
+void test17() {
+  set17(vector<vector<int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set17'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<(missing const) vector<[...]>>' to 'vector<const vector<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set17'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<(missing const) vector<int>>' to 'vector<const vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set17'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE:   vector<
+// CHECK-ELIDE-TREE:     [(no qualifiers) != const] vector<
+// CHECK-ELIDE-TREE:       [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set17'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE:   vector<
+// CHECK-NOELIDE-TREE:     [(no qualifiers) != const] vector<
+// CHECK-NOELIDE-TREE:       int>>
+
+void set18(vector<volatile vector<int>>) {}
+void test18() {
+  set18(vector<const vector<int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set18'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const (missing volatile) vector<[...]>>' to 'vector<volatile (missing const) vector<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set18'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const (missing volatile) vector<int>>' to 'vector<volatile (missing const) vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set18'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE:   vector<
+// CHECK-ELIDE-TREE:     [const != volatile] vector<
+// CHECK-ELIDE-TREE:       [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set18'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE:   vector<
+// CHECK-NOELIDE-TREE:     [const != volatile] vector<
+// CHECK-NOELIDE-TREE:       int>>
+
+void set19(vector<const volatile vector<int>>) {}
+void test19() {
+  set19(vector<const vector<int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set19'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const (missing volatile) vector<[...]>>' to 'vector<const volatile vector<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set19'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const (missing volatile) vector<int>>' to 'vector<const volatile vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set19'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE:   vector<
+// CHECK-ELIDE-TREE:     [const != const volatile] vector<
+// CHECK-ELIDE-TREE:       [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set19'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE:   vector<
+// CHECK-NOELIDE-TREE:     [const != const volatile] vector<
+// CHECK-NOELIDE-TREE:       int>>
+
+
+// Checks that volatile does not show up in diagnostics.
+template<typename T> struct S20 {};
+template<typename T> using U20 = volatile S20<T>;
+int f20(vector<const U20<int>>);
+int k20 = f20(vector<U20<int>>());
+// CHECK-ELIDE-NOTREE: no matching function for call to 'f20'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<(missing const) U20<[...]>>' to 'vector<const U20<[...]>>' for 1st argument 
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'f20'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<(missing const) U20<int>>' to 'vector<const U20<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'f20'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE:    vector<
+// CHECK-ELIDE-TREE:      [(no qualifiers) != const] U20<
+// CHECK-ELIDE-TREE:        [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'f20'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE:    vector<
+// CHECK-NOELIDE-TREE:      [(no qualifiers) != const] U20<
+// CHECK-NOELIDE-TREE:        int>>
+
+// Checks that volatile does not show up in diagnostics.
+template<typename T> struct S21 {};
+template<typename T> using U21 = volatile S21<T>;
+int f21(vector<volatile const U21<int>>);
+int k21 = f21(vector<volatile U21<int>>());
+// CHECK-ELIDE-NOTREE: no matching function for call to 'f21'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<(missing const) U21<[...]>>' to 'vector<const U21<[...]>>' for 1st argument 
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'f21'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<(missing const) U21<int>>' to 'vector<const U21<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'f21'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE:    vector<
+// CHECK-ELIDE-TREE:      [(no qualifiers) != const] U21<
+// CHECK-ELIDE-TREE:        [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'f21'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE:    vector<
+// CHECK-NOELIDE-TREE:      [(no qualifiers) != const] U21<
+// CHECK-NOELIDE-TREE:        int>>
+
+
 // CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.
 // CHECK-NOELIDE-NOTREE: {{[0-9]*}} errors generated.
 // CHECK-ELIDE-TREE: {{[0-9]*}} errors generated.
Index: lib/AST/ASTDiagnostic.cpp
===================================================================
--- lib/AST/ASTDiagnostic.cpp	(revision 162297)
+++ lib/AST/ASTDiagnostic.cpp	(working copy)
@@ -430,6 +430,9 @@
       /// arguments or the type arguments that are templates.
       TemplateDecl *FromTD, *ToTD;
 
+      /// FromQual, ToQual - Qualifiers for template types.
+      Qualifiers FromQual, ToQual;
+
       /// FromDefault, ToDefault - Whether the argument is a default argument.
       bool FromDefault, ToDefault;
 
@@ -480,6 +483,12 @@
       FlatTree[CurrentNode].ToExpr = ToExpr;
     }
 
+    /// SetNode - Set FromQual and ToQual of the current node.
+    void SetNode(Qualifiers FromQual, Qualifiers ToQual) {
+      FlatTree[CurrentNode].FromQual = FromQual;
+      FlatTree[CurrentNode].ToQual = ToQual;
+    }
+
     /// SetSame - Sets the same flag of the current node.
     void SetSame(bool Same) {
       FlatTree[CurrentNode].Same = Same;
@@ -575,6 +584,12 @@
       ToTD = FlatTree[ReadNode].ToTD;
     }
 
+    /// GetNode - Gets the FromQual and ToQual.
+    void GetNode(Qualifiers &FromQual, Qualifiers &ToQual) {
+      FromQual = FlatTree[ReadNode].FromQual;
+      ToQual = FlatTree[ReadNode].ToQual;
+    }
+
     /// NodeIsSame - Returns true the arguments are the same.
     bool NodeIsSame() {
       return FlatTree[ReadNode].Same;
@@ -778,17 +793,19 @@
           if (Context.hasSameType(FromType, ToType)) {
             Tree.SetSame(true);
           } else {
-            const TemplateSpecializationType *FromArgTST =
-                GetTemplateSpecializationType(Context, FromType);
-            const TemplateSpecializationType *ToArgTST =
-                GetTemplateSpecializationType(Context, ToType);
-
-            if (FromArgTST && ToArgTST) {
-              bool SameTemplate = hasSameTemplate(FromArgTST, ToArgTST);
-              if (SameTemplate) {
-                Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
-                             ToArgTST->getTemplateName().getAsTemplateDecl());
-                DiffTemplate(FromArgTST, ToArgTST);
+            Qualifiers FromQual, ToQual;
+            bool SameTemplate = hasSameTemplate(Context, FromType, ToType,
+                                                FromQual, ToQual);
+            if (SameTemplate) {
+              const TemplateSpecializationType *FromArgTST =
+                  GetTemplateSpecializationType(Context, FromType);
+              const TemplateSpecializationType *ToArgTST =
+                  GetTemplateSpecializationType(Context, ToType);
+              if (FromArgTST && ToArgTST) {
+              Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
+                           ToArgTST->getTemplateName().getAsTemplateDecl());
+              Tree.SetNode(FromQual, ToQual);
+              DiffTemplate(FromArgTST, ToArgTST);
               }
             }
           }
@@ -824,62 +841,120 @@
     }
   }
 
+  static void RemoveQualifiers(Qualifiers &Qual, Qualifiers RemoveQual) {
+    if (Qual.hasConst() && RemoveQual.hasConst())
+      Qual.removeConst();
+
+    if (Qual.hasVolatile() && RemoveQual.hasVolatile())
+      Qual.removeVolatile();
+
+    if (Qual.hasRestrict() && RemoveQual.hasRestrict())
+      Qual.removeRestrict();
+
+    if (Qual.getObjCGCAttr() == RemoveQual.getObjCGCAttr())
+      Qual.removeObjCGCAttr();
+
+    if (Qual.getObjCLifetime() == RemoveQual.getObjCLifetime())
+      Qual.removeObjCLifetime();
+
+    if (Qual.getAddressSpace() == RemoveQual.getAddressSpace())
+      Qual.removeAddressSpace();
+  }
+
+  static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST,
+                                  const TemplateSpecializationType *ToTST) {
+    return FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==
+           ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier();
+  }
+
   /// hasSameTemplate - Returns true if both types are specialized from the
   /// same template declaration.  If they come from different template aliases,
   /// do a parallel ascension search to determine the highest template alias in
   /// common and set the arguments to them.
-  static bool hasSameTemplate(const TemplateSpecializationType *&FromTST,
-                              const TemplateSpecializationType *&ToTST) {
+  static bool hasSameTemplate(ASTContext &Context, QualType &FromType,
+                              QualType &ToType,
+                              Qualifiers &FromQual, Qualifiers &ToQual) {
+    const TemplateSpecializationType *FromTST =
+        GetTemplateSpecializationType(Context, FromType);
+    const TemplateSpecializationType *ToTST =
+        GetTemplateSpecializationType(Context, ToType);
+
+    if (!FromTST || !ToTST)
+      return false;
+
+    FromQual = FromType.getLocalQualifiers();
+    ToQual = ToType.getLocalQualifiers();
+
     // Check the top templates if they are the same.
-    if (FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==
-        ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier())
+    if (hasSameBaseTemplate(FromTST, ToTST)) {
+      RemoveQualifiers(FromQual,
+                       FromType.getLocalUnqualifiedType().getQualifiers());
+      RemoveQualifiers(ToQual,
+                       ToType.getLocalUnqualifiedType().getQualifiers());
       return true;
+    }
 
-    // Create vectors of template aliases.
-    SmallVector<const TemplateSpecializationType*, 1> FromTemplateList,
-                                                      ToTemplateList;
+    // Create vectors of template aliases and types.
+    typedef SmallVector<std::pair<const TemplateSpecializationType*,
+                                  QualType>, 1>
+        TemplateInfoVector;
+    TemplateInfoVector FromTemplateList, ToTemplateList;
 
-    const TemplateSpecializationType *TempToTST = ToTST, *TempFromTST = FromTST;
-    FromTemplateList.push_back(FromTST);
-    ToTemplateList.push_back(ToTST);
+    const TemplateSpecializationType *TempTST;
+    QualType TempType;
+    FromTemplateList.push_back(std::make_pair(FromTST, FromType));
+    ToTemplateList.push_back(std::make_pair(ToTST, ToType));
 
-    // Dump every template alias into the vectors.
-    while (TempFromTST->isTypeAlias()) {
-      TempFromTST =
-          TempFromTST->getAliasedType()->getAs<TemplateSpecializationType>();
-      if (!TempFromTST)
+    // Dump every template alias and type into the vectors.
+    TempTST = FromTST;
+    while (TempTST->isTypeAlias()) {
+      TempType = TempTST->getAliasedType();
+      TempTST = TempType->getAs<TemplateSpecializationType>();
+      if (!TempTST)
         break;
-      FromTemplateList.push_back(TempFromTST);
+      FromTemplateList.push_back(std::make_pair(TempTST, TempType));
     }
-    while (TempToTST->isTypeAlias()) {
-      TempToTST =
-          TempToTST->getAliasedType()->getAs<TemplateSpecializationType>();
-      if (!TempToTST)
+
+    TempTST = ToTST;
+    while (TempTST->isTypeAlias()) {
+      TempType = TempTST->getAliasedType();
+      TempTST = TempType->getAs<TemplateSpecializationType>();
+      if (!TempTST)
         break;
-      ToTemplateList.push_back(TempToTST);
+      ToTemplateList.push_back(std::make_pair(TempTST, TempType));
     }
 
-    SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator
+    TemplateInfoVector::reverse_iterator
         FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(),
         ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();
 
     // Check if the lowest template types are the same.  If not, return.
-    if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() !=
-        (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier())
+    if (!hasSameBaseTemplate(FromIter->first, ToIter->first))
       return false;
 
     // Begin searching up the template aliases.  The bottom most template
     // matches so move up until one pair does not match.  Use the template
     // right before that one.
     for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) {
-      if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() !=
-          (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier())
+      if (!hasSameBaseTemplate(FromIter->first, ToIter->first))
         break;
     }
 
-    FromTST = FromIter[-1];
-    ToTST = ToIter[-1];
+    FromType = FromIter[-1].second;
+    ToType = ToIter[-1].second;
 
+    FromQual = FromType.getLocalQualifiers();
+    for (; FromIter != FromEnd; ++FromIter)
+      FromQual.addQualifiers(FromIter->second.getLocalQualifiers());
+    RemoveQualifiers(FromQual,
+                     FromType.getLocalUnqualifiedType().getQualifiers());
+
+    ToQual = ToType.getLocalQualifiers();
+    for (; ToIter != ToEnd; ++ToIter)
+      ToQual.addQualifiers(ToIter->second.getLocalQualifiers());
+    RemoveQualifiers(ToQual,
+                     ToType.getLocalUnqualifiedType().getQualifiers());
+
     return true;
   }
 
@@ -1027,6 +1102,10 @@
 
     assert(Tree.HasChildren() && "Template difference not found in diff tree.");
 
+    Qualifiers FromQual, ToQual;
+    Tree.GetNode(FromQual, ToQual);
+    PrintQualifiers(FromQual, ToQual);
+
     OS << FromTD->getNameAsString() << '<'; 
     Tree.MoveToChild();
     unsigned NumElideArgs = 0;
@@ -1191,6 +1270,118 @@
       OS << "[" << NumElideArgs << " * ...]";
   }
 
+  // Prints and highlights differences in Qualifiers.
+  void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) {
+    // Both types have no qualifiers
+    if (FromQual.empty() && ToQual.empty())
+      return;
+
+    // Both types have same qualifiers
+    if (FromQual == ToQual) {
+      FromQual.print(OS, Policy, /*appendSpaceIfNonEmpty*/true);
+      return;
+    }
+
+    // Find common and different qualifiers
+    Qualifiers CommonQual;
+    DiffQualifiers(FromQual, ToQual, CommonQual);
+
+    // The qualifiers are printed before the template name.
+    // Inline printing:
+    // The common qualifiers are printed.  Then, qualifiers only in this type
+    // are printed and highlighted.  Finally, qualifiers only in the other
+    // type are printed and highlighted inside parentheses after "missing".
+    // Tree printing:
+    // Qualifiers are printed next to each other, inside brackets, and
+    // separated by "!=".  The printing order is:
+    // common qualifiers, highlighted from qualifiers, "!=",
+    // common qualifiers, highlighted to qualifiers
+    if (PrintTree) {
+      OS << "[";
+      if (CommonQual.empty() && FromQual.empty()) {
+        Bold();
+        OS << "(no qualifiers) ";
+        Unbold();
+      } else {
+        CommonQual.print(OS, Policy, /*appendSpaceIfNonEmpty*/true);
+        if (!FromQual.empty()) {
+          Bold();
+          FromQual.print(OS, Policy, /*appendSpaceIfNonEmpty*/true);
+          Unbold();
+        }
+      }
+      OS << "!= ";
+      if (CommonQual.empty() && ToQual.empty()) {
+        Bold();
+        OS << "(no qualifiers)";
+        Unbold();
+      } else {
+        CommonQual.print(OS, Policy, /*appendSpaceIfNonEmpty*/true);
+        if (!ToQual.empty()) {
+          Bold();
+          ToQual.print(OS, Policy, /*appendSpaceIfNonEmpty*/false);
+          Unbold();
+        }
+      }
+      OS << "] ";
+    } else {
+      CommonQual.print(OS, Policy, /*appendSpaceIfNonEmpty*/true);
+      if (!FromQual.empty()) {
+        Bold();
+        FromQual.print(OS, Policy, /*appendSpaceIfNonEmpty*/true);
+        Unbold();
+      }
+      if (!ToQual.empty()) {
+        Bold();
+        OS << "(missing ";
+        ToQual.print(OS, Policy, /*appendSpaceIfNonEmpty*/false);
+        OS << ") ";
+        Unbold();
+      }
+    }
+  }
+
+  // Removes any common qualifiers from ToQual and FromQual and places them
+  // in CommonQual.
+  void DiffQualifiers(Qualifiers &FromQual, Qualifiers &ToQual,
+                      Qualifiers &CommonQual) {
+    if (FromQual.hasConst() && ToQual.hasConst()) {
+      CommonQual.addConst();
+      FromQual.removeConst();
+      ToQual.removeConst();
+    }
+
+    if (FromQual.hasVolatile() && ToQual.hasVolatile()) {
+      CommonQual.addVolatile();
+      FromQual.removeVolatile();
+      ToQual.removeVolatile();
+    }
+
+    if (FromQual.hasRestrict() && ToQual.hasRestrict()) {
+      CommonQual.addRestrict();
+      FromQual.removeRestrict();
+      ToQual.removeRestrict();
+    }
+
+    if (FromQual.getObjCGCAttr() == ToQual.getObjCGCAttr()) {
+      CommonQual.setObjCGCAttr(FromQual.getObjCGCAttr());
+      FromQual.removeObjCGCAttr();
+      ToQual.removeObjCGCAttr();
+    }
+
+    if (FromQual.getObjCLifetime() == ToQual.getObjCLifetime()) {
+      CommonQual.setObjCLifetime(FromQual.getObjCLifetime());
+      FromQual.removeObjCLifetime();
+      ToQual.removeObjCLifetime();
+    }
+
+    if (FromQual.getAddressSpace() == ToQual.getAddressSpace()) {
+      CommonQual.setAddressSpace(FromQual.getAddressSpace());
+      FromQual.removeAddressSpace();
+      ToQual.removeAddressSpace();
+    }
+  }
+
 public:
 
   TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType,
@@ -1210,22 +1401,22 @@
 
   /// DiffTemplate - Start the template type diffing.
   void DiffTemplate() {
-    const TemplateSpecializationType *FromOrigTST =
-        GetTemplateSpecializationType(Context, FromType);
-    const TemplateSpecializationType *ToOrigTST =
-        GetTemplateSpecializationType(Context, ToType);
+    // These will be updated by hasSameTemplate.
+    QualType FromTemplateType = FromType, ToTemplateType = ToType;
+    Qualifiers FromQual, ToQual;
 
-    // Only checking templates.
-    if (!FromOrigTST || !ToOrigTST)
+    if (!hasSameTemplate(Context, FromType, ToType, FromQual, ToQual)) {
       return;
-
-    // Different base templates.
-    if (!hasSameTemplate(FromOrigTST, ToOrigTST)) {
-      return;
     }
 
     Tree.SetNode(FromType, ToType);
+    Tree.SetNode(FromQual, ToQual);
 
+    const TemplateSpecializationType *FromOrigTST =
+        GetTemplateSpecializationType(Context, FromType);
+    const TemplateSpecializationType *ToOrigTST =
+        GetTemplateSpecializationType(Context, ToType);
+
     // Same base template, but different arguments.
     Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),
                  ToOrigTST->getTemplateName().getAsTemplateDecl());
