[clang] [clang] NNS: don't print trailing scope resolution operator in diagnostics (PR #130529)

Matheus Izvekov via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 10 04:25:22 PDT 2025


https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/130529

>From 87d712f87890d0a4fb4e782170e879b8397b4f69 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Fri, 7 Mar 2025 10:32:05 -0300
Subject: [PATCH] [clang] NNS: don't print trailing scope resolution operator

This clears up the printing of a NestedNameSpecifier so
a trailing '::' is not printed, unless it refers into the
global scope.

This fixes a bunch of diagnostics where the trailing :: was awkward.
This also prints the NNS quoted consistenty.

There is a drive-by improvement to error recovery, where now
we print the actual type instead of '<dependent type>'.

This will clear up further uses of NNS printing in further patches.
---
 clang/include/clang/AST/NestedNameSpecifier.h |  3 +-
 .../clang/Basic/DiagnosticSemaKinds.td        | 76 ++++++++++---------
 clang/lib/AST/ASTDiagnostic.cpp               |  5 +-
 clang/lib/AST/NestedNameSpecifier.cpp         |  9 ++-
 clang/lib/Sema/SemaDecl.cpp                   |  8 +-
 clang/lib/Sema/SemaExpr.cpp                   | 34 +++++----
 clang/lib/Sema/SemaTemplate.cpp               | 17 +++--
 .../basic.lookup.qual/class.qual/p2.cpp       |  2 +-
 .../CXX/class.access/class.access.dcl/p1.cpp  |  2 +-
 .../class.access/class.friend/p3-cxx0x.cpp    |  2 +-
 .../test/CXX/class.access/class.friend/p6.cpp |  8 +-
 .../basic.namespace/namespace.udecl/p3.cpp    | 10 +--
 .../basic.namespace/namespace.udecl/p4.cpp    |  2 +-
 clang/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp |  4 +-
 clang/test/CXX/drs/cwg14xx.cpp                |  4 +-
 clang/test/CXX/drs/cwg18xx.cpp                | 28 +++----
 clang/test/CXX/drs/cwg19xx.cpp                |  8 +-
 clang/test/CXX/drs/cwg1xx.cpp                 |  4 +-
 clang/test/CXX/drs/cwg28xx.cpp                |  2 +-
 clang/test/CXX/drs/cwg2xx.cpp                 | 20 ++---
 clang/test/CXX/drs/cwg3xx.cpp                 |  4 +-
 clang/test/CXX/drs/cwg4xx.cpp                 |  2 +-
 clang/test/CXX/drs/cwg5xx.cpp                 |  6 +-
 clang/test/CXX/drs/cwg6xx.cpp                 | 12 +--
 .../CXX/special/class.inhctor/elsewhere.cpp   |  4 +-
 clang/test/CXX/temp/temp.res/temp.dep/p3.cpp  | 22 +++---
 clang/test/Parser/cxx-attributes.cpp          |  2 +-
 clang/test/Parser/cxx2c-variadic-friends.cpp  |  4 +-
 clang/test/SemaCXX/PR62533.cpp                |  6 +-
 .../SemaCXX/cxx0x-defaulted-functions.cpp     |  4 +-
 .../SemaCXX/cxx11-user-defined-literals.cpp   | 12 +--
 .../test/SemaCXX/pr25181-crash-on-invalid.cpp |  2 +-
 clang/test/SemaCXX/pr36536.cpp                |  4 +-
 clang/test/SemaCXX/using-decl-templates.cpp   |  8 +-
 clang/test/SemaObjCXX/propert-dot-error.mm    |  4 +-
 clang/test/SemaTemplate/friend-template.cpp   | 10 +--
 .../ms-sizeof-missing-typename.cpp            |  2 +-
 clang/test/SemaTemplate/nested-template.cpp   |  2 +-
 clang/test/SemaTemplate/qualified-id.cpp      |  8 +-
 clang/test/SemaTemplate/template-id-expr.cpp  | 20 ++---
 .../SemaTemplate/typename-specifier-3.cpp     |  2 +-
 41 files changed, 203 insertions(+), 185 deletions(-)

diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h
index a1d9e30e660d1..051d632f1cdf9 100644
--- a/clang/include/clang/AST/NestedNameSpecifier.h
+++ b/clang/include/clang/AST/NestedNameSpecifier.h
@@ -223,7 +223,8 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
   /// `ns::SomeTemplate<int, MyClass>` instead of
   /// `ns::SomeTemplate<Container::value_type, T>`.
   void print(raw_ostream &OS, const PrintingPolicy &Policy,
-             bool ResolveTemplateArguments = false) const;
+             bool ResolveTemplateArguments = false,
+             bool PrintFinalScopeResOp = true) const;
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
     ID.AddPointer(Prefix.getOpaqueValue());
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 239f16769ace9..eeb7e236e8b7a 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -599,16 +599,17 @@ def err_using_typename_non_type : Error<
   "'typename' keyword used on a non-type">;
 def err_using_dependent_value_is_type : Error<
   "dependent using declaration resolved to type without 'typename'">;
-def err_using_decl_nested_name_specifier_is_not_class : Error<
-  "using declaration in class refers into '%0', which is not a class">;
+def err_using_decl_nested_name_specifier_is_not_class
+    : Error<"using declaration in class refers into %0, which is not a class">;
 def warn_cxx17_compat_using_decl_non_member_enumerator : Warning<
   "member using declaration naming non-class '%0' enumerator is "
   "incompatible with C++ standards before C++20">, InGroup<CXXPre20Compat>,
   DefaultIgnore;
 def err_using_decl_nested_name_specifier_is_current_class : Error<
   "using declaration refers to its own class">;
-def err_using_decl_nested_name_specifier_is_not_base_class : Error<
-  "using declaration refers into '%0', which is not a base class of %1">;
+def err_using_decl_nested_name_specifier_is_not_base_class
+    : Error<
+          "using declaration refers into %0, which is not a base class of %1">;
 def err_using_decl_constructor_not_in_direct_base : Error<
   "%0 is not a direct base of %1, cannot inherit constructors">;
 def err_using_decl_can_not_refer_to_class_member : Error<
@@ -1733,8 +1734,8 @@ def err_no_matching_local_friend_suggest : Error<
   "cannot define friend function %0 in a local class definition; did you mean %3?">;
 def err_partial_specialization_friend : Error<
   "partial specialization cannot be declared as a friend">;
-def err_qualified_friend_def : Error<
-  "friend function definition cannot be qualified with '%0'">;
+def err_qualified_friend_def
+    : Error<"friend function definition cannot be qualified with %0">;
 def err_friend_def_in_local_class : Error<
   "friend function cannot be defined in a local class">;
 def err_friend_specialization_def : Error<
@@ -1743,14 +1744,16 @@ def err_friend_not_first_in_declaration : Error<
   "'friend' must appear first in a non-function declaration">;
 def err_using_decl_friend : Error<
   "cannot befriend target of using declaration">;
-def warn_template_qualified_friend_unsupported : Warning<
-  "dependent nested name specifier '%0' for friend class declaration is "
-  "not supported; turning off access control for %1">,
-  InGroup<UnsupportedFriend>;
-def warn_template_qualified_friend_ignored : Warning<
-  "dependent nested name specifier '%0' for friend template declaration is "
-  "not supported; ignoring this friend declaration">,
-  InGroup<UnsupportedFriend>;
+def warn_template_qualified_friend_unsupported
+    : Warning<
+          "dependent nested name specifier %0 for friend class declaration is "
+          "not supported; turning off access control for %1">,
+      InGroup<UnsupportedFriend>;
+def warn_template_qualified_friend_ignored
+    : Warning<"dependent nested name specifier %0 for friend template "
+              "declaration is "
+              "not supported; ignoring this friend declaration">,
+      InGroup<UnsupportedFriend>;
 def ext_friend_tag_redecl_outside_namespace : ExtWarn<
   "unqualified friend declaration referring to type outside of the nearest "
   "enclosing namespace is a Microsoft extension; add a nested name specifier">,
