[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