https://github.com/dschuff updated 
https://github.com/llvm/llvm-project/pull/201966

>From 4d28c014e95020e0753db092a82cb72c6720a578 Mon Sep 17 00:00:00 2001
From: Derek Schuff <[email protected]>
Date: Fri, 5 Jun 2026 23:26:49 +0000
Subject: [PATCH 1/3] [WebAssembly] Add support for import and export name
 attributes on global vars

Currently these are only supported on functions. This change adds support to
addrspace(1) global variables, which lower to wasm globals.
---
 clang/include/clang/Basic/Attr.td             |  6 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +-
 clang/lib/CodeGen/Targets/WebAssembly.cpp     | 58 +++++++++++++++---
 clang/lib/Sema/SemaWasm.cpp                   | 60 +++++++++++--------
 .../CodeGen/WebAssembly/wasm-global-export.c  |  8 +++
 .../CodeGen/WebAssembly/wasm-global-import.c  | 11 ++++
 .../CodeGen/WebAssembly/wasm-import-err-fun.c |  3 +
 .../CodeGen/WebAssembly/wasm-import-err-var.c |  5 ++
 llvm/lib/MC/WasmObjectWriter.cpp              |  8 +++
 .../WebAssembly/WebAssemblyAsmPrinter.cpp     | 39 ++++++++++++
 .../WebAssembly/export-metadata-global.ll     | 18 ++++++
 .../WebAssembly/import-metadata-global-err.ll |  9 +++
 .../WebAssembly/import-metadata-global.ll     | 26 ++++++++
 13 files changed, 216 insertions(+), 37 deletions(-)
 create mode 100644 clang/test/CodeGen/WebAssembly/wasm-global-export.c
 create mode 100644 clang/test/CodeGen/WebAssembly/wasm-global-import.c
 create mode 100644 clang/test/CodeGen/WebAssembly/wasm-import-err-fun.c
 create mode 100644 clang/test/CodeGen/WebAssembly/wasm-import-err-var.c
 create mode 100644 llvm/test/CodeGen/WebAssembly/export-metadata-global.ll
 create mode 100644 llvm/test/CodeGen/WebAssembly/import-metadata-global-err.ll
 create mode 100644 llvm/test/CodeGen/WebAssembly/import-metadata-global.ll

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index ec82a14e9393b..77f45dade1426 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2566,7 +2566,7 @@ def WebAssemblyExportName : InheritableAttr,
   let Spellings = [Clang<"export_name">];
   let Args = [StringArgument<"ExportName">];
   let Documentation = [WebAssemblyExportNameDocs];
-  let Subjects = SubjectList<[Function], ErrorDiag>;
+  let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag>;
 }
 
 def WebAssemblyImportModule : InheritableAttr,
@@ -2574,7 +2574,7 @@ def WebAssemblyImportModule : InheritableAttr,
   let Spellings = [Clang<"import_module">];
   let Args = [StringArgument<"ImportModule">];
   let Documentation = [WebAssemblyImportModuleDocs];
-  let Subjects = SubjectList<[Function], ErrorDiag>;
+  let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag>;
 }
 
 def WebAssemblyImportName : InheritableAttr,
@@ -2582,7 +2582,7 @@ def WebAssemblyImportName : InheritableAttr,
   let Spellings = [Clang<"import_name">];
   let Args = [StringArgument<"ImportName">];
   let Documentation = [WebAssemblyImportNameDocs];