@@ -5556,9 +5559,10 @@ def ext_template_spec_extra_headers : ExtWarn<
 def note_explicit_template_spec_does_not_need_header : Note<
   "'template<>' header not required for explicitly-specialized class %0 "
   "declared here">;
-def err_template_qualified_declarator_no_match : Error<
-  "nested name specifier '%0' for declaration does not refer into a class, "
-  "class template or class template partial specialization">;
+def err_template_qualified_declarator_no_match
+    : Error<"nested name specifier %0 for declaration does not refer into a "
+            "class, "
+            "class template or class template partial specialization">;
 def err_specialize_member_of_template : Error<
   "cannot specialize %select{|(with 'template<>') }0a member of an "
   "unspecialized template">;
@@ -5858,13 +5862,13 @@ def note_typename_member_refers_here : Note<
     "referenced member %0 is declared here">;
 def note_typename_refers_here : Note<
     "referenced %0 is declared here">;
-def err_typename_missing : Error<
-  "missing 'typename' prior to dependent type name '%0%1'">;
-def err_typename_missing_template : Error<
-  "missing 'typename' prior to dependent type template name '%0%1'">;
-def ext_typename_missing : ExtWarn<
-  "missing 'typename' prior to dependent type name '%0%1'">,
-  InGroup<DiagGroup<"typename-missing">>;
+def err_typename_missing
+    : Error<"missing 'typename' prior to dependent type name %0">;
+def err_typename_missing_template
+    : Error<"missing 'typename' prior to dependent type template name %0">;
+def ext_typename_missing
+    : ExtWarn<"missing 'typename' prior to dependent type name %0">,
+      InGroup<DiagGroup<"typename-missing">>;
 def ext_typename_outside_of_template : ExtWarn<
   "'typename' occurs outside of a template">, InGroup<CXX11>;
 def warn_cxx98_compat_typename_outside_of_template : Warning<
@@ -5878,9 +5882,10 @@ def note_using_value_decl_missing_typename : Note<
 def warn_cxx17_compat_implicit_typename : Warning<"use of implicit 'typename' is "
   "incompatible with C++ standards before C++20">, InGroup<CXX20Compat>,
   DefaultIgnore;
-def ext_implicit_typename : ExtWarn<"missing 'typename' prior to dependent "
-  "type name %0%1; implicit 'typename' is a C++20 extension">,
-  InGroup<CXX20>;
+def ext_implicit_typename
+    : ExtWarn<"missing 'typename' prior to dependent "
+              "type name %0; implicit 'typename' is a C++20 extension">,
+      InGroup<CXX20>;
 
 def err_template_kw_refers_to_non_template : Error<
   "%0%select{| following the 'template' keyword}1 "
@@ -5890,12 +5895,13 @@ def note_template_kw_refers_to_non_template : Note<
 def err_template_kw_refers_to_dependent_non_template : Error<
   "%0%select{| following the 'template' keyword}1 "
   "cannot refer to a dependent template">;
-def err_template_kw_refers_to_type_template : Error<
-  "'%0%1' is expected to be a non-type template, but instantiated to a %select{class|type alias}2 template">;
+def err_template_kw_refers_to_type_template
+    : Error<"%0 is expected to be a non-type template, but instantiated to a "
+            "%select{class|type alias}1 template">;
 def note_referenced_type_template : Note<
   "%select{class|type alias}0 template declared here">;
-def err_template_kw_missing : Error<
-  "missing 'template' keyword prior to dependent template name '%0%1'">;
+def err_template_kw_missing
+    : Error<"missing 'template' keyword prior to dependent template name %0">;
 def ext_template_outside_of_template : ExtWarn<
   "'template' keyword outside of a template">, InGroup<CXX11>;
 def warn_cxx98_compat_template_outside_of_template : Warning<
@@ -7888,8 +7894,8 @@ def err_nogetter_property_incdec : Error<
   "no getter method %1 for %select{increment|decrement}0 of property">;
 def err_no_subobject_property_setting : Error<
   "expression is not assignable">;
-def err_qualified_objc_access : Error<
-  "%select{property|instance variable}0 access cannot be qualified with '%1'">;
+def err_qualified_objc_access : Error<"%select{property|instance variable}0 "
+                                      "access cannot be qualified with %1">;
 
 def ext_freestanding_complex : Extension<
   "complex numbers are an extension in a freestanding C99 implementation">;
@@ -9839,8 +9845,8 @@ def note_non_usual_function_declared_here : Note<
 // C++ literal operators
 def err_literal_operator_outside_namespace : Error<
   "literal operator %0 must be in a namespace or global scope">;
-def err_literal_operator_id_outside_namespace : Error<
-  "non-namespace scope '%0' cannot have a literal operator member">;
+def err_literal_operator_id_outside_namespace
+    : Error<"non-namespace scope %0 cannot have a literal operator member">;
 def err_literal_operator_default_argument : Error<
   "literal operator cannot have a default argument">;
 def err_literal_operator_bad_param_count : Error<
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 7b873ee9833b3..b4e7360e126fb 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -461,8 +461,9 @@ void clang::FormatASTNodeDiagnosticArgument(
     }
     case DiagnosticsEngine::ak_nestednamespec: {
       NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val);
-      NNS->print(OS, Context.getPrintingPolicy());
-      NeedQuotes = false;
+      NNS->print(OS, Context.getPrintingPolicy(),
+                 /*ResolveTemplateArguments=*/false,
+                 /*PrintFinalScopeResOp=*/false);
       break;
     }
     case DiagnosticsEngine::ak_declcontext: {
diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp
index 76c77569da9fd..593f2fcc0159c 100644
--- a/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/clang/lib/AST/NestedNameSpecifier.cpp
@@ -248,7 +248,8 @@ bool NestedNameSpecifier::containsErrors() const {
 /// Print this nested name specifier to the given output
 /// stream.
 void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
-                                bool ResolveTemplateArguments) const {
+                                bool ResolveTemplateArguments,
+                                bool PrintFinalScopeResOp) const {
   if (getPrefix())
     getPrefix()->print(OS, Policy);
 
@@ -269,7 +270,8 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
     break;
 
   case Global:
-    break;
+    OS << "::";
+    return;
 
   case Super:
     OS << "__super";
@@ -331,7 +333,8 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
   }
   }
 
-  OS << "::";
+  if (PrintFinalScopeResOp)
+    OS << "::";
 }
 
 LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 5716eb61d4ae8..5ae3e58e4088d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -351,7 +351,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
             Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename);
           else
             Diag(QualifiedLoc, diag::ext_implicit_typename)
-                << SS->getScopeRep() << II.getName()
+                << NestedNameSpecifier::Create(Context, SS->getScopeRep(), &II)
                 << FixItHint::CreateInsertion(QualifiedLoc, "typename ");
         }
 
@@ -795,9 +795,9 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
       DiagID = diag::ext_typename_missing;
 
     Diag(SS->getRange().getBegin(), DiagID)
-      << SS->getScopeRep() << II->getName()
-      << SourceRange(SS->getRange().getBegin(), IILoc)
-      << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
+        << NestedNameSpecifier::Create(Context, SS->getScopeRep(), II)
+        << SourceRange(SS->getRange().getBegin(), IILoc)
+        << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
     SuggestedType = ActOnTypenameType(S, SourceLocation(),
                                       *SS, *II, IILoc).get();
   } else {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index de7be6b2805af..a36a2f563739e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2940,6 +2940,9 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
   }
 
   if (const TypeDecl *TD = R.getAsSingle<TypeDecl>()) {
+    QualType Ty = Context.getTypeDeclType(TD);
+    QualType ET = getElaboratedType(ElaboratedTypeKeyword::None, SS, Ty);
+
     // Diagnose a missing typename if this resolved unambiguously to a type in
     // a dependent context.  If we can recover with a type, downgrade this to
     // a warning in Microsoft compatibility mode.
@@ -2948,8 +2951,7 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
       DiagID = diag::ext_typename_missing;
     SourceLocation Loc = SS.getBeginLoc();
     auto D = Diag(Loc, DiagID);
-    D << SS.getScopeRep() << NameInfo.getName().getAsString()
-      << SourceRange(Loc, NameInfo.getEndLoc());
+    D << ET << SourceRange(Loc, NameInfo.getEndLoc());
 
     // Don't recover if the caller isn't expecting us to or if we're in a SFINAE
     // context.
@@ -2960,11 +2962,9 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
     D << FixItHint::CreateInsertion(Loc, "typename ");
 
     // Recover by pretending this was an elaborated type.
-    QualType Ty = Context.getTypeDeclType(TD);
     TypeLocBuilder TLB;
     TLB.pushTypeSpec(Ty).setNameLoc(NameInfo.getLoc());
 
-    QualType ET = getElaboratedType(ElaboratedTypeKeyword::None, SS, Ty);
     ElaboratedTypeLoc QTL = TLB.push<ElaboratedTypeLoc>(ET);
     QTL.setElaboratedKeywordLoc(SourceLocation());
     QTL.setQualifierLoc(SS.getWithLocInContext(Context));
@@ -15433,7 +15433,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
         Diag(OE->getQualifier() ? OE->getQualifierLoc().getBeginLoc()
                                 : OE->getNameLoc(),
              diag::err_template_kw_missing)
-          << OE->getName().getAsString() << "";
+            << OE->getName().getAsIdentifierInfo();
         return ExprError();
       }
     }
