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

David Blaikie via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 16 18:48:45 PST 2020


Neat!

On Wed, Nov 11, 2020 at 3:08 PM Richard Smith via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
>
>
> 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>'}}
> +}
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


More information about the cfe-commits mailing list