-  let Subjects = SubjectList<[Function], ErrorDiag>;
+  let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag>;
 }
 
 def NoSplitStack : InheritableAttr {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4e3585b7b8191..0008db8fb1f05 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13399,7 +13399,7 @@ def warn_mismatched_import : Warning<
   "previous declaration">,
   InGroup<IgnoredAttributes>;
 def warn_import_on_definition : Warning<
-  "import %select{module|name}0 cannot be applied to a function with a 
definition">,
+  "import %select{module|name}0 cannot be applied to a 
%select{function|variable}1 with a definition">,
   InGroup<IgnoredAttributes>;
 
 def err_preserve_field_info_not_field : Error<
diff --git a/clang/lib/CodeGen/Targets/WebAssembly.cpp 
b/clang/lib/CodeGen/Targets/WebAssembly.cpp
index 71454982c4f82..3c99f3c116052 100644
--- a/clang/lib/CodeGen/Targets/WebAssembly.cpp
+++ b/clang/lib/CodeGen/Targets/WebAssembly.cpp
@@ -8,6 +8,7 @@
 
 #include "ABIInfoImpl.h"
 #include "TargetInfo.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 
 using namespace clang;
 using namespace clang::CodeGen;
@@ -57,17 +58,58 @@ class WebAssemblyTargetCodeGenInfo final : public 
TargetCodeGenInfo {
   void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
                            CodeGen::CodeGenModule &CGM) const override {
     TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
-    if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
-      if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
-        llvm::Function *Fn = cast<llvm::Function>(GV);
-        llvm::AttrBuilder B(GV->getContext());
-        B.addAttribute("wasm-import-module", Attr->getImportModule());
-        Fn->addFnAttrs(B);
+    if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
+      if (auto *Global = dyn_cast<llvm::GlobalVariable>(GV)) {
+        const auto *ModuleAttr = VD->getAttr<WebAssemblyImportModuleAttr>();
+        const auto *NameAttr = VD->getAttr<WebAssemblyImportNameAttr>();
+        if (ModuleAttr || NameAttr) {
+          if (VD->isThisDeclarationADefinition() != VarDecl::DeclarationOnly) {
+            auto AttrLoc = ModuleAttr ? ModuleAttr->getLocation() : 
NameAttr->getLocation();
+            CGM.getDiags().Report(AttrLoc, diag::err_fe_backend_unsupported)
+                << "import attribute cannot be applied to a definition";
+            return;
+          }
+          llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+          if (ModuleAttr) {
+            Global->setMetadata(
+                "wasm.import.module",
+                llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, 
ModuleAttr->getImportModule())));
+          }
+          if (NameAttr) {
+            Global->setMetadata(
+                "wasm.import.name",
+                llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, 
NameAttr->getImportName())));
+          }
+        }
+        if (const auto *Attr = VD->getAttr<WebAssemblyExportNameAttr>()) {
+          llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+          Global->setMetadata(
+              "wasm.export.name",
+              llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, 
Attr->getExportName())));
+        }
       }