@@ -21025,18 +21025,24 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
     NamedDecl *Temp = *ULE->decls_begin();
     const bool IsTypeAliasTemplateDecl = isa<TypeAliasTemplateDecl>(Temp);
 
-    if (NestedNameSpecifierLoc Loc = ULE->getQualifierLoc(); Loc.hasQualifier())
-      Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
-          << Loc.getNestedNameSpecifier() << NameInfo.getName().getAsString()
-          << Loc.getSourceRange() << IsTypeAliasTemplateDecl;
-    else
-      Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
-          << "" << NameInfo.getName().getAsString() << ULE->getSourceRange()
-          << IsTypeAliasTemplateDecl;
+    NestedNameSpecifier *NNS = ULE->getQualifierLoc().getNestedNameSpecifier();
+    TemplateName TN(dyn_cast<TemplateDecl>(Temp));
+    if (TN.isNull())
+      TN = Context.getAssumedTemplateName(NameInfo.getName());
+    TN = Context.getQualifiedTemplateName(NNS,
+                                          /*TemplateKeyword=*/true, TN);
+
+    Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
+        << TN << ULE->getSourceRange() << IsTypeAliasTemplateDecl;
     Diag(Temp->getLocation(), diag::note_referenced_type_template)
         << IsTypeAliasTemplateDecl;
 
-    return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
+    QualType TST =
+        Context.getTemplateSpecializationType(TN, ULE->template_arguments());
+    QualType ET =
+        Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST);
+    return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {},
+                              ET);
   }
 
   // Overloaded expressions.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 7ffcef1592a93..96f3ceb9ef8f5 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -363,12 +363,12 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
 
   // The code is missing a 'template' keyword prior to the dependent template
   // name.
-  NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep();
-  Diag(IILoc, diag::err_template_kw_missing)
-    << Qualifier << II.getName()
-    << FixItHint::CreateInsertion(IILoc, "template ");
+  NestedNameSpecifier *Qualifier = (NestedNameSpecifier *)SS->getScopeRep();
   SuggestedTemplate
     = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II));
+  Diag(IILoc, diag::err_template_kw_missing)
+      << SuggestedTemplate.get()
+      << FixItHint::CreateInsertion(IILoc, "template ");
   SuggestedKind = TNK_Dependent_template_name;
   return true;
 }
@@ -660,7 +660,7 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
   // was missing.
   if (MissingTemplateKeyword) {
     Diag(NameInfo.getBeginLoc(), diag::err_template_kw_missing)
-        << "" << NameInfo.getName().getAsString() << SourceRange(Less, Greater);
+        << NameInfo.getName() << SourceRange(Less, Greater);
     return;
   }
 
