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
