[clang] 5f12f4f - Suppress printing of inline namespace names in diagnostics by default,

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 11 15:08:03 PST 2020


Author: Richard Smith
Date: 2020-11-11T15:05:51-08:00
New Revision: 5f12f4ff9078455cad9d4806da01f570553a5bf9

URL: https://github.com/llvm/llvm-project/commit/5f12f4ff9078455cad9d4806da01f570553a5bf9
DIFF: https://github.com/llvm/llvm-project/commit/5f12f4ff9078455cad9d4806da01f570553a5bf9.diff

LOG: Suppress printing of inline namespace names in diagnostics by default,
except where they are necessary to disambiguate the target.

This substantially improves diagnostics from the standard library,
which are otherwise full of `::__1::` noise.

Added: 
    clang/test/Misc/diag-inline-namespace.cpp

Modified: 
    clang/include/clang/AST/PrettyPrinter.h
    clang/lib/AST/Decl.cpp
    clang/lib/AST/TypePrinter.cpp
    clang/lib/ASTMatchers/ASTMatchersInternal.cpp
    clang/lib/CodeGen/CodeGenTypes.cpp
    clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index 50e2142e2ef0..e06b3b8843ce 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -52,9 +52,9 @@ struct PrintingPolicy {
       : Indentation(2), SuppressSpecifiers(false),
         SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
         SuppressScope(false), SuppressUnwrittenScope(false),
-        SuppressInitializers(false), ConstantArraySizeAsWritten(false),
-        AnonymousTagLocations(true), SuppressStrongLifetime(false),
-        SuppressLifetimeQualifiers(false),
+        SuppressInlineNamespace(true), SuppressInitializers(false),
+        ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
+        SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
         SuppressTemplateArgsInCXXConstructors(false),
         SuppressDefaultTemplateArgs(true), Bool(LO.Bool),
         Nullptr(LO.CPlusPlus11), Restrict(LO.C99), Alignof(LO.CPlusPlus11),
@@ -118,10 +118,15 @@ struct PrintingPolicy {
   /// Suppresses printing of scope specifiers.
   unsigned SuppressScope : 1;
 
-  /// Suppress printing parts of scope specifiers that don't need
-  /// to be written, e.g., for inline or anonymous namespaces.
+  /// Suppress printing parts of scope specifiers that are never
+  /// written, e.g., for anonymous namespaces.
   unsigned SuppressUnwrittenScope : 1;
 
+  /// Suppress printing parts of scope specifiers that correspond
+  /// to inline namespaces, where the name is unambiguous with the specifier
+  /// removed.
+  unsigned SuppressInlineNamespace : 1;
+
   /// Suppress printing of variable initializers.
   ///
   /// This flag is used when printing the loop variable in a for-range

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 5055c6359d1c..888999978466 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1600,21 +1600,35 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
   ContextsTy Contexts;
 
   // Collect named contexts.
-  while (Ctx) {
-    if (isa<NamedDecl>(Ctx))
-      Contexts.push_back(Ctx);
-    Ctx = Ctx->getParent();
+  DeclarationName NameInScope = getDeclName();
+  for (; Ctx; Ctx = Ctx->getParent()) {
+    // Suppress anonymous namespace if requested.
+    if (P.SuppressUnwrittenScope && isa<NamespaceDecl>(Ctx) &&
+        cast<NamespaceDecl>(Ctx)->isAnonymousNamespace())
+      continue;
+
+    // Suppress inline namespace if it doesn't make the result ambiguous.
+    if (P.SuppressInlineNamespace && Ctx->isInlineNamespace() && NameInScope &&
+        Ctx->lookup(NameInScope).size() ==
+            Ctx->getParent()->lookup(NameInScope).size())
+      continue;
+
+    // Skip non-named contexts such as linkage specifications and ExportDecls.
+    const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx);
+    if (!ND)
+      continue;
+
+    Contexts.push_back(Ctx);
+    NameInScope = ND->getDeclName();
   }
 
-  for (const DeclContext *DC : llvm::reverse(Contexts)) {
+  for (unsigned I = Contexts.size(); I != 0; --I) {
+    const DeclContext *DC = Contexts[I - 1];
     if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
       OS << Spec->getName();
       const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
       printTemplateArgumentList(OS, TemplateArgs.asArray(), P);
     } else if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) {
-      if (P.SuppressUnwrittenScope &&
-          (ND->isAnonymousNamespace() || ND->isInline()))
-        continue;
       if (ND->isAnonymousNamespace()) {
         OS << (P.MSVCFormatting ? "`anonymous namespace\'"
                                 : "(anonymous namespace)");

diff  --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 3368905007a4..721031932a4a 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -118,7 +118,8 @@ namespace {
 
     void printBefore(QualType T, raw_ostream &OS);
     void printAfter(QualType T, raw_ostream &OS);
-    void AppendScope(DeclContext *DC, raw_ostream &OS);
+    void AppendScope(DeclContext *DC, raw_ostream &OS,
+                     DeclarationName NameInScope);
     void printTag(TagDecl *T, raw_ostream &OS);
     void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
 #define ABSTRACT_TYPE(CLASS, PARENT)
@@ -1021,7 +1022,7 @@ void TypePrinter::printTypeSpec(NamedDecl *D, raw_ostream &OS) {
   // In C, this will always be empty except when the type
   // being printed is anonymous within other Record.
   if (!Policy.SuppressScope)
-    AppendScope(D->getDeclContext(), OS);
+    AppendScope(D->getDeclContext(), OS, D->getDeclName());
 
   IdentifierInfo *II = D->getIdentifier();
   OS << II->getName();
@@ -1211,20 +1212,34 @@ void TypePrinter::printDependentExtIntAfter(const DependentExtIntType *T,
                                             raw_ostream &OS) {}
 
 /// Appends the given scope to the end of a string.
-void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
-  if (DC->isTranslationUnit()) return;
-  if (DC->isFunctionOrMethod()) return;
-  AppendScope(DC->getParent(), OS);
+void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS,
+                              DeclarationName NameInScope) {
+  if (DC->isTranslationUnit())
+    return;
+
+  // FIXME: Consider replacing this with NamedDecl::printNestedNameSpecifier,
+  // which can also print names for function and method scopes.
+  if (DC->isFunctionOrMethod())
+    return;
 
   if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
-    if (Policy.SuppressUnwrittenScope &&
-        (NS->isAnonymousNamespace() || NS->isInline()))
-      return;
+    if (Policy.SuppressUnwrittenScope && NS->isAnonymousNamespace())
+      return AppendScope(DC->getParent(), OS, NameInScope);
+
+    // Only suppress an inline namespace if the name has the same lookup
+    // results in the enclosing namespace.
+    if (Policy.SuppressInlineNamespace && NS->isInline() && NameInScope &&
+        DC->getParent()->lookup(NameInScope).size() ==
+            DC->lookup(NameInScope).size())
+      return AppendScope(DC->getParent(), OS, NameInScope);
+
+    AppendScope(DC->getParent(), OS, NS->getDeclName());
     if (NS->getIdentifier())
       OS << NS->getName() << "::";
     else
       OS << "(anonymous namespace)::";
   } else if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
+    AppendScope(DC->getParent(), OS, Spec->getDeclName());
     IncludeStrongLifetimeRAII Strong(Policy);
     OS << Spec->getIdentifier()->getName();
     const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
@@ -1233,12 +1248,15 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
         Spec->getSpecializedTemplate()->getTemplateParameters());
     OS << "::";
   } else if (const auto *Tag = dyn_cast<TagDecl>(DC)) {
+    AppendScope(DC->getParent(), OS, Tag->getDeclName());
     if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl())
       OS << Typedef->getIdentifier()->getName() << "::";
     else if (Tag->getIdentifier())
       OS << Tag->getIdentifier()->getName() << "::";
     else
       return;
+  } else {
+    AppendScope(DC->getParent(), OS, NameInScope);
   }
 }
 
@@ -1265,7 +1283,7 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
   // In C, this will always be empty except when the type
   // being printed is anonymous within other Record.
   if (!Policy.SuppressScope)
-    AppendScope(D->getDeclContext(), OS);
+    AppendScope(D->getDeclContext(), OS, D->getDeclName());
 
   if (const IdentifierInfo *II = D->getIdentifier())
     OS << II->getName();

diff  --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 0eea41bdc4e5..b7044cd23ffe 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -630,13 +630,10 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const {
     llvm::SmallString<128> NodeName = StringRef("::");
     llvm::raw_svector_ostream OS(NodeName);
 
-    if (SkipUnwritten) {
-      PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
-      Policy.SuppressUnwrittenScope = true;
-      Node.printQualifiedName(OS, Policy);
-    } else {
-      Node.printQualifiedName(OS);
-    }
+    PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
+    Policy.SuppressUnwrittenScope = SkipUnwritten;
+    Policy.SuppressInlineNamespace = SkipUnwritten;
+    Node.printQualifiedName(OS, Policy);
 
     const StringRef FullName = OS.str();
 

diff  --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index e8a4b4f49324..2804b0ee8dd2 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -52,20 +52,26 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
   llvm::raw_svector_ostream OS(TypeName);
   OS << RD->getKindName() << '.';
 
+  // FIXME: We probably want to make more tweaks to the printing policy. For
+  // example, we should probably enable PrintCanonicalTypes and
+  // FullyQualifiedNames.
+  PrintingPolicy Policy = RD->getASTContext().getPrintingPolicy();
+  Policy.SuppressInlineNamespace = false;
+
   // Name the codegen type after the typedef name
   // if there is no tag type name available
   if (RD->getIdentifier()) {
     // FIXME: We should not have to check for a null decl context here.
     // Right now we do it because the implicit Obj-C decls don't have one.
     if (RD->getDeclContext())
-      RD->printQualifiedName(OS);
+      RD->printQualifiedName(OS, Policy);
     else
       RD->printName(OS);
   } else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) {
     // FIXME: We should not have to check for a null decl context here.
     // Right now we do it because the implicit Obj-C decls don't have one.
     if (TDD->getDeclContext())
-      TDD->printQualifiedName(OS);
+      TDD->printQualifiedName(OS, Policy);
     else
       TDD->printName(OS);
   } else

diff  --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
index 96a0df4a03f0..3b2c48920b37 100644
--- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
+++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
@@ -21,7 +21,7 @@ void foo1() {
   f1();
   ::f1();
   X::f1();
-  Y::f1(); // expected-error {{no member named 'f1' in namespace 'X::Y'; did you mean simply 'f1'?}}
+  Y::f1(); // expected-error {{no member named 'f1' in namespace 'Y'; did you mean simply 'f1'?}}
 
   f2();
   ::f2();

diff  --git a/clang/test/Misc/diag-inline-namespace.cpp b/clang/test/Misc/diag-inline-namespace.cpp
new file mode 100644
index 000000000000..74bdeed68d21
--- /dev/null
+++ b/clang/test/Misc/diag-inline-namespace.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -verify %s -std=c++20
+
+// We avoid printing the name of an inline namespace unless it's necessary to
+// uniquely identify the target.
+namespace N {
+  inline namespace A {
+    inline namespace B {
+      inline namespace C {
+        int f, g, h, i, j;
+        struct f; struct g; struct h; struct i; struct j;
+      }
+      struct g;
+      struct j;
+    }
+    struct h;
+  }
+  struct i;
+  struct j;
+
+  template<int*> struct Q; // expected-note 5{{here}}
+  Q<&A::B::C::f> q1; // expected-error {{implicit instantiation of undefined template 'N::Q<&N::f>'}}
+  Q<&A::B::C::g> q2; // expected-error {{implicit instantiation of undefined template 'N::Q<&N::C::g>'}}
+  Q<&A::B::C::h> q3; // expected-error {{implicit instantiation of undefined template 'N::Q<&N::B::h>'}}
+  Q<&A::B::C::i> q4; // expected-error {{implicit instantiation of undefined template 'N::Q<&N::A::i>'}}
+  Q<&A::B::C::j> q5; // expected-error {{implicit instantiation of undefined template 'N::Q<&N::C::j>'}}
+
+  template<typename> struct R; // expected-note 5{{here}}
+  R<struct A::B::C::f> r1; // expected-error {{implicit instantiation of undefined template 'N::R<N::f>'}}
+  R<struct A::B::C::g> r2; // expected-error {{implicit instantiation of undefined template 'N::R<N::C::g>'}}
+  R<struct A::B::C::h> r3; // expected-error {{implicit instantiation of undefined template 'N::R<N::B::h>'}}
+  R<struct A::B::C::i> r4; // expected-error {{implicit instantiation of undefined template 'N::R<N::A::i>'}}
+  R<struct A::B::C::j> r5; // expected-error {{implicit instantiation of undefined template 'N::R<N::C::j>'}}
+
+  // Make the name N::C ambiguous.
+  inline namespace A { int C; }
+
+  template<int*> struct S; // expected-note 5{{here}}
+  S<&A::B::C::f> s1; // expected-error {{implicit instantiation of undefined template 'N::S<&N::f>'}}
+  S<&A::B::C::g> s2; // expected-error {{implicit instantiation of undefined template 'N::S<&N::B::C::g>'}}
+  S<&A::B::C::h> s3; // expected-error {{implicit instantiation of undefined template 'N::S<&N::B::h>'}}
+  S<&A::B::C::i> s4; // expected-error {{implicit instantiation of undefined template 'N::S<&N::A::i>'}}
+  S<&A::B::C::j> s5; // expected-error {{implicit instantiation of undefined template 'N::S<&N::B::C::j>'}}
+
+  template<typename> struct T; // expected-note 5{{here}}
+  T<struct A::B::C::f> t1; // expected-error {{implicit instantiation of undefined template 'N::T<N::f>'}}
+  T<struct A::B::C::g> t2; // expected-error {{implicit instantiation of undefined template 'N::T<N::B::C::g>'}}
+  T<struct A::B::C::h> t3; // expected-error {{implicit instantiation of undefined template 'N::T<N::B::h>'}}
+  T<struct A::B::C::i> t4; // expected-error {{implicit instantiation of undefined template 'N::T<N::A::i>'}}
+  T<struct A::B::C::j> t5; // expected-error {{implicit instantiation of undefined template 'N::T<N::B::C::j>'}}
+}


        


More information about the cfe-commits mailing list