mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 06:06:06 +00:00
[clang][AST] fix ast-print of extern <lang> with >=2 declarators
Fixes #93913
This commit is contained in:
parent
7b34070eb4
commit
48f13d48a8
@ -576,13 +576,16 @@ template <typename T> static bool isFirstInExternCContext(T *D) {
|
||||
return First->isInExternCContext();
|
||||
}
|
||||
|
||||
static bool isSingleLineLanguageLinkage(const Decl &D) {
|
||||
if (const auto *SD = dyn_cast<LinkageSpecDecl>(D.getDeclContext()))
|
||||
if (!SD->hasBraces())
|
||||
return true;
|
||||
static bool isUnbracedLanguageLinkage(const DeclContext *DC) {
|
||||
if (const auto *SD = dyn_cast_if_present<LinkageSpecDecl>(DC))
|
||||
return !SD->hasBraces();
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hasUnbracedLanguageLinkage(const Decl &D) {
|
||||
return isUnbracedLanguageLinkage(D.getDeclContext());
|
||||
}
|
||||
|
||||
static bool isDeclaredInModuleInterfaceOrPartition(const NamedDecl *D) {
|
||||
if (auto *M = D->getOwningModule())
|
||||
return M->isInterfaceOrPartition();
|
||||
@ -644,7 +647,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
|
||||
|
||||
if (Var->getStorageClass() != SC_Extern &&
|
||||
Var->getStorageClass() != SC_PrivateExtern &&
|
||||
!isSingleLineLanguageLinkage(*Var))
|
||||
!hasUnbracedLanguageLinkage(*Var))
|
||||
return LinkageInfo::internal();
|
||||
}
|
||||
|
||||
@ -2118,6 +2121,12 @@ VarDecl::VarDecl(Kind DK, ASTContext &C, DeclContext *DC,
|
||||
"ParmVarDeclBitfields too large!");
|
||||
static_assert(sizeof(NonParmVarDeclBitfields) <= sizeof(unsigned),
|
||||
"NonParmVarDeclBitfields too large!");
|
||||
|
||||
// The unbraced `extern "C"` invariant is that the storage class
|
||||
// specifier is omitted in the source code, i.e. SC_None (but is,
|
||||
// implicitly, `extern`).
|
||||
assert(!isUnbracedLanguageLinkage(DC) || SC == SC_None);
|
||||
|
||||
AllBits = 0;
|
||||
VarDeclBits.SClass = SC;
|
||||
// Everything else is implicitly initialized to false.
|
||||
@ -2301,7 +2310,7 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const {
|
||||
// A declaration directly contained in a linkage-specification is treated
|
||||
// as if it contains the extern specifier for the purpose of determining
|
||||
// the linkage of the declared name and whether it is a definition.
|
||||
if (isSingleLineLanguageLinkage(*this))
|
||||
if (hasUnbracedLanguageLinkage(*this))
|
||||
return DeclarationOnly;
|
||||
|
||||
// C99 6.9.2p2:
|
||||
@ -3027,6 +3036,12 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
|
||||
DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
|
||||
EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {
|
||||
assert(T.isNull() || T->isFunctionType());
|
||||
|
||||
// The unbraced `extern "C"` invariant is that the storage class
|
||||
// specifier is omitted in the source code, i.e. SC_None (but is,
|
||||
// implicitly, `extern`).
|
||||
assert(!isUnbracedLanguageLinkage(DC) || S == SC_None);
|
||||
|
||||
FunctionDeclBits.SClass = S;
|
||||
FunctionDeclBits.IsInline = isInlineSpecified;
|
||||
FunctionDeclBits.IsInlineSpecified = isInlineSpecified;
|
||||
|
@ -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,22 +1164,21 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
|
||||
const char *l;
|
||||
if (!D->hasBraces()) {
|
||||
VisitDeclContext(D);
|
||||
return;
|
||||
}
|
||||
const char *L;
|
||||
if (D->getLanguage() == LinkageSpecLanguageIDs::C)
|
||||
l = "C";
|
||||
L = "C";
|
||||
else {
|
||||
assert(D->getLanguage() == LinkageSpecLanguageIDs::CXX &&
|
||||
"unknown language in linkage specification");
|
||||
l = "C++";
|
||||
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,
|
||||
|
@ -2379,7 +2379,7 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type,
|
||||
}
|
||||
|
||||
FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
|
||||
/*TInfo=*/nullptr, SC_Extern,
|
||||
/*TInfo=*/nullptr, SC_None,
|
||||
getCurFPFeatures().isFPConstrained(),
|
||||
false, Type->isFunctionProtoType());
|
||||
New->setImplicit();
|
||||
|
@ -6288,7 +6288,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
|
||||
FunctionDecl *OverloadDecl = FunctionDecl::Create(
|
||||
Context, Parent, FDecl->getLocation(), FDecl->getLocation(),
|
||||
FDecl->getIdentifier(), OverloadTy,
|
||||
/*TInfo=*/nullptr, SC_Extern, Sema->getCurFPFeatures().isFPConstrained(),
|
||||
/*TInfo=*/nullptr, SC_None, Sema->getCurFPFeatures().isFPConstrained(),
|
||||
false,
|
||||
/*hasPrototype=*/true);
|
||||
SmallVector<ParmVarDecl*, 16> Params;
|
||||
|
31
clang/test/AST/ast-print-language-linkage.cpp
Normal file
31
clang/test/AST/ast-print-language-linkage.cpp
Normal file
@ -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++";
|
@ -881,7 +881,7 @@ private:
|
||||
else
|
||||
ToInsert += "(";
|
||||
raw_string_ostream OS(Description);
|
||||
F->print(OS, m_desc_policy, false);
|
||||
F->print(OS, m_desc_policy);
|
||||
OS.flush();
|
||||
} else if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
|
||||
Description = V->getType().getAsString(m_desc_policy);
|
||||
|
@ -77,7 +77,8 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
|
||||
|
||||
clang::FunctionDecl *func_decl = FunctionDecl::Create(
|
||||
ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type,
|
||||
nullptr, SC_Extern, /*UsesFPIntrin=*/false, isInlineSpecified, hasWrittenPrototype,
|
||||
nullptr, SC_None, /*UsesFPIntrin=*/false, isInlineSpecified,
|
||||
hasWrittenPrototype,
|
||||
isConstexprSpecified ? ConstexprSpecKind::Constexpr
|
||||
: ConstexprSpecKind::Unspecified);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user