https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/93131
>From ae5225aa51a0a8f79ed134d9d5013d5774d2c04d Mon Sep 17 00:00:00 2001 From: Artem Yurchenko <artemyurche...@zoho.com> Date: Wed, 22 May 2024 23:41:35 -0400 Subject: [PATCH] [clang][AST] fix ast-print of `extern <lang>` with >=2 declarators Problem: the printer used to ignore all but the first declarator for unbraced language linkage declarators. Furthemore, that one would be printed without the final semicolon. Solution: when there is more than one declarator, we print them in a braced `extern <lang>` block. If the original declaration was unbraced and there is one or less declarator, we omit the braces, but add the semicolon. --- clang/lib/AST/DeclPrinter.cpp | 37 ++++++++++++++++--- clang/test/AST/ast-print-language-linkage.cpp | 31 ++++++++++++++++ 2 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 clang/test/AST/ast-print-language-linkage.cpp diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 0cf4e64f83b8d..60d5074e69151 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -633,7 +633,7 @@ static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out, Out << Proto; } -static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy, +static void maybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy, QualType T, llvm::raw_ostream &Out) { StringRef prefix = T->isClassType() ? "class " @@ -643,6 +643,22 @@ static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy, Out << prefix; } +/// Return the language of the linkage spec of `D`, if applicable. +/// +/// \Return - "C" if `D` has been declared with unbraced `extern "C"` +/// - "C++" if `D` has been declared with unbraced `extern "C++"` +/// - nullptr in any other case +static const char *tryGetUnbracedLinkageLanguage(const Decl *D) { + const auto *SD = dyn_cast<LinkageSpecDecl>(D->getDeclContext()); + if (!SD) return nullptr; + if (SD->hasBraces()) return nullptr; + if (SD->getLanguage() == LinkageSpecLanguageIDs::C) + return "C"; + assert(SD->getLanguage() == LinkageSpecLanguageIDs::CXX && + "unknown language in linkage specification"); + return "C++"; +} + void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!D->getDescribedFunctionTemplate() && !D->isFunctionTemplateSpecialization()) { @@ -662,6 +678,10 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D); CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D); if (!Policy.SuppressSpecifiers) { + if (const char *lang = tryGetUnbracedLinkageLanguage(D)) { + assert(D->getStorageClass() == SC_None); // the "extern" specifier is implicit + Out << "extern \"" << lang << "\" "; + } switch (D->getStorageClass()) { case SC_None: break; case SC_Extern: Out << "extern "; break; @@ -807,7 +827,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } if (!Policy.SuppressTagKeyword && Policy.SuppressScope && !Policy.SuppressUnwrittenScope) - MaybePrintTagKeywordIfSupressingScopes(Policy, AFT->getReturnType(), + maybePrintTagKeywordIfSupressingScopes(Policy, AFT->getReturnType(), Out); AFT->getReturnType().print(Out, Policy, Proto); Proto.clear(); @@ -932,6 +952,10 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { : D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); if (!Policy.SuppressSpecifiers) { + if (const char *lang = tryGetUnbracedLinkageLanguage(D)) { + assert(D->getStorageClass() == SC_None); // the "extern" specifier is implicit + Out << "extern \"" << lang << "\" "; + } StorageClass SC = D->getStorageClass(); if (SC != SC_None) Out << VarDecl::getStorageClassSpecifierString(SC) << " "; @@ -961,7 +985,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { if (!Policy.SuppressTagKeyword && Policy.SuppressScope && !Policy.SuppressUnwrittenScope) - MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out); + maybePrintTagKeywordIfSupressingScopes(Policy, T, Out); printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters && D->getIdentifier()) @@ -1064,6 +1088,8 @@ void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) { prettyPrintAttributes(D); + if (const char *lang = tryGetUnbracedLinkageLanguage(D)) + Out << "extern \"" << lang << "\";"; } void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { @@ -1145,13 +1171,12 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { l = "C++"; } - Out << "extern \"" << l << "\" "; if (D->hasBraces()) { - Out << "{\n"; + Out << "extern \"" << l << "\" {\n"; VisitDeclContext(D); Indent() << "}"; } else - Visit(*D->decls_begin()); + VisitDeclContext(D); } void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params, diff --git a/clang/test/AST/ast-print-language-linkage.cpp b/clang/test/AST/ast-print-language-linkage.cpp new file mode 100644 index 0000000000000..7e4dc3f25f062 --- /dev/null +++ b/clang/test/AST/ast-print-language-linkage.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -ast-print %s -o - | FileCheck %s + +// CHECK: extern "C" int printf(const char *, ...); +extern "C" int printf(const char *...); + +// CHECK: extern "C++" int f(int); +// CHECK-NEXT: extern "C++" int g(int); +extern "C++" int f(int), g(int); + +// CHECK: extern "C" char a; +// CHECK-NEXT: extern "C" char b; +extern "C" char a, b; + +// CHECK: extern "C" { +// CHECK-NEXT: void foo(); +// CHECK-NEXT: int x; +// CHECK-NEXT: int y; +// CHECK-NEXT: extern short z; +// CHECK-NEXT: } +extern "C" { + void foo(void); + int x, y; + extern short z; +} + +// CHECK: extern "C" { +// CHECK-NEXT: } +extern "C" {} + +// CHECK: extern "C++"; +extern "C++"; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits