[clang] [lldb] [clang][AST] fix ast-print of extern <lang> with >=2 declarators, fixed (PR #93913)

Artem Yurchenko via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 7 12:46:46 PDT 2024


https://github.com/temyurchenko updated https://github.com/llvm/llvm-project/pull/93913

>From 9b18a5c4132cf093fc9b32f6b4dcfe406d485e3d Mon Sep 17 00:00:00 2001
From: Artem Yurchenko <artemyurchenko at zoho.com>
Date: Thu, 6 Jun 2024 20:20:19 -0400
Subject: [PATCH] enforce the unbraced `extern <lang>` invariant

Quoting 9.11.8:
> A declaration directly contained in a linkage-specification is
> treated as if it contains the extern specifier (9.2.2) for the
> purpose of determining the linkage of the declared name and whether
> it is a definition. Such a declaration shall not specify a storage
> class.

So, the invariant is that function and variable declarations within an
unbraced language linkage specification have `StorageClass` set to
`SC_None`.

Problem: in several places the invariant was broken.

Solution: remove the explicit `SC_Extern` specification. Note, that my
changes result in the `extern` being implicit in some functions
that are not contained in a language linkage specification.
---
 clang/lib/AST/Decl.cpp                        | 26 ++++++++++++++++---
 clang/lib/Sema/SemaDecl.cpp                   |  2 +-
 clang/lib/Sema/SemaExpr.cpp                   |  2 +-
 .../Clang/ClangExpressionParser.cpp           |  2 +-
 .../Clang/NameSearchContext.cpp               |  3 ++-
 5 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 1f19dadafa44e..ebaeed0e818e1 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -576,13 +576,19 @@ 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()))
+static bool isUnbracedLanguageLinkage(const DeclContext *DC) {
+  if (!DC)
+    return false;
+  if (const auto *SD = dyn_cast<LinkageSpecDecl>(DC))
     if (!SD->hasBraces())
       return true;
   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 +650,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
 
       if (Var->getStorageClass() != SC_Extern &&
           Var->getStorageClass() != SC_PrivateExtern &&
-          !isSingleLineLanguageLinkage(*Var))
+          !hasUnbracedLanguageLinkage(*Var))
         return LinkageInfo::internal();
     }
 
@@ -2133,6 +2139,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.
@@ -2316,7 +2328,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:
@@ -3041,6 +3053,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;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4b9b735f1cfb4..4e2f02ba7007a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2380,7 +2380,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();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 76145f291887c..60075120fe030 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6286,7 +6286,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;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 1dd98567f8d69..12aa1bd60bcb7 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -881,7 +881,7 @@ class CodeComplete : public CodeCompleteConsumer {
         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);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
index da59855a9f162..e02b418b1e793 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
@@ -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);
 



More information about the cfe-commits mailing list