@@ -3762,16 +3762,17 @@ TypeResult Sema::ActOnTemplateIdType(
     //   elaborated-type-specifier (7.1.5.3).
     if (!LookupCtx && isDependentScopeSpecifier(SS)) {
       // C++2a relaxes some of those restrictions in [temp.res]p5.
+      NestedNameSpecifier *NNS =
+          NestedNameSpecifier::Create(Context, SS.getScopeRep(), TemplateII);
       if (AllowImplicitTypename == ImplicitTypenameContext::Yes) {
         if (getLangOpts().CPlusPlus20)
           Diag(SS.getBeginLoc(), diag::warn_cxx17_compat_implicit_typename);
         else
           Diag(SS.getBeginLoc(), diag::ext_implicit_typename)
-              << SS.getScopeRep() << TemplateII->getName()
+              << NNS
               << FixItHint::CreateInsertion(SS.getBeginLoc(), "typename ");
       } else
-        Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
-            << SS.getScopeRep() << TemplateII->getName();
+        Diag(SS.getBeginLoc(), diag::err_typename_missing_template) << NNS;
 
       // FIXME: This is not quite correct recovery as we don't transform SS
       // into the corresponding dependent form (and we don't diagnose missing
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
index 0fa98ad101f6c..5c281ac806836 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
@@ -190,7 +190,7 @@ namespace InhCtor {
   }
   struct DerivedFromNS : NS::NS {
     // No special case unless the NNS names a class.
-    using InhCtor::NS::NS; // expected-error {{using declaration in class refers into 'InhCtor::NS::', which is not a class}}
+    using InhCtor::NS::NS; // expected-error {{using declaration in class refers into 'InhCtor::NS', which is not a class}}
 
   };
 
diff --git a/clang/test/CXX/class.access/class.access.dcl/p1.cpp b/clang/test/CXX/class.access/class.access.dcl/p1.cpp
index 118ab9e52d0a1..fdb1373dd9b12 100644
--- a/clang/test/CXX/class.access/class.access.dcl/p1.cpp
+++ b/clang/test/CXX/class.access/class.access.dcl/p1.cpp
@@ -331,7 +331,7 @@ namespace test4 {
     // expected-warning at -2 {{access declarations are deprecated; use using declarations instead}}
 #else
     // expected-error at -4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
-    // expected-error at -5 {{using declaration refers into 'Subclass::', which is not a base class of 'C'}}
+    // expected-error at -5 {{using declaration refers into 'Subclass', which is not a base class of 'C'}}
 #endif
 
     int bar();
diff --git a/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp
index 9aabdbe540a66..f7216ea7eb7b0 100644
--- a/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ b/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -36,7 +36,7 @@ class A {
 public:
   class foo {};
   static int y;
-  template <typename S> friend class B<S>::ty; // expected-warning {{dependent nested name specifier 'B<S>::' for friend class declaration is not supported}}
+  template <typename S> friend class B<S>::ty; // expected-warning {{dependent nested name specifier 'B<S>' for friend class declaration is not supported}}
 };
 
 template<typename T> class B { typedef int ty; };
diff --git a/clang/test/CXX/class.access/class.friend/p6.cpp b/clang/test/CXX/class.access/class.friend/p6.cpp
index 47104e29dc6b3..da6d212b78868 100644
--- a/clang/test/CXX/class.access/class.friend/p6.cpp
+++ b/clang/test/CXX/class.access/class.friend/p6.cpp
@@ -8,11 +8,11 @@ struct X {
 
 struct Y {
   friend void ::f1() { } // expected-error{{friend function definition cannot be qualified with '::'}}
-  friend void X::f2() { } // expected-error{{friend function definition cannot be qualified with 'X::'}}
+  friend void X::f2() { } // expected-error{{friend function definition cannot be qualified with 'X'}}
 };
 
 template <typename T> struct Z {
-  friend void T::f() {} // expected-error{{friend function definition cannot be qualified with 'T::'}}
+  friend void T::f() {} // expected-error{{friend function definition cannot be qualified with 'T'}}
 };
 
 void local() {
@@ -32,6 +32,6 @@ namespace N {
 template<typename T> struct A {
   friend void f3(T) {}
   friend void f3<T>(T) {} // expected-error{{friend function specialization cannot be defined}}
-  friend void N::f4(T) {} // expected-error{{friend function definition cannot be qualified with 'N::'}}
-  friend void N::f4<T>(T) {} // expected-error{{friend function definition cannot be qualified with 'N::'}}
+  friend void N::f4(T) {} // expected-error{{friend function definition cannot be qualified with 'N'}}
+  friend void N::f4<T>(T) {} // expected-error{{friend function definition cannot be qualified with 'N'}}
 };
diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
index 3351666525374..657695657e0f7 100644
--- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
+++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
@@ -28,7 +28,7 @@ class D2 : public B {
   using B::E;
   using B::e;
   using B::x;
-  using C::g; // expected-error{{using declaration refers into 'C::', which is not a base class of 'D2'}}
+  using C::g; // expected-error{{using declaration refers into 'C', which is not a base class of 'D2'}}
 
   // These are valid in C++98 but not in C++11.
   using D::f2;
@@ -36,10 +36,10 @@ class D2 : public B {
   using D::e2;
   using D::x2;
 #if __cplusplus >= 201103L
-  // expected-error at -5 {{using declaration refers into 'D::', which is not a base class of 'D2'}}
-  // expected-error at -5 {{using declaration refers into 'D::', which is not a base class of 'D2'}}
-  // expected-error at -5 {{using declaration refers into 'D::', which is not a base class of 'D2'}}
-  // expected-error at -5 {{using declaration refers into 'D::', which is not a base class of 'D2'}}
+  // expected-error at -5 {{using declaration refers into 'D', which is not a base class of 'D2'}}
+  // expected-error at -5 {{using declaration refers into 'D', which is not a base class of 'D2'}}
+  // expected-error at -5 {{using declaration refers into 'D', which is not a base class of 'D2'}}
+  // expected-error at -5 {{using declaration refers into 'D', which is not a base class of 'D2'}}
 #endif
 
   using B::EC;
diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
index 65ccb751b9aa5..973cd77279f19 100644
--- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
+++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
@@ -210,7 +210,7 @@ namespace test4 {
     using Subclass::foo; // legal in C++03
 #if __cplusplus >= 201103L
     // expected-error at -3 {{refers to its own class}}
-    // expected-error at -3 {{refers into 'Subclass::', which is not a base class}}
+    // expected-error at -3 {{refers into 'Subclass', which is not a base class}}
 #endif
 
     int bar();
diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
index 13be079a40bc3..4475bd787c74d 100644
--- a/clang/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
@@ -18,9 +18,9 @@ class tfoo {
 };
 
 template<typename T>
-int decltype(tfoo<T>())::i; // expected-error{{nested name specifier 'decltype(tfoo<T>())::' for declaration does not refer into a class, class template or class template partial specialization}}
+int decltype(tfoo<T>())::i; // expected-error{{nested name specifier 'decltype(tfoo<T>())' for declaration does not refer into a class, class template or class template partial specialization}}
 template<typename T>
-void decltype(tfoo<T>())::func() { // expected-error{{nested name specifier 'decltype(tfoo<T>())::' for declaration does not refer into a class, class template or class template partial specialization}}
+void decltype(tfoo<T>())::func() { // expected-error{{nested name specifier 'decltype(tfoo<T>())' for declaration does not refer into a class, class template or class template partial specialization}}
 }
 
 // An init-declarator named with a qualified-id can refer to an element of the
diff --git a/clang/test/CXX/drs/cwg14xx.cpp b/clang/test/CXX/drs/cwg14xx.cpp
index 759a402b5f9d6..26febd9715184 100644
--- a/clang/test/CXX/drs/cwg14xx.cpp
+++ b/clang/test/CXX/drs/cwg14xx.cpp
@@ -660,14 +660,14 @@ namespace cwg1487 { // cwg1487: 3.3
 struct A { // #cwg1482-A
   struct B {
     using A::A;
-    // since-cxx11-error at -1 {{using declaration refers into 'A::', which is not a base class of 'B'}}
+    // since-cxx11-error at -1 {{using declaration refers into 'A', which is not a base class of 'B'}}
   };
 
   struct C : A {
   // since-cxx11-error at -1 {{base class has incomplete type}}
   //   since-cxx11-note@#cwg1482-A {{definition of 'cwg1487::A' is not complete until the closing '}'}}
     using A::A;
-    // since-cxx11-error at -1 {{using declaration refers into 'A::', which is not a base class of 'C'}}
+    // since-cxx11-error at -1 {{using declaration refers into 'A', which is not a base class of 'C'}}
   };
 
   struct D;
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 626473f11d3ec..5b4551ba0143b 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -381,13 +381,13 @@ struct A {
   struct B {
     void e();
   };
-  
+
   void f();
-  
+
   struct D {
     void g();
   };
-  
+
   T h();
 
   template<T U>
@@ -399,13 +399,13 @@ struct A<int> {
   struct B {
     void e();
   };
-  
+
   int f();
-  
+
   struct D {
     void g();
   };
-  
+
   template<int U>
   int i();
 };
@@ -420,25 +420,25 @@ class C {
 
   template<class T>
   friend struct A<T>::B;
-  // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'C'}}
+  // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'C'}}
 
   template<class T>
   friend void A<T>::f();
-  // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'C'}}
+  // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'C'}}
 
   // FIXME: this is ill-formed, because A<T>​::​D does not end with a simple-template-id
   template<class T>
   friend void A<T>::D::g();
-  // expected-warning at -1 {{dependent nested name specifier 'A<T>::D::' for friend class declaration is not supported; turning off access control for 'C'}}
-  
+  // expected-warning at -1 {{dependent nested name specifier 'A<T>::D' for friend class declaration is not supported; turning off access control for 'C'}}
+
   template<class T>
   friend int *A<T*>::h();
-  // expected-warning at -1 {{dependent nested name specifier 'A<T *>::' for friend class declaration is not supported; turning off access control for 'C'}}
-  
+  // expected-warning at -1 {{dependent nested name specifier 'A<T *>' for friend class declaration is not supported; turning off access control for 'C'}}
+
   template<class T>
   template<T U>
   friend T A<T>::i();
-  // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'C'}}
+  // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'C'}}
 };
 
 C c;
@@ -451,7 +451,7 @@ template<class T>
 void A<T>::f() { (void)c.private_int; }
 int A<int>::f() { (void)c.private_int; return 0; }
 
-// FIXME: both definition of 'D::g' are not friends, so they don't have access to 'private_int' 
+// FIXME: both definition of 'D::g' are not friends, so they don't have access to 'private_int'
 template<class T>
 void A<T>::D::g() { (void)c.private_int; }
 void A<int>::D::g() { (void)c.private_int; }
diff --git a/clang/test/CXX/drs/cwg19xx.cpp b/clang/test/CXX/drs/cwg19xx.cpp
index 55a7c7cbba66f..15ad3921cb1be 100644
--- a/clang/test/CXX/drs/cwg19xx.cpp
+++ b/clang/test/CXX/drs/cwg19xx.cpp
@@ -18,7 +18,7 @@ struct A {
 };
 }
 int N::f() { return 0; }
-int N::g() { return 0; } 
+int N::g() { return 0; }
 // expected-error at -1 {{out-of-line definition of 'g' does not match any declaration in namespace 'cwg1900::N'}}
 } // namespace cwg1900
 
@@ -84,7 +84,7 @@ namespace cwg1909 { // cwg1909: 3.7
   };
   struct C {
     template<typename T> static int C;
-    // expected-error at -1 {{member 'C' has the same name as its class}} 
+    // expected-error at -1 {{member 'C' has the same name as its class}}
     // cxx98-11-error at -2 {{variable templates are a C++14 extension}}
   };
   struct D {
@@ -105,7 +105,7 @@ class X {
   // FIXME: this is ill-formed, because A<T>::B::C does not end with a simple-template-id
   template <typename T>
   friend class A<T>::B::C;
-  // expected-warning at -1 {{dependent nested name specifier 'A<T>::B::' for friend class declaration is not supported; turning off access control for 'X'}}
+  // expected-warning at -1 {{dependent nested name specifier 'A<T>::B' for friend class declaration is not supported; turning off access control for 'X'}}
 };
 template<> struct A<int> {
   typedef struct Q B;
@@ -170,7 +170,7 @@ class X {
   // FIXME: this is ill-formed, because A<T>::B::C does not end with a simple-template-id
   template <typename T>
   friend class A<T>::B::C;
-  // expected-warning at -1 {{dependent nested name specifier 'A<T>::B::' for friend class declaration is not supported; turning off access control for 'X'}}
+  // expected-warning at -1 {{dependent nested name specifier 'A<T>::B' for friend class declaration is not supported; turning off access control for 'X'}}
 };
 } // namespace cwg1945
 
diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp
index 15bcc20b7fa2a..4a5394be146bc 100644
--- a/clang/test/CXX/drs/cwg1xx.cpp
+++ b/clang/test/CXX/drs/cwg1xx.cpp
@@ -96,7 +96,7 @@ namespace cwg108 { // cwg108: 2.9
   template<typename T> struct A {
     struct B { typedef int X; };
     B::X x;
-    // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name B::X; implicit 'typename' is a C++20 extension}}
+    // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'B::X'; implicit 'typename' is a C++20 extension}}
     struct C : B { X x; };
     // expected-error at -1 {{unknown type name 'X'}}
   };
@@ -321,7 +321,7 @@ namespace cwg121 { // cwg121: 2.7
     X::Y<T> x;
     T::Y<T> y;
     // expected-error at -1 {{use 'template' keyword to treat 'Y' as a dependent template name}}
-    // cxx98-17-error at -2 {{missing 'typename' prior to dependent type name T::Y; implicit 'typename' is a C++20 extension}}
+    // cxx98-17-error at -2 {{missing 'typename' prior to dependent type name 'T::Y'; implicit 'typename' is a C++20 extension}}
   };
   Z<X> z;
 } // namespace cwg121
diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp
index caa9b0f1f5058..b32e649374893 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -150,7 +150,7 @@ struct A {
   // FIXME: The index of the pack-index-specifier is printed as a memory address in the diagnostic.
   template<typename U>
   friend struct Ts...[0]::C;
-  // since-cxx26-warning at -1 {{dependent nested name specifier 'Ts...[0]::' for friend template declaration is not supported; ignoring this friend declaration}}
+  // since-cxx26-warning at -1 {{dependent nested name specifier 'Ts...[0]' for friend template declaration is not supported; ignoring this friend declaration}}
 };
 
 #endif
diff --git a/clang/test/CXX/drs/cwg2xx.cpp b/clang/test/CXX/drs/cwg2xx.cpp
index 0d644bae78382..4f383aacd4532 100644
--- a/clang/test/CXX/drs/cwg2xx.cpp
+++ b/clang/test/CXX/drs/cwg2xx.cpp
@@ -426,7 +426,7 @@ namespace cwg224 { // cwg224: 16
       A::type a;
       A<T>::type b;
       A<T*>::type c;
-      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name A<T *>::type; implicit 'typename' is a C++20 extension}}
+      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'A<T *>::type'; implicit 'typename' is a C++20 extension}}
       ::cwg224::example1::A<T>::type d;
 
       class B {
@@ -435,13 +435,13 @@ namespace cwg224 { // cwg224: 16
         A::type a;
         A<T>::type b;
         A<T*>::type c;
-        // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name A<T *>::type; implicit 'typename' is a C++20 extension}}
+        // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'A<T *>::type'; implicit 'typename' is a C++20 extension}}
         ::cwg224::example1::A<T>::type d;
 
         B::type e;
         A<T>::B::type f;
         A<T*>::B::type g;
-        // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name A<T *>::B::type; implicit 'typename' is a C++20 extension}}
+        // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'A<T *>::B::type'; implicit 'typename' is a C++20 extension}}
         typename A<T*>::B::type h;
       };
     };
@@ -450,25 +450,25 @@ namespace cwg224 { // cwg224: 16
       typedef int type;
       A<T*>::type a;
       A<T>::type b;
-      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name A<T>::type; implicit 'typename' is a C++20 extension}}
+      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'A<T>::type'; implicit 'typename' is a C++20 extension}}
     };
 
     template <class T1, class T2, int I> struct B {
       typedef int type;
       B<T1, T2, I>::type b1;
       B<T2, T1, I>::type b2;
-      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name B<T2, T1, I>::type; implicit 'typename' is a C++20 extension}}
+      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'B<T2, T1, I>::type'; implicit 'typename' is a C++20 extension}}
 
       typedef T1 my_T1;
       static const int my_I = I;
       static const int my_I2 = I+0;
       static const int my_I3 = my_I;
       B<my_T1, T2, my_I>::type b3;
-      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name B<my_T1, T2, my_I>::type; implicit 'typename' is a C++20 extension}}
+      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I>::type'; implicit 'typename' is a C++20 extension}}
       B<my_T1, T2, my_I2>::type b4;