-      if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
+      return;
+    }
+
+    if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+      const auto *ModuleAttr = FD->getAttr<WebAssemblyImportModuleAttr>();
+      const auto *NameAttr = FD->getAttr<WebAssemblyImportNameAttr>();
+      if (ModuleAttr || NameAttr) {
+        if (FD->isThisDeclarationADefinition()) {
+          auto AttrLoc = ModuleAttr ? ModuleAttr->getLocation() : 
NameAttr->getLocation();
+          CGM.getDiags().Report(AttrLoc, diag::err_fe_backend_unsupported)
+              << "import attribute cannot be applied to a definition";
+          auto *NonConstFD = const_cast<FunctionDecl *>(FD);
+          NonConstFD->dropAttr<WebAssemblyImportModuleAttr>();
+          NonConstFD->dropAttr<WebAssemblyImportNameAttr>();
+          return;
+        }
         llvm::Function *Fn = cast<llvm::Function>(GV);
         llvm::AttrBuilder B(GV->getContext());
-        B.addAttribute("wasm-import-name", Attr->getImportName());
+        if (ModuleAttr)
+          B.addAttribute("wasm-import-module", ModuleAttr->getImportModule());
+        if (NameAttr)
+          B.addAttribute("wasm-import-name", NameAttr->getImportName());
         Fn->addFnAttrs(B);
       }
       if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 083460eb6e201..9b75fc62dce85 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -358,49 +358,59 @@ SemaWasm::mergeImportNameAttr(Decl *D, const 
WebAssemblyImportNameAttr &AL) {
 
 void SemaWasm::handleWebAssemblyImportModuleAttr(Decl *D,
                                                  const ParsedAttr &AL) {
-  auto *FD = cast<FunctionDecl>(D);
-
   StringRef Str;
   SourceLocation ArgLoc;
   if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
     return;
-  if (FD->hasBody()) {
-    Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
-    return;
-  }
 
-  FD->addAttr(::new (getASTContext())
-                  WebAssemblyImportModuleAttr(getASTContext(), AL, Str));
+  if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    if (FD->hasBody()) {
+      Diag(AL.getLoc(), diag::warn_import_on_definition) << 0 << 0;
+      return;
+    }
+    FD->addAttr(::new (getASTContext())
+                    WebAssemblyImportModuleAttr(getASTContext(), AL, Str));
+  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+    if (VD->isThisDeclarationADefinition() != VarDecl::DeclarationOnly) {
+      Diag(AL.getLoc(), diag::warn_import_on_definition) << 0 << 1;
+      return;
+    }
+    VD->addAttr(::new (getASTContext())
+                    WebAssemblyImportModuleAttr(getASTContext(), AL, Str));
+  }
 }
 
 void SemaWasm::handleWebAssemblyImportNameAttr(Decl *D, const ParsedAttr &AL) {
-  auto *FD = cast<FunctionDecl>(D);
-
   StringRef Str;
   SourceLocation ArgLoc;
   if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
     return;
-  if (FD->hasBody()) {
-    Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
-    return;
-  }
 
-  FD->addAttr(::new (getASTContext())
-                  WebAssemblyImportNameAttr(getASTContext(), AL, Str));
+  if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    if (FD->hasBody()) {
+      Diag(AL.getLoc(), diag::warn_import_on_definition) << 1 << 0;
+      return;
+    }
+    FD->addAttr(::new (getASTContext())
+                    WebAssemblyImportNameAttr(getASTContext(), AL, Str));
+  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+    if (VD->isThisDeclarationADefinition() != VarDecl::DeclarationOnly) {
+      Diag(AL.getLoc(), diag::warn_import_on_definition) << 1 << 1;
+      return;
+    }
+    VD->addAttr(::new (getASTContext())
+                    WebAssemblyImportNameAttr(getASTContext(), AL, Str));
+  }
 }
 
 void SemaWasm::handleWebAssemblyExportNameAttr(Decl *D, const ParsedAttr &AL) {
   ASTContext &Context = getASTContext();
-  if (!isFuncOrMethodForAttrSubject(D)) {
-    Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
-        << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
-    return;
-  }
 
-  auto *FD = cast<FunctionDecl>(D);
-  if (FD->isThisDeclarationADefinition()) {
-    Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
-    return;
+  if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    if (FD->isThisDeclarationADefinition()) {
+      Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
+      return;
+    }
   }
 
   StringRef Str;
diff --git a/clang/test/CodeGen/WebAssembly/wasm-global-export.c 
b/clang/test/CodeGen/WebAssembly/wasm-global-export.c
new file mode 100644
index 0000000000000..3ea1da0f20ef6
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-global-export.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | 
FileCheck %s
+
+// Test export_name
+int __attribute__((address_space(1))) exported_g
+    __attribute__((export_name("global_g"))) = 42;
+
+// CHECK: @exported_g = addrspace(1) global i32 42, align 4, !wasm.export.name 
![[MD_EXPORT:[0-9]+]]
+// CHECK: ![[MD_EXPORT]] = !{!"global_g"}
diff --git a/clang/test/CodeGen/WebAssembly/wasm-global-import.c 
b/clang/test/CodeGen/WebAssembly/wasm-global-import.c
new file mode 100644
index 0000000000000..7ea5ef874b3bd
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-global-import.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | 
FileCheck %s
+
+// Test import_module and import_name
+extern const int __attribute__((address_space(1))) imported_g
+    __attribute__((import_module("js"), import_name("global_g")));
+
+int get_import(void) { return imported_g; }
+
+// CHECK: @imported_g = external addrspace(1) constant i32, align 4, 
!wasm.import.module ![[MD_MOD:[0-9]+]], !wasm.import.name ![[MD_NAME:[0-9]+]]
+// CHECK: ![[MD_MOD]] = !{!"js"}
+// CHECK: ![[MD_NAME]] = !{!"global_g"}
diff --git a/clang/test/CodeGen/WebAssembly/wasm-import-err-fun.c 
b/clang/test/CodeGen/WebAssembly/wasm-import-err-fun.c
new file mode 100644
index 0000000000000..c819f8a4e6b5e
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-import-err-fun.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm-only -verify 
%s
+
+void defined_fn(void) __attribute__((import_module("js"))) {} // 
expected-error {{import attribute cannot be applied to a definition}}
diff --git a/clang/test/CodeGen/WebAssembly/wasm-import-err-var.c 
b/clang/test/CodeGen/WebAssembly/wasm-import-err-var.c
new file mode 100644
index 0000000000000..31cfeddcdba7f
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-import-err-var.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm-only 
-Wno-extern-initializer -verify %s
+
+// Test definition inline
+extern const int __attribute__((address_space(1))) defined_g_inline
+    __attribute__((import_module("js"))) = 42; // expected-error {{import 
attribute cannot be applied to a definition}}
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 44ca69f0ff302..be970ea3df7ee 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -1672,6 +1672,14 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler 
&Asm,
           assert(!WasmIndices.contains(&WS));
           WasmIndices[&WS] = Global.Index;
           Globals.push_back(Global);
+
+          if (WS.hasExportName()) {
+            wasm::WasmExport Export;
+            Export.Name = WS.getExportName();
+            Export.Kind = wasm::WASM_EXTERNAL_GLOBAL;
+            Export.Index = Global.Index;
+            Exports.push_back(Export);
+          }
         } else {
           // An import; the index was assigned above
           LLVM_DEBUG(dbgs() << "  -> global index: "
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index c25972343c96a..8bddc9068359b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -179,6 +179,18 @@ MCSymbolWasm 
*WebAssemblyAsmPrinter::getMCSymbolForFunction(
   return WasmSym;
 }
 
+static StringRef getWasmMetadata(const GlobalVariable &GV, StringRef Key) {
+  MDNode *MD = GV.getMetadata(Key);
+  if (!MD || MD->getNumOperands() == 0)
+    return {};
+
+  auto *Name = dyn_cast<MDString>(MD->getOperand(0));
+  if (!Name)
+    return {};
+
+  return Name->getString();
+}
+
 void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
   if (GV->hasCommonLinkage()) {
     OutContext.reportError(SMLoc(),
@@ -187,6 +199,16 @@ void WebAssemblyAsmPrinter::emitGlobalVariable(const 
GlobalVariable *GV) {
     return;
   }
 
+  if (!GV->isDeclaration()) {
+    if (!getWasmMetadata(*GV, "wasm.import.module").empty() ||
+        !getWasmMetadata(*GV, "wasm.import.name").empty()) {
+      OutContext.reportError(SMLoc(),
+                             "definition of global '" + GV->getName() +
+                                 "' cannot have import metadata");
+      return;
+    }
+  }
+
   if (!WebAssembly::isWasmVarAddressSpace(GV->getAddressSpace())) {
     AsmPrinter::emitGlobalVariable(GV);
     return;
@@ -211,10 +233,27 @@ void WebAssemblyAsmPrinter::emitGlobalVariable(const 
GlobalVariable *GV) {
 
   emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());
   emitSymbolType(Sym);
+  if (GV->isDeclaration()) {
+    StringRef ImportModule = getWasmMetadata(*GV, "wasm.import.module");
+    if (!ImportModule.empty()) {
+      Sym->setImportModule(OutContext.allocateString(ImportModule));
+      getTargetStreamer()->emitImportModule(Sym, ImportModule);
+    }
+    StringRef ImportName = getWasmMetadata(*GV, "wasm.import.name");
+    if (!ImportName.empty()) {
+      Sym->setImportName(OutContext.allocateString(ImportName));
+      getTargetStreamer()->emitImportName(Sym, ImportName);
+    }
+  }
   if (GV->hasInitializer()) {
     assert(getSymbolPreferLocal(*GV) == Sym);
     emitLinkage(GV, Sym);
     OutStreamer->emitLabel(Sym);
+    StringRef ExportName = getWasmMetadata(*GV, "wasm.export.name");
+    if (!ExportName.empty()) {
+      Sym->setExportName(OutContext.allocateString(ExportName));
+      getTargetStreamer()->emitExportName(Sym, ExportName);
+    }
     // TODO: Actually emit the initializer value.  Otherwise the global has the
     // default value for its type (0, ref.null, etc).
     OutStreamer->addBlankLine();
diff --git a/llvm/test/CodeGen/WebAssembly/export-metadata-global.ll 
b/llvm/test/CodeGen/WebAssembly/export-metadata-global.ll
new file mode 100644
index 0000000000000..e7dbf0e4c29c5
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/export-metadata-global.ll
@@ -0,0 +1,18 @@
+; RUN: llc < %s -asm-verbose=false | FileCheck --check-prefix=ASM %s
+; RUN: llc < %s --filetype=obj | obj2yaml | FileCheck --check-prefix=OBJ %s
+
+target triple = "wasm32-unknown-unknown"
+
+@exported_g = addrspace(1) global i32 42, !wasm.export.name !0
+
+; ASM: .globaltype exported_g, i32
+; ASM: exported_g:
+; ASM-NEXT: .export_name exported_g, "global_g"
+
+; OBJ:      - Type:            EXPORT
+; OBJ:        Exports:
+; OBJ:          - Name:            global_g
+; OBJ-NEXT:       Kind:            GLOBAL
+; OBJ-NEXT:       Index:           0
+
+!0 = !{!"global_g"}
diff --git a/llvm/test/CodeGen/WebAssembly/import-metadata-global-err.ll 
b/llvm/test/CodeGen/WebAssembly/import-metadata-global-err.ll
new file mode 100644
index 0000000000000..b678884b6504b
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/import-metadata-global-err.ll
@@ -0,0 +1,9 @@
+; RUN: not llc < %s 2>&1 | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+@g = global i32 42, !wasm.import.module !0
+
+; CHECK: error: definition of global 'g' cannot have import metadata
+
+!0 = !{!"js"}
diff --git a/llvm/test/CodeGen/WebAssembly/import-metadata-global.ll 
b/llvm/test/CodeGen/WebAssembly/import-metadata-global.ll
new file mode 100644
index 0000000000000..a3a052ec1534d
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/import-metadata-global.ll
@@ -0,0 +1,26 @@
+; RUN: llc < %s -asm-verbose=false | FileCheck --check-prefix=ASM %s
+; RUN: llc < %s --filetype=obj | obj2yaml | FileCheck --check-prefix=OBJ %s
+
+target triple = "wasm32-unknown-unknown"
+
+@imported_g = external addrspace(1) global i32, !wasm.import.module !0, 
!wasm.import.name !1
+
+define i32 @get() {
+  %v = load i32, ptr addrspace(1) @imported_g
+  ret i32 %v
+}
+
+; ASM: .globaltype imported_g, i32
+; ASM-NEXT: .import_module imported_g, "js"
+; ASM-NEXT: .import_name imported_g, "global_g"
+
+; OBJ:      - Type:            IMPORT
+; OBJ:        Imports:
+; OBJ:          - Module:          js
+; OBJ-NEXT:       Field:           global_g
+; OBJ-NEXT:       Kind:            GLOBAL
+; OBJ-NEXT:       GlobalType:      I32
+; OBJ-NEXT:       GlobalMutable:   true
+
+!0 = !{!"js"}
+!1 = !{!"global_g"}

>From 58096642dc484d8100d0c81f8a8c098d65a1750c Mon Sep 17 00:00:00 2001
From: Derek Schuff <[email protected]>
Date: Fri, 5 Jun 2026 23:57:03 +0000
Subject: [PATCH 2/3] update name merging logic and implement export name
 merging

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   2 +-
 clang/include/clang/Sema/SemaWasm.h           |   2 +
 clang/lib/Sema/SemaDecl.cpp                   |   6 +-
 clang/lib/Sema/SemaWasm.cpp                   | 101 +++++++++++++-----
 ...a-attribute-supported-attributes-list.test |   6 +-
 clang/test/Sema/attr-wasm.c                   |  23 +++-
 6 files changed, 107 insertions(+), 33 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0008db8fb1f05..2be3dc7351e46 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13395,7 +13395,7 @@ def err_builtin_matrix_invalid_member
     : Error<"invalid matrix member '%0' expected %1">;
 
 def warn_mismatched_import : Warning<
-  "import %select{module|name}0 (%1) does not match the import 
%select{module|name}0 (%2) of the "
+  "%select{import module|import name|export name}0 (%1) does not match the 
%select{import module|import name|export name}0 (%2) of the "
   "previous declaration">,
   InGroup<IgnoredAttributes>;
 def warn_import_on_definition : Warning<
diff --git a/clang/include/clang/Sema/SemaWasm.h 
b/clang/include/clang/Sema/SemaWasm.h
index f82590755d183..c70cda259029e 100644
--- a/clang/include/clang/Sema/SemaWasm.h
+++ b/clang/include/clang/Sema/SemaWasm.h
@@ -44,6 +44,8 @@ class SemaWasm : public SemaBase {
   mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL);
   WebAssemblyImportModuleAttr *
   mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL);
+  WebAssemblyExportNameAttr *
+  mergeExportNameAttr(Decl *D, const WebAssemblyExportNameAttr &AL);
 
   void handleWebAssemblyExportNameAttr(Decl *D, const ParsedAttr &AL);
   void handleWebAssemblyImportModuleAttr(Decl *D, const ParsedAttr &AL);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index cddcf3a010279..4d31159bfeb68 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2987,6 +2987,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
     NewAttr = S.Wasm().mergeImportModuleAttr(D, *IMA);
   else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr))
     NewAttr = S.Wasm().mergeImportNameAttr(D, *INA);
+  else if (const auto *ENA = dyn_cast<WebAssemblyExportNameAttr>(Attr))
+    NewAttr = S.Wasm().mergeExportNameAttr(D, *ENA);
   else if (const auto *TCBA = dyn_cast<EnforceTCBAttr>(Attr))
     NewAttr = S.mergeEnforceTCBAttr(D, *TCBA);
   else if (const auto *TCBLA = dyn_cast<EnforceTCBLeafAttr>(Attr))
@@ -15384,14 +15386,14 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
   }
 
   if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) {
-    if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) {
+    if (!Attr->isInherited() && !Attr->isImplicit() && 
!VD->isThisDeclarationADefinition()) {
       Diag(Attr->getLocation(), diag::warn_attribute_ignored_on_non_definition)
           << Attr;
       VD->dropAttr<UsedAttr>();
     }
   }
   if (RetainAttr *Attr = VD->getAttr<RetainAttr>()) {
-    if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) {
+    if (!Attr->isInherited() && !Attr->isImplicit() && 
!VD->isThisDeclarationADefinition()) {
       Diag(Attr->getLocation(), diag::warn_attribute_ignored_on_non_definition)
           << Attr;
       VD->dropAttr<RetainAttr>();
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 9b75fc62dce85..4ea95617892c3 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -317,20 +317,33 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const 
TargetInfo &TI,
 
 WebAssemblyImportModuleAttr *
 SemaWasm::mergeImportModuleAttr(Decl *D,
-                                const WebAssemblyImportModuleAttr &AL) {
-  auto *FD = cast<FunctionDecl>(D);
-
-  if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
-    if (ExistingAttr->getImportModule() == AL.getImportModule())
+                                 const WebAssemblyImportModuleAttr &AL) {
+  if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) 
{
+      if (ExistingAttr->getImportModule() == AL.getImportModule())
+        return nullptr;
+      Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
+          << 0 << ExistingAttr->getImportModule() << AL.getImportModule();
+      Diag(AL.getLoc(), diag::note_previous_attribute);
       return nullptr;
-    Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
-        << 0 << ExistingAttr->getImportModule() << AL.getImportModule();
-    Diag(AL.getLoc(), diag::note_previous_attribute);
-    return nullptr;
-  }
-  if (FD->hasBody()) {
-    Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
-    return nullptr;
+    }
+    if (FD->hasBody()) {
+      Diag(AL.getLoc(), diag::warn_import_on_definition) << 0 << 0;
+      return nullptr;
+    }
+  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+    if (const auto *ExistingAttr = VD->getAttr<WebAssemblyImportModuleAttr>()) 
{
+      if (ExistingAttr->getImportModule() == AL.getImportModule())
+        return nullptr;
+      Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
+          << 0 << ExistingAttr->getImportModule() << AL.getImportModule();
+      Diag(AL.getLoc(), diag::note_previous_attribute);
+      return nullptr;
+    }
+    if (VD->isThisDeclarationADefinition() != VarDecl::DeclarationOnly) {
+      Diag(AL.getLoc(), diag::warn_import_on_definition) << 0 << 1;
+      return nullptr;
+    }
   }
   return ::new (getASTContext())
       WebAssemblyImportModuleAttr(getASTContext(), AL, AL.getImportModule());
@@ -338,24 +351,62 @@ SemaWasm::mergeImportModuleAttr(Decl *D,
 
 WebAssemblyImportNameAttr *
 SemaWasm::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) {
-  auto *FD = cast<FunctionDecl>(D);
-
-  if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
-    if (ExistingAttr->getImportName() == AL.getImportName())
+  if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
+      if (ExistingAttr->getImportName() == AL.getImportName())
+        return nullptr;
+      Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
+          << 1 << ExistingAttr->getImportName() << AL.getImportName();
+      Diag(AL.getLoc(), diag::note_previous_attribute);
       return nullptr;
-    Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
-        << 1 << ExistingAttr->getImportName() << AL.getImportName();
-    Diag(AL.getLoc(), diag::note_previous_attribute);
-    return nullptr;
-  }
-  if (FD->hasBody()) {
-    Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
-    return nullptr;
+    }
+    if (FD->hasBody()) {
+      Diag(AL.getLoc(), diag::warn_import_on_definition) << 1 << 0;
+      return nullptr;
+    }
+  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+    if (const auto *ExistingAttr = VD->getAttr<WebAssemblyImportNameAttr>()) {
+      if (ExistingAttr->getImportName() == AL.getImportName())
+        return nullptr;
+      Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
+          << 1 << ExistingAttr->getImportName() << AL.getImportName();
+      Diag(AL.getLoc(), diag::note_previous_attribute);
+      return nullptr;
+    }
+    if (VD->isThisDeclarationADefinition() != VarDecl::DeclarationOnly) {
+      Diag(AL.getLoc(), diag::warn_import_on_definition) << 1 << 1;
+      return nullptr;
+    }
   }
   return ::new (getASTContext())
       WebAssemblyImportNameAttr(getASTContext(), AL, AL.getImportName());
 }
 
+WebAssemblyExportNameAttr *
+SemaWasm::mergeExportNameAttr(Decl *D, const WebAssemblyExportNameAttr &AL) {
+  if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    if (const auto *ExistingAttr = FD->getAttr<WebAssemblyExportNameAttr>()) {
+      if (ExistingAttr->getExportName() == AL.getExportName())
+        return nullptr;
+      Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
+          << 2 << ExistingAttr->getExportName() << AL.getExportName();
+      Diag(AL.getLoc(), diag::note_previous_attribute);
+      return nullptr;
+    }
+  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+    if (const auto *ExistingAttr = VD->getAttr<WebAssemblyExportNameAttr>()) {
+      if (ExistingAttr->getExportName() == AL.getExportName())
+        return nullptr;
+      Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
+          << 2 << ExistingAttr->getExportName() << AL.getExportName();
+      Diag(AL.getLoc(), diag::note_previous_attribute);
+      return nullptr;
+    }
+  }
+  return ::new (getASTContext())
+      WebAssemblyExportNameAttr(getASTContext(), AL, AL.getExportName());
+}
+
 void SemaWasm::handleWebAssemblyImportModuleAttr(Decl *D,
                                                  const ParsedAttr &AL) {
   StringRef Str;
diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test 
b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index 03b9a77ec1814..d284370647f29 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -234,9 +234,9 @@
 // CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, 
SubjectMatchRule_enum, SubjectMatchRule_record, 
SubjectMatchRule_hasType_functionType, SubjectMatchRule_type_alias)
 // CHECK-NEXT: Weak (SubjectMatchRule_variable, SubjectMatchRule_function, 
