https://github.com/zmodem created 
https://github.com/llvm/llvm-project/pull/198738

This was causing assertion failures:

Assertion `D->getCachedLinkage() == LV.getLinkage()' failed.

see discussion on the original PR.

Reverts llvm/llvm-project#198215

>From 2e3671edd5c3401d295b7c341524cbfa00b92c4f Mon Sep 17 00:00:00 2001
From: Hans Wennborg <[email protected]>
Date: Wed, 20 May 2026 11:48:30 +0200
Subject: [PATCH] Revert "[clang] Give unnamed namespaces internal linkage
 (#198215)"

This reverts commit 7ae1a3fad8f06625d4e55b846a090ce9206c3c82.
---
 clang/lib/AST/Decl.cpp                       | 65 +++++++++-----------
 clang/test/AST/ast-dump-linkage-internal.cpp | 12 +---
 2 files changed, 33 insertions(+), 44 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 79fd680737d00..535adcb2ae109 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -672,6 +672,23 @@ LinkageComputer::getLVForNamespaceScopeDecl(const 
NamedDecl *D,
   }
   assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!");
 
+  // FIXME: This gives internal linkage to names that should have no linkage
+  // (those not covered by [basic.link]p6).
+  if (D->isInAnonymousNamespace()) {
+    const auto *Var = dyn_cast<VarDecl>(D);
+    const auto *Func = dyn_cast<FunctionDecl>(D);
+    // FIXME: The check for extern "C" here is not justified by the standard
+    // wording, but we retain it from the pre-DR1113 model to avoid breaking
+    // code.
+    //
+    // C++11 [basic.link]p4:
+    //   An unnamed namespace or a namespace declared directly or indirectly
+    //   within an unnamed namespace has internal linkage.
+    if ((!Var || !isFirstInExternCContext(Var)) &&
+        (!Func || !isFirstInExternCContext(Func)))
+      return LinkageInfo::internal();
+  }
+
   // Set up the defaults.
 
   // C99 6.2.2p5:
@@ -680,12 +697,6 @@ LinkageComputer::getLVForNamespaceScopeDecl(const 
NamedDecl *D,
   //   external.
   LinkageInfo LV = getExternalLinkageFor(D);
 
-  // Inherit linkage from the enclosing namespace, if there is any.
-  if (const auto *ND = dyn_cast<NamespaceDecl>(
-          D->getDeclContext()->getEnclosingNamespaceContext())) {
-    LV.setLinkage(ND->getLinkageInternal());
-  }
-
   if (!hasExplicitVisibilityAlready(computation)) {
     if (std::optional<Visibility> Vis = getExplicitVisibility(D, computation)) 
{
       LV.mergeVisibility(*Vis, true);
@@ -738,14 +749,6 @@ LinkageComputer::getLVForNamespaceScopeDecl(const 
NamedDecl *D,
 
   //     - a variable; or
   if (const auto *Var = dyn_cast<VarDecl>(D)) {
-    // FIXME: The check for extern "C" here is not justified by the standard
-    // wording, but we retain it from the pre-DR1113 model to avoid breaking
-    // code.
-    if (isFirstInExternCContext(Var)) {
-      LV.setLinkage(Linkage::External);
-      return LV;
-    }
-
     // GCC applies the following optimization to variables and static
     // data members, but not to functions:
     //
@@ -768,7 +771,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl 
*D,
     // Note that we don't want to make the variable non-external
     // because of this, but unique-external linkage suits us.
 
-    if (Context.getLangOpts().CPlusPlus && !IgnoreVarTypeLinkage) {
+    if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var) &&
+        !IgnoreVarTypeLinkage) {
       LinkageInfo TypeLV = getLVForType(*Var->getType(), computation);
       if (!isExternallyVisible(TypeLV.getLinkage()))
         return LinkageInfo::uniqueExternal();
@@ -813,27 +817,18 @@ LinkageComputer::getLVForNamespaceScopeDecl(const 
NamedDecl *D,
     // merging storage classes and visibility attributes, so we don't have to
     // look at previous decls in here.
 
-    // FIXME: The check for extern "C" here is not justified by the standard
-    // wording, but we retain it from the pre-DR1113 model to avoid breaking
-    // code.
-    if (isFirstInExternCContext(Function)) {
-      LV.setLinkage(Linkage::External);
-      return LV;
-    }
-
     // In C++, then if the type of the function uses a type with
     // unique-external linkage, it's not legally usable from outside
-    // this translation unit.
-    if (Context.getLangOpts().CPlusPlus) {
+    // this translation unit.  However, we should use the C linkage
+    // rules instead for extern "C" declarations.
+    if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Function)) 
{
       // Only look at the type-as-written. Otherwise, deducing the return type
       // of a function could change its linkage.
       QualType TypeAsWritten = Function->getType();
       if (TypeSourceInfo *TSI = Function->getTypeSourceInfo())
         TypeAsWritten = TSI->getType();
-      if (!isExternallyVisible(TypeAsWritten->getLinkage())) {
-        LV.mergeLinkage(LinkageInfo::uniqueExternal());
-        return LV;
-      }
+      if (!isExternallyVisible(TypeAsWritten->getLinkage()))
+        return LinkageInfo::uniqueExternal();
     }
 
     // Consider LV from the template and the template arguments.
@@ -881,13 +876,13 @@ LinkageComputer::getLVForNamespaceScopeDecl(const 
NamedDecl *D,
   //     An unnamed namespace or a namespace declared directly or indirectly
   //     within an unnamed namespace has internal linkage. All other namespaces
   //     have external linkage.
-  } else if (auto *ND = dyn_cast<NamespaceDecl>(D)) {
-    if (ND->isAnonymousNamespace()) {
-      LV.mergeLinkage(Linkage::Internal);
-    }
+  //
+  // We handled names in anonymous namespaces above.
+  } else if (isa<NamespaceDecl>(D)) {
+    return LV;
 
-    // By extension, we assign external linkage to Objective-C
-    // interfaces.
+  // By extension, we assign external linkage to Objective-C
+  // interfaces.
   } else if (isa<ObjCInterfaceDecl>(D)) {
     // fallout
 
diff --git a/clang/test/AST/ast-dump-linkage-internal.cpp 
b/clang/test/AST/ast-dump-linkage-internal.cpp
index 10558526fbbdd..6b961301c4abb 100644
--- a/clang/test/AST/ast-dump-linkage-internal.cpp
+++ b/clang/test/AST/ast-dump-linkage-internal.cpp
@@ -1,7 +1,6 @@
 // RUN: %clang_cc1 -ast-dump -std=c++2c %s | FileCheck --match-full-lines %s
 
 namespace std {
-// CHECK: |-NamespaceDecl {{.*}} std external-linkage
 template <typename T>
 struct initializer_list {
   const T* begin;
@@ -10,7 +9,8 @@ struct initializer_list {
 } // namespace std
 
 namespace {
-// CHECK: |-NamespaceDecl {{.*}} internal-linkage
+// CHECK: |-NamespaceDecl {{.*}} external-linkage
+// FIXME: Unnamed namespaces have internal linkage.
 
 typedef int TypedefInt;
 // CHECK: | |-TypedefDecl {{.*}} TypedefInt 'int'
@@ -57,7 +57,7 @@ enum Enum {};
 // CHECK: | |-EnumDecl {{.*}} Enum internal-linkage
 
 enum { Enumerator };
-// CHECK: | |-EnumDecl {{.*}}
+// CHECK: | |-EnumDecl {{.*}} internal-linkage
 // CHECK: | | `-EnumConstantDecl {{.*}} referenced Enumerator '(anonymous 
namespace)::(unnamed enum at {{.*}})'
 
 decltype(Enumerator) f();
@@ -77,9 +77,6 @@ int Int = 0;
 const int ConstInt = 0;
 // CHECK: | |-VarDecl {{.*}} ConstInt 'const int' cinit internal-linkage
 
-extern "C" int ExternCInt;
-// CHECK: | | `-VarDecl {{.*}} ExternCInt 'int' external-linkage
-
 template <typename T>
 T TemplatedVar = T{};
 // CHECK: | |-VarTemplateDecl {{.*}} TemplatedVar internal-linkage
@@ -125,9 +122,6 @@ namespace Known {
 void FuncDecl();
 // CHECK: | | |-FunctionDecl {{.*}} FuncDecl 'void ()' internal-linkage
 
-extern "C" void ExternCFuncDecl();
-// CHECK: | | | `-FunctionDecl {{.*}} ExternCFuncDecl 'void ()' 
external-linkage
-
 constexpr void ConstexprFuncDecl();
 // CHECK: | | |-FunctionDecl{{.*}} constexpr ConstexprFuncDecl 'void ()' 
implicit-inline internal-linkage
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to