-      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name B<my_T1, T2, my_I2>::type; implicit 'typename' is a C++20 extension}}
+      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I2>::type'; implicit 'typename' is a C++20 extension}}
       B<my_T1, T2, my_I3>::type b5;
-      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name B<my_T1, T2, my_I3>::type; implicit 'typename' is a C++20 extension}}
+      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I3>::type'; implicit 'typename' is a C++20 extension}}
     };
   }
 
@@ -480,7 +480,7 @@ namespace cwg224 { // cwg224: 16
       X<A::i, char>::type x;
       X<A<T>::i, double>::type y;
       X<A<T*>::i, long>::type z;
-      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name X<A<T *>::i, long>::type; implicit 'typename' is a C++20 extension}}
+      // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'X<A<T *>::i, long>::type'; implicit 'typename' is a C++20 extension}}
       int f();
     };
     template <class T> int A<T>::f() {
@@ -867,7 +867,7 @@ namespace cwg252 { // cwg252: 3.1
   struct E {
     void operator delete(void*, int);
     void operator delete(void*) = delete; // #cwg252-E
-    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}} 
+    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}}
     virtual ~E();
   };
   E::~E() {}
diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index 6c420ecd4c91d..164cc26ae585a 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -603,7 +603,7 @@ namespace cwg336 { // cwg336: 2.7
     // expected-error at -1 {{out-of-line definition of 'mf1' does not match any declaration in 'cwg336::Pre::A<int>::B<double>'}}
     //   expected-note@#cwg336-B {{defined here}}
     template<class Y> template<> void A<Y>::B<double>::mf2() {}
-    // expected-error at -1 {{nested name specifier 'A<Y>::B<double>::' for declaration does not refer into a class, class template or class template partial specialization}}
+    // expected-error at -1 {{nested name specifier 'A<Y>::B<double>' for declaration does not refer into a class, class template or class template partial specialization}}
   }
   namespace Post {
     template<class T1> class A {
@@ -618,7 +618,7 @@ namespace cwg336 { // cwg336: 2.7
     template<> template<> template<class T> void A<int>::B<double>::mf1(T t) {}
     // FIXME: This diagnostic isn't very good.
     template<class Y> template<> void A<Y>::B<double>::mf2() {}
-    // expected-error at -1 {{nested name specifier 'A<Y>::B<double>::' for declaration does not refer into a class, class template or class template partial specialization}}
+    // expected-error at -1 {{nested name specifier 'A<Y>::B<double>' for declaration does not refer into a class, class template or class template partial specialization}}
   }
 } // namespace cwg336
 
diff --git a/clang/test/CXX/drs/cwg4xx.cpp b/clang/test/CXX/drs/cwg4xx.cpp
index 0debc104ac45b..d76c6012b9195 100644
--- a/clang/test/CXX/drs/cwg4xx.cpp
+++ b/clang/test/CXX/drs/cwg4xx.cpp
@@ -257,7 +257,7 @@ namespace cwg409 { // cwg409: 2.7
     A::B b2;
     A<T>::B b3;
     A<T*>::B b4;
-    // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name A<T *>::B; implicit 'typename' is a C++20 extension}}
+    // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'A<T *>::B'; implicit 'typename' is a C++20 extension}}
   };
 } // namespace cwg409
 