SubjectMatchRule_record)
 // CHECK-NEXT: WeakRef (SubjectMatchRule_variable, SubjectMatchRule_function)
-// CHECK-NEXT: WebAssemblyExportName (SubjectMatchRule_function)
-// CHECK-NEXT: WebAssemblyImportModule (SubjectMatchRule_function)
-// CHECK-NEXT: WebAssemblyImportName (SubjectMatchRule_function)
+// CHECK-NEXT: WebAssemblyExportName (SubjectMatchRule_function, 
SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: WebAssemblyImportModule (SubjectMatchRule_function, 
SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: WebAssemblyImportName (SubjectMatchRule_function, 
SubjectMatchRule_variable_is_global)
 // CHECK-NEXT: WorkGroupSizeHint (SubjectMatchRule_function)
 // CHECK-NEXT: XRayInstrument (SubjectMatchRule_function, 
SubjectMatchRule_objc_method)
 // CHECK-NEXT: XRayLogArgs (SubjectMatchRule_function, 
SubjectMatchRule_objc_method)
diff --git a/clang/test/Sema/attr-wasm.c b/clang/test/Sema/attr-wasm.c
index 9d380da460888..5c05a5fb33372 100644
--- a/clang/test/Sema/attr-wasm.c
+++ b/clang/test/Sema/attr-wasm.c
@@ -2,7 +2,8 @@
 
 void name_a(void) __attribute__((import_name)); //expected-error 
{{'import_name' attribute takes one argument}}
 
