https://github.com/temyurchenko updated https://github.com/llvm/llvm-project/pull/93131
>From a8f15038fa0fbe3ba55d136eb459f511d73b0b34 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: for unbraced case we traverse all declarators via `VisitDeclContext`. Furthermore, in appropriate visitors we query for whether they are a part of the unbraced extern language linkage spec, and if so, print appropriately. --- clang/lib/AST/DeclPrinter.cpp | 49 ++++++++++++++----- clang/test/AST/ast-print-language-linkage.cpp | 31 ++++++++++++ 2 files changed, 69 insertions(+), 11 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..9e7ce96d1b41e 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 || 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,11 @@ 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)) { + // the "extern" specifier is implicit + assert(D->getStorageClass() == SC_None); + Out << "extern \"" << lang << "\" "; + } switch (D->getStorageClass()) { case SC_None: break; case SC_Extern: Out << "extern "; break; @@ -807,7 +828,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 +953,11 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { : D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); if (!Policy.SuppressSpecifiers) { + if (const char *lang = tryGetUnbracedLinkageLanguage(D)) { + // the "extern" specifier is implicit + assert(D->getStorageClass() == SC_None); + Out << "extern \"" << lang << "\" "; + } StorageClass SC = D->getStorageClass(); if (SC != SC_None) Out << VarDecl::getStorageClassSpecifierString(SC) << " "; @@ -961,7 +987,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 +1090,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) { @@ -1136,6 +1164,10 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { } void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + if (!D->hasBraces()) { + VisitDeclContext(D); + return; + } const char *l; if (D->getLanguage() == LinkageSpecLanguageIDs::C) l = "C"; @@ -1144,14 +1176,9 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { "unknown language in linkage specification"); l = "C++"; } - - Out << "extern \"" << l << "\" "; - if (D->hasBraces()) { - Out << "{\n"; - VisitDeclContext(D); - Indent() << "}"; - } else - Visit(*D->decls_begin()); + Out << "extern \"" << l << "\" {\n"; + VisitDeclContext(D); + Indent() << "}"; } 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