diff --git a/clang/test/CXX/drs/cwg5xx.cpp b/clang/test/CXX/drs/cwg5xx.cpp
index 1fdfe5785c5c4..0825b52653b4d 100644
--- a/clang/test/CXX/drs/cwg5xx.cpp
+++ b/clang/test/CXX/drs/cwg5xx.cpp
@@ -254,9 +254,9 @@ namespace cwg526 { // cwg526: 2.7
     typedef int type;
     X<N>::type v1;
     X<(N)>::type v2;
-    // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name X<(N)>::type; implicit 'typename' is a C++20 extension}}
+    // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'X<(N)>::type'; implicit 'typename' is a C++20 extension}}
     X<+N>::type v3;
-    // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name X<+N>::type; implicit 'typename' is a C++20 extension}}
+    // cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'X<+N>::type'; implicit 'typename' is a C++20 extension}}
   };
 } // namespace cwg526
 
@@ -783,7 +783,7 @@ struct Outer {
 };
 template <class T>
 Outer<T>::Inner* Outer<T>::Inner::self() { return this; }
-// cxx98-17-error at -1 {{missing 'typename' prior to dependent type name Outer<T>::Inner; implicit 'typename' is a C++20 extension}}
+// cxx98-17-error at -1 {{missing 'typename' prior to dependent type name 'Outer<T>::Inner'; implicit 'typename' is a C++20 extension}}
 
 } // namespace cwg560
 
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index fb6acde459d9c..e2eb009508b52 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -407,14 +407,14 @@ namespace cwg638 { // cwg638: no
 
   class X {
     typedef int type;
-    template<class T> friend struct A<T>::B; 
-    // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
+    template<class T> friend struct A<T>::B;
+    // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'X'}}
     template<class T> friend void A<T>::f();
-    // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
+    // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'X'}}
     template<class T> friend void A<T>::g();
-    // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
+    // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'X'}}
     template<class T> friend void A<T>::C::h();
-    // expected-warning at -1 {{dependent nested name specifier 'A<T>::C::' for friend class declaration is not supported; turning off access control for 'X'}}
+    // expected-warning at -1 {{dependent nested name specifier 'A<T>::C' for friend class declaration is not supported; turning off access control for 'X'}}
   };
 
   template<> struct A<int> {
@@ -1078,7 +1078,7 @@ namespace cwg677 { // cwg677: no
   struct A {
     void *operator new(std::size_t);
     void operator delete(void*) = delete; // #cwg677-A-delete
-    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}} 
+    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}}
   };
   struct B {
     void *operator new(std::size_t);
diff --git a/clang/test/CXX/special/class.inhctor/elsewhere.cpp b/clang/test/CXX/special/class.inhctor/elsewhere.cpp
index f86f4b86faa7d..9aa310bb7f6ab 100644
--- a/clang/test/CXX/special/class.inhctor/elsewhere.cpp
+++ b/clang/test/CXX/special/class.inhctor/elsewhere.cpp
@@ -33,14 +33,14 @@ struct D1 : I1 {
 template<typename T> struct A {};
 
 template<typename T> struct B : A<bool>, A<char> {
-  using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}}
+  using A<T>::A; // expected-error {{'A<double>', which is not a base class of 'B<double>'}}
 };
 B<bool> bb;
 B<char> bc;
 B<double> bd; // expected-note {{here}}
 
 template<typename T> struct C : A<T> {
-  using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}}
+  using A<bool>::A; // expected-error {{'A<bool>', which is not a base class of 'C<char>'}}
 };
 C<bool> cb;
 C<char> cc; // expected-note {{here}}
diff --git a/clang/test/CXX/temp/temp.res/temp.dep/p3.cpp b/clang/test/CXX/temp/temp.res/temp.dep/p3.cpp
index 583fb4b3cc05d..a5cbcfc0fcafa 100644
--- a/clang/test/CXX/temp/temp.res/temp.dep/p3.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.dep/p3.cpp
@@ -10,13 +10,13 @@ template <typename T> struct B0: A0 {
 };
 
 namespace E1 {
-  typedef double A; 
+  typedef double A;
 
   template<class T> class B {
-    typedef int A; 
+    typedef int A;
   };
 
-  template<class T> 
+  template<class T>
   struct X : B<T> {
     A* blarg(double *dp) {
       return dp;
@@ -25,20 +25,20 @@ namespace E1 {
 }
 
 namespace E2 {
-  struct A { 
+  struct A {
     struct B;
     int *a;
     int Y;
   };
-    
+
   int a;
-  template<class T> struct Y : T { 
+  template<class T> struct Y : T {
     struct B { /* ... */ };
-    B b; 
-    void f(int i) { a = i; } 
+    B b;
+    void f(int i) { a = i; }
     Y* p;
-  }; 
-  
+  };
+
   Y<A> ya;
 }
 
@@ -56,7 +56,7 @@ namespace PR14402 {
     };
 
     struct D {
-      using A::n; // expected-error {{using declaration refers into 'A<T>::', which is not a base class of 'D'}}
+      using A::n; // expected-error {{using declaration refers into 'A<T>', which is not a base class of 'D'}}
       int g() { return f(); } // expected-error {{call to non-static member function 'f' of 'A' from nested type 'D'}}
     };
 
diff --git a/clang/test/Parser/cxx-attributes.cpp b/clang/test/Parser/cxx-attributes.cpp
index 51d1f9c822812..cd09f8d11f1a6 100644
--- a/clang/test/Parser/cxx-attributes.cpp
+++ b/clang/test/Parser/cxx-attributes.cpp
@@ -14,7 +14,7 @@ class c {
 };
 
 template <typename T> class X {
-  template <typename S> void X<S>::f() __attribute__((locks_excluded())); // expected-error{{nested name specifier 'X<S>::' for declaration does not refer into a class, class template or class template partial specialization}} \
+  template <typename S> void X<S>::f() __attribute__((locks_excluded())); // expected-error{{nested name specifier 'X<S>' for declaration does not refer into a class, class template or class template partial specialization}} \
                                                                           // expected-warning{{attribute locks_excluded ignored, because it is not attached to a declaration}}
 };
 
diff --git a/clang/test/Parser/cxx2c-variadic-friends.cpp b/clang/test/Parser/cxx2c-variadic-friends.cpp
index b7da3e6110481..621ae912c1ac9 100644
--- a/clang/test/Parser/cxx2c-variadic-friends.cpp
+++ b/clang/test/Parser/cxx2c-variadic-friends.cpp
@@ -59,10 +59,10 @@ struct VS {
   // FIXME: Both of these should be valid, but we can't handle these at
   // the moment because the NNS is dependent.
   template<class ...T>
-  friend class TS<Ts>::Nested...; // expected-warning {{dependent nested name specifier 'TS<Ts>::' for friend template declaration is not supported; ignoring this friend declaration}}
+  friend class TS<Ts>::Nested...; // expected-warning {{dependent nested name specifier 'TS<Ts>' for friend template declaration is not supported; ignoring this friend declaration}}
 
   template<class T>
-  friend class D<T, Ts>::Nested...; // expected-warning {{dependent nested name specifier 'D<T, Ts>::' for friend class declaration is not supported; turning off access control for 'VS'}}
+  friend class D<T, Ts>::Nested...; // expected-warning {{dependent nested name specifier 'D<T, Ts>' for friend class declaration is not supported; turning off access control for 'VS'}}
 };
 
 namespace length_mismatch {
diff --git a/clang/test/SemaCXX/PR62533.cpp b/clang/test/SemaCXX/PR62533.cpp
index 0753156813f8e..2015161e7946f 100644
--- a/clang/test/SemaCXX/PR62533.cpp
+++ b/clang/test/SemaCXX/PR62533.cpp
@@ -7,11 +7,11 @@ struct test {
 
 template<typename T, typename V>
 decltype(T::template fun_diff<V>) foo1() {}
-// expected-note at -1 {{candidate template ignored: substitution failure [with T = test<int>, V = int]: 'test<int>::fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
+// expected-note at -1 {{candidate template ignored: substitution failure [with T = test<int>, V = int]: 'test<int>::template fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
 
 template<typename T>
 void foo2() {
-  // expected-error at +1 {{test<int>::fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
+  // expected-error at +1 {{test<int>::template fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
   int a = test<T>::template fun_diff<int>;
 }
 
@@ -22,7 +22,7 @@ struct has_fun_diff {
 
 template<typename T>
 struct has_fun_diff<T, int> {
-  // expected-error at +1 {{'test<int>::fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
+  // expected-error at +1 {{'test<int>::template fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
   using type = decltype(T::template fun_diff<int>);
 };
 
diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
index 0c3dd1ea7aa27..340e9037b0f42 100644
--- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -174,10 +174,10 @@ namespace PR14577 {
   };
 
   template<typename T>
-  Outer<T>::Inner1<T>::~Inner1() = delete; // expected-error {{nested name specifier 'Outer<T>::Inner1<T>::' for declaration does not refer into a class, class template or class template partial specialization}}  expected-error {{only functions can have deleted definitions}}
+  Outer<T>::Inner1<T>::~Inner1() = delete; // expected-error {{nested name specifier 'Outer<T>::Inner1<T>' for declaration does not refer into a class, class template or class template partial specialization}}  expected-error {{only functions can have deleted definitions}}
 
   template<typename T>
-  Outer<T>::Inner2<T>::~Inner2() = default; // expected-error {{nested name specifier 'Outer<T>::Inner2<T>::' for declaration does not refer into a class, class template or class template partial specialization}}
+  Outer<T>::Inner2<T>::~Inner2() = default; // expected-error {{nested name specifier 'Outer<T>::Inner2<T>' for declaration does not refer into a class, class template or class template partial specialization}}
 }
 
 extern "C" { // expected-note {{extern "C" language linkage specification begins here}}
diff --git a/clang/test/SemaCXX/cxx11-user-defined-literals.cpp b/clang/test/SemaCXX/cxx11-user-defined-literals.cpp
index bdf88ee01c3a1..c31ea4e6bc45e 100644
--- a/clang/test/SemaCXX/cxx11-user-defined-literals.cpp
+++ b/clang/test/SemaCXX/cxx11-user-defined-literals.cpp
@@ -150,18 +150,18 @@ namespace bad_names {
         operator // expected-error {{expected identifier}}
             ""_q<'a'>;
 
-    T::template operator""_q<'a'>(); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
-    T::template operator""_q<'a'>::X; // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
-    T::operator""_q<'a'>(); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
-    typename T::template operator""_q<'a'> a; // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
+    T::template operator""_q<'a'>(); // expected-error {{non-namespace scope 'T' cannot have a literal operator member}} expected-error +{{}}
+    T::template operator""_q<'a'>::X; // expected-error {{non-namespace scope 'T' cannot have a literal operator member}} expected-error +{{}}
+    T::operator""_q<'a'>(); // expected-error {{non-namespace scope 'T' cannot have a literal operator member}} expected-error +{{}}
+    typename T::template operator""_q<'a'> a; // expected-error {{non-namespace scope 'T' cannot have a literal operator member}} expected-error +{{}}
     typename T::operator""_q(""); // expected-error +{{}} expected-note {{to match}}
-    T::operator""_q(""); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}}
+    T::operator""_q(""); // expected-error {{non-namespace scope 'T' cannot have a literal operator member}}
 
     bad_names::operator""_x<'a', 'b', 'c'>();
   };
 
   struct S {};
   void g() {
-    S::operator""_q(); // expected-error {{non-namespace scope 'S::' cannot have a literal operator member}}
+    S::operator""_q(); // expected-error {{non-namespace scope 'S' cannot have a literal operator member}}
   }
 }
diff --git a/clang/test/SemaCXX/pr25181-crash-on-invalid.cpp b/clang/test/SemaCXX/pr25181-crash-on-invalid.cpp
index 41178c95e8ad4..e0ece54270fec 100644
--- a/clang/test/SemaCXX/pr25181-crash-on-invalid.cpp
+++ b/clang/test/SemaCXX/pr25181-crash-on-invalid.cpp
@@ -3,5 +3,5 @@
 
 template <typename T> class Foo { // expected-note {{template parameter is declared here}}
   template <typename T> // expected-error {{declaration of 'T' shadows template parameter}}
-  void Foo<T>::method(T *) const throw() {} // expected-error {{nested name specifier 'Foo<T>::' for declaration does not refer into a class, class template or class template partial specialization}}
+  void Foo<T>::method(T *) const throw() {} // expected-error {{nested name specifier 'Foo<T>' for declaration does not refer into a class, class template or class template partial specialization}}
 };
diff --git a/clang/test/SemaCXX/pr36536.cpp b/clang/test/SemaCXX/pr36536.cpp
index 702b9ccb707e8..a923d79e25070 100644
--- a/clang/test/SemaCXX/pr36536.cpp
+++ b/clang/test/SemaCXX/pr36536.cpp
@@ -23,7 +23,7 @@ void Foo::f() {
 
 struct ImplicitDefaultCtor2 {};
 template <typename T> class TFoo { void f(); };
-// expected-error at +1 {{nested name specifier 'decltype(TFoo<T>())::'}}
+// expected-error at +1 {{nested name specifier 'decltype(TFoo<T>())'}}
 template <typename T> void decltype(TFoo<T>())::f() {
   switch (0) { case 0: ImplicitDefaultCtor1 o; }
 }
@@ -37,7 +37,7 @@ template <class T1> class A {
 };
 template <class Y>
 template <>
-// expected-error at +1 {{nested name specifier 'A<Y>::B<double>::'}}
+// expected-error at +1 {{nested name specifier 'A<Y>::B<double>'}}
 void A<Y>::B<double>::mf2() {
   switch (0) { case 0: ImplicitDefaultCtor3 o; }
 }
diff --git a/clang/test/SemaCXX/using-decl-templates.cpp b/clang/test/SemaCXX/using-decl-templates.cpp
index 1cf4caee1c0db..c96c4879cb68c 100644
--- a/clang/test/SemaCXX/using-decl-templates.cpp
+++ b/clang/test/SemaCXX/using-decl-templates.cpp
@@ -8,22 +8,22 @@ template<typename T> struct A {
 template<typename T> struct B : A<T> {
   using A<T>::f;
   using A<T>::N; // expected-error{{dependent using declaration resolved to type without 'typename'}}
-  
+
   using A<T>::foo; // expected-error{{no member named 'foo'}}
-  using A<double>::f; // expected-error{{using declaration refers into 'A<double>::', which is not a base class of 'B<int>'}}
+  using A<double>::f; // expected-error{{using declaration refers into 'A<double>', which is not a base class of 'B<int>'}}
 };
 
 B<int> a; // expected-note{{in instantiation of template class 'B<int>' requested here}}
 
 template<typename T> struct C : A<T> {
   using A<T>::f;
-  
+
   void f() { };
 };
 
 template <typename T> struct D : A<T> {
   using A<T>::f;
-  
+
   void f();
 };
 
diff --git a/clang/test/SemaObjCXX/propert-dot-error.mm b/clang/test/SemaObjCXX/propert-dot-error.mm
index 31ee43a3c27d8..377f50de68d11 100644
--- a/clang/test/SemaObjCXX/propert-dot-error.mm
+++ b/clang/test/SemaObjCXX/propert-dot-error.mm
@@ -60,8 +60,8 @@ @interface D { // expected-note 2 {{'D' declared here}}
 @end
 
 void testD(D *d) {
-  d.Forward::property = 17; // expected-error{{property access cannot be qualified with 'Forward::'}}
-  d->Forward::ivar = 12; // expected-error{{instance variable access cannot be qualified with 'Forward::'}}
+  d.Forward::property = 17; // expected-error{{property access cannot be qualified with 'Forward'}}
+  d->Forward::ivar = 12; // expected-error{{instance variable access cannot be qualified with 'Forward'}}
   d.D::property = 17; // expected-error{{'D' is not a class, namespace, or enumeration}}
   d->D::ivar = 12; // expected-error{{'D' is not a class, namespace, or enumeration}}
 }
diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp
index 2dcee6c76da7d..2b5a226c3b33c 100644
--- a/clang/test/SemaTemplate/friend-template.cpp
+++ b/clang/test/SemaTemplate/friend-template.cpp
@@ -30,7 +30,7 @@ namespace test2 {
   template<typename T> struct X0 {
     template<typename U> friend struct X0;
   };
-  
+
   template<typename T> struct X0<T*> {
     template<typename U> friend struct X0;
   };
@@ -116,13 +116,13 @@ namespace PR6022 {
   template <class T1, class T2 , class T3  > class A;
 
   namespace inner {
-    template<class T1, class T2, class T3, class T> 
+    template<class T1, class T2, class T3, class T>
     A<T1, T2, T3>& f0(A<T1, T2, T3>&, T);
-  } 
+  }
 
   template<class T1, class T2, class T3>
   class A {
-    template<class U1, class U2, class U3, class T>  
+    template<class U1, class U2, class U3, class T>
     friend A<U1, U2, U3>& inner::f0(A<U1, U2, U3>&, T);
   };
 }
@@ -235,7 +235,7 @@ namespace rdar11147355 {
   template <class T>
   struct A {
     template <class U> class B;
-    template <class S> template <class U> friend class A<S>::B; // expected-warning {{dependent nested name specifier 'A<S>::' for friend template declaration is not supported; ignoring this friend declaration}}
+    template <class S> template <class U> friend class A<S>::B; // expected-warning {{dependent nested name specifier 'A<S>' for friend template declaration is not supported; ignoring this friend declaration}}
   private:
     int n; // expected-note {{here}}
   };
diff --git a/clang/test/SemaTemplate/ms-sizeof-missing-typename.cpp b/clang/test/SemaTemplate/ms-sizeof-missing-typename.cpp
index fcba385be5ab4..463d86f0d3b94 100644
--- a/clang/test/SemaTemplate/ms-sizeof-missing-typename.cpp
+++ b/clang/test/SemaTemplate/ms-sizeof-missing-typename.cpp
@@ -50,7 +50,7 @@ template struct Foo<Bar>; // expected-note-re {{in instantiation {{.*}} requeste
 }
 
 namespace ambiguous_missing_parens {
-// expected-error at +1 {{'Q::U' is expected to be a non-type template, but instantiated to a class template}}
+// expected-error at +1 {{'Q::template U' is expected to be a non-type template, but instantiated to a class template}}
 template <typename T> void f() { int a = sizeof T::template U<0> + 4; }
 struct Q {
   // expected-note at +1 {{class template declared here}}
diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp
index 4d7f2d9c5c946..7911cf555f4b4 100644
--- a/clang/test/SemaTemplate/nested-template.cpp
+++ b/clang/test/SemaTemplate/nested-template.cpp
@@ -90,7 +90,7 @@ Y Outer<X>::Inner1<Y>::ReallyInner::value3 = Y();
 
 template<typename X>
 template<typename Y>
-Y Outer<X>::Inner1<Y*>::ReallyInner::value4; // expected-error{{Outer<X>::Inner1<Y *>::ReallyInner::}}
+Y Outer<X>::Inner1<Y*>::ReallyInner::value4; // expected-error{{'Outer<X>::Inner1<Y *>::ReallyInner'}}
 
 
 template<typename T>
diff --git a/clang/test/SemaTemplate/qualified-id.cpp b/clang/test/SemaTemplate/qualified-id.cpp
index 883d3d330d148..b15f9826b62e8 100644
--- a/clang/test/SemaTemplate/qualified-id.cpp
+++ b/clang/test/SemaTemplate/qualified-id.cpp
@@ -33,12 +33,12 @@ namespace test2 {
 
 namespace PR6063 {
   template <typename T> void f(T, T);
-  
-  namespace detail 
+
+  namespace detail
   {
     using PR6063::f;
   }
-  
+
   template <typename T>
   void g(T a, T b)
   {
@@ -51,7 +51,7 @@ namespace PR12291 {
   class Outer2 {
     template <typename V>
     template <typename W>
-    class Outer2<V>::Inner; // expected-error{{nested name specifier 'Outer2<V>::' for declaration does not refer into a class, class template or class template partial specialization}}
+    class Outer2<V>::Inner; // expected-error{{nested name specifier 'Outer2<V>' for declaration does not refer into a class, class template or class template partial specialization}}
                             // expected-error at -1{{forward declaration of class cannot have a nested name specifier}}
   };
 }
diff --git a/clang/test/SemaTemplate/template-id-expr.cpp b/clang/test/SemaTemplate/template-id-expr.cpp
index dc12823ae307f..a13013a1ffd47 100644
--- a/clang/test/SemaTemplate/template-id-expr.cpp
+++ b/clang/test/SemaTemplate/template-id-expr.cpp
@@ -19,7 +19,7 @@ template<typename T>
 struct X0 {
   template<typename U>
   void f1();
-  
+
   template<typename U>
   void f2(U) {
     f1<U>();
@@ -39,9 +39,9 @@ struct Y {
 template<int I>
 struct X {
   X(int, int);
-  void f() { 
-    Y<X<I> >(X<I>(0, 0)); 
-    Y<X<I> >(::X<I>(0, 0)); 
+  void f() {
+    Y<X<I> >(X<I>(0, 0));
+    Y<X<I> >(::X<I>(0, 0));
   }
 };
 
@@ -184,7 +184,7 @@ class E {
 #if __cplusplus <= 199711L
 // expected-warning at +2 {{extension}}
 #endif
-template<typename T> using D = int; // expected-note {{declared here}} 
+template<typename T> using D = int; // expected-note {{declared here}}
 E<D> ed; // expected-note {{instantiation of}}
 
 namespace non_functions {
@@ -202,7 +202,7 @@ struct P {
 struct Q {
   template <typename T> int foo() {
     return T::template I<int>;
-    // expected-error at -1 {{'P::I' is expected to be a non-type template, but instantiated to a type alias template}}
+    // expected-error at -1 {{'P::template I' is expected to be a non-type template, but instantiated to a type alias template}}
     // expected-note@#TypeAlias {{type alias template declared here}}
   }
 };
@@ -251,18 +251,18 @@ template <typename T1> struct A {
 
   void foo() {
     C<T1>::template Type<2>;
-    // expected-error at -1 {{'C<float>::Type' is expected to be a non-type template, but instantiated to a class template}}}
+    // expected-error at -1 {{'C<float>::template Type' is expected to be a non-type template, but instantiated to a class template}}}
     // expected-note@#ClassTemplate {{class template declared here}}
 
     foo(C<T1>::Type<2>); // expected-error {{expected expression}}
 
     foo(C<T1>::template Type<2>);
-    // expected-error at -1 {{'C<float>::Type' is expected to be a non-type template, but instantiated to a class template}}
+    // expected-error at -1 {{'C<float>::template Type' is expected to be a non-type template, but instantiated to a class template}}
     // expected-note@#ClassTemplate {{class template declared here}}
 
     foo(C<T1>::template Type<2>());
-    // expected-error at -1 {{'C<float>::Type' is expected to be a non-type template, but instantiated to a class template}}
-    // expected-error at -2 {{called object type '<dependent type>' is not a function or function pointer}}
+    // expected-error at -1 {{'C<float>::template Type' is expected to be a non-type template, but instantiated to a class template}}
+    // expected-error at -2 {{called object type 'C<float>::template Type<2>' is not a function or function pointer}}
     // expected-note@#ClassTemplate {{class template declared here}}
 
     foo(typename C<T1>::template Type<2>());
diff --git a/clang/test/SemaTemplate/typename-specifier-3.cpp b/clang/test/SemaTemplate/typename-specifier-3.cpp
index 714830f0032d2..0140b1a479c2d 100644
--- a/clang/test/SemaTemplate/typename-specifier-3.cpp
+++ b/clang/test/SemaTemplate/typename-specifier-3.cpp
@@ -28,7 +28,7 @@ namespace PR12884_original {
       typedef int arg;
     };
     struct C {
-      typedef B::X<typename B::arg> x; // precxx17-warning{{missing 'typename' prior to dependent type name B::X; implicit 'typename' is a C++20 extension}}
+      typedef B::X<typename B::arg> x; // precxx17-warning{{missing 'typename' prior to dependent type name 'B::X'; implicit 'typename' is a C++20 extension}}
     };
   };
 



More information about the cfe-commits mailing list