-int name_b __attribute__((import_name("foo"))); //expected-error 
{{'import_name' attribute only applies to functions}}
+extern int name_b __attribute__((import_name("foo")));
+int name_b_def __attribute__((import_name("foo"))); //expected-warning 
{{import name cannot be applied to a variable with a definition}}
 
 void name_c(void) __attribute__((import_name("foo", "bar"))); //expected-error 
{{'import_name' attribute takes one argument}}
 
@@ -14,7 +15,8 @@ void name_z(void) __attribute__((import_name("bar"))); 
//expected-warning {{impo
 
 void module_a(void) __attribute__((import_module)); //expected-error 
{{'import_module' attribute takes one argument}}
 
-int module_b __attribute__((import_module("foo"))); //expected-error 
{{'import_module' attribute only applies to functions}}
+extern int module_b __attribute__((import_module("foo")));
+int module_b_def __attribute__((import_module("foo"))); //expected-warning 
{{import module cannot be applied to a variable with a definition}}
 
 void module_c(void) __attribute__((import_module("foo", "bar"))); 
//expected-error {{'import_module' attribute takes one argument}}
 
@@ -25,3 +27,20 @@ void module_z(void) __attribute__((import_module("foo"))); 
//expected-note {{pre
 void module_z(void) __attribute__((import_module("bar"))); //expected-warning 
{{import module (bar) does not match the import module (foo) of the previous 
declaration}}
 
 void both(void) __attribute__((import_name("foo"), import_module("bar")));
+
+// export_name tests
+void export_a(void) __attribute__((export_name)); //expected-error 
{{'export_name' attribute takes one argument}}
+void export_b(void) __attribute__((export_name("foo", "bar"))); 
//expected-error {{'export_name' attribute takes one argument}}
+
+void export_c(void) __attribute__((export_name("foo"))); //expected-note 
{{previous attribute is here}}
+void export_c(void) __attribute__((export_name("bar"))); //expected-warning 
{{export name (bar) does not match the export name (foo) of the previous 
declaration}}
+
+extern int export_d __attribute__((export_name("foo"))); //expected-note 
{{previous attribute is here}}
+extern int export_d __attribute__((export_name("bar"))); //expected-warning 
{{export name (bar) does not match the export name (foo) of the previous 
declaration}}
+
+// Variable mismatch tests for import_module/name
+extern int name_z_var __attribute__((import_name("foo"))); //expected-note 
{{previous attribute is here}}
+extern int name_z_var __attribute__((import_name("bar"))); //expected-warning 
{{import name (bar) does not match the import name (foo) of the previous 
declaration}}
+
+extern int module_z_var __attribute__((import_module("foo"))); //expected-note 
{{previous attribute is here}}
+extern int module_z_var __attribute__((import_module("bar"))); 
//expected-warning {{import module (bar) does not match the import module (foo) 
of the previous declaration}}

>From 8a000329851dd1f2fe23ed3892718149c819ca52 Mon Sep 17 00:00:00 2001
From: Derek Schuff <[email protected]>
Date: Fri, 5 Jun 2026 23:57:31 +0000
Subject: [PATCH 3/3] clang-format

---
 clang/lib/CodeGen/Targets/WebAssembly.cpp        | 16 +++++++++++-----
 clang/lib/Sema/SemaDecl.cpp                      |  6 ++++--
 clang/lib/Sema/SemaWasm.cpp                      |  2 +-
 .../Target/WebAssembly/WebAssemblyAsmPrinter.cpp |  5 ++---
 4 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/WebAssembly.cpp 
