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