b/clang/lib/CodeGen/Targets/WebAssembly.cpp
index 3c99f3c116052..f6822ac8c70ab 100644
--- a/clang/lib/CodeGen/Targets/WebAssembly.cpp
+++ b/clang/lib/CodeGen/Targets/WebAssembly.cpp
@@ -64,7 +64,8 @@ class WebAssemblyTargetCodeGenInfo final : public 
TargetCodeGenInfo {
         const auto *NameAttr = VD->getAttr<WebAssemblyImportNameAttr>();
         if (ModuleAttr || NameAttr) {
           if (VD->isThisDeclarationADefinition() != VarDecl::DeclarationOnly) {
-            auto AttrLoc = ModuleAttr ? ModuleAttr->getLocation() : 
NameAttr->getLocation();
+            auto AttrLoc = ModuleAttr ? ModuleAttr->getLocation()
+                                      : NameAttr->getLocation();
             CGM.getDiags().Report(AttrLoc, diag::err_fe_backend_unsupported)
                 << "import attribute cannot be applied to a definition";
             return;
@@ -73,19 +74,23 @@ class WebAssemblyTargetCodeGenInfo final : public 
TargetCodeGenInfo {
           if (ModuleAttr) {
             Global->setMetadata(
                 "wasm.import.module",
-                llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, 
ModuleAttr->getImportModule())));
+                llvm::MDNode::get(
+                    Ctx,
+                    llvm::MDString::get(Ctx, ModuleAttr->getImportModule())));
           }
           if (NameAttr) {
             Global->setMetadata(
                 "wasm.import.name",
-                llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, 
NameAttr->getImportName())));
+                llvm::MDNode::get(
+                    Ctx, llvm::MDString::get(Ctx, NameAttr->getImportName())));
           }
         }
         if (const auto *Attr = VD->getAttr<WebAssemblyExportNameAttr>()) {
           llvm::LLVMContext &Ctx = CGM.getLLVMContext();
           Global->setMetadata(
               "wasm.export.name",
-              llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, 
Attr->getExportName())));
+              llvm::MDNode::get(
+                  Ctx, llvm::MDString::get(Ctx, Attr->getExportName())));
         }
       }
       return;
@@ -96,7 +101,8 @@ class WebAssemblyTargetCodeGenInfo final : public 
TargetCodeGenInfo {
       const auto *NameAttr = FD->getAttr<WebAssemblyImportNameAttr>();
       if (ModuleAttr || NameAttr) {
         if (FD->isThisDeclarationADefinition()) {
-          auto AttrLoc = ModuleAttr ? ModuleAttr->getLocation() : 
NameAttr->getLocation();
+          auto AttrLoc =
+              ModuleAttr ? ModuleAttr->getLocation() : NameAttr->getLocation();
           CGM.getDiags().Report(AttrLoc, diag::err_fe_backend_unsupported)
               << "import attribute cannot be applied to a definition";
           auto *NonConstFD = const_cast<FunctionDecl *>(FD);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4d31159bfeb68..777f97e30e436 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15386,14 +15386,16 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
   }
 
   if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) {
-    if (!Attr->isInherited() && !Attr->isImplicit() && 
!VD->isThisDeclarationADefinition()) {
+    if (!Attr->isInherited() && !Attr->isImplicit() &&
+        !VD->isThisDeclarationADefinition()) {
       Diag(Attr->getLocation(), diag::warn_attribute_ignored_on_non_definition)
           << Attr;
       VD->dropAttr<UsedAttr>();
     }
   }
   if (RetainAttr *Attr = VD->getAttr<RetainAttr>()) {
-    if (!Attr->isInherited() && !Attr->isImplicit() && 
!VD->isThisDeclarationADefinition()) {
+    if (!Attr->isInherited() && !Attr->isImplicit() &&
+        !VD->isThisDeclarationADefinition()) {
       Diag(Attr->getLocation(), diag::warn_attribute_ignored_on_non_definition)
           << Attr;
       VD->dropAttr<RetainAttr>();
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 4ea95617892c3..c3f531f15d1f3 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -317,7 +317,7 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const 
TargetInfo &TI,
 
 WebAssemblyImportModuleAttr *
 SemaWasm::mergeImportModuleAttr(Decl *D,
-                                 const WebAssemblyImportModuleAttr &AL) {
+                                const WebAssemblyImportModuleAttr &AL) {
   if (auto *FD = dyn_cast<FunctionDecl>(D)) {
     if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) 
{
       if (ExistingAttr->getImportModule() == AL.getImportModule())
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 8bddc9068359b..f97ea54dcdf91 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -202,9 +202,8 @@ void WebAssemblyAsmPrinter::emitGlobalVariable(const 
GlobalVariable *GV) {
   if (!GV->isDeclaration()) {
     if (!getWasmMetadata(*GV, "wasm.import.module").empty() ||
         !getWasmMetadata(*GV, "wasm.import.name").empty()) {
-      OutContext.reportError(SMLoc(),
-                             "definition of global '" + GV->getName() +
-                                 "' cannot have import metadata");
+      OutContext.reportError(SMLoc(), "definition of global '" + GV->getName() 
+
+                                          "' cannot have import metadata");
       return;
     }
   }

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

Reply via email to