https://github.com/dschuff created 
https://github.com/llvm/llvm-project/pull/221363

Allow the export_name attribute to be specified without arguments on
functions and global variables. When no argument is provided, the symbol
is exported using its linkage name (its mangled name in C++, or unmangled
name in C / extern "C").


>From d2e159235ae02926aa1f11de0572847767d219be Mon Sep 17 00:00:00 2001
From: Derek Schuff <[email protected]>
Date: Fri, 4 Sep 2026 16:04:08 -0700
Subject: [PATCH] [WebAssembly] Support 0-argument export_name to export with
 linkage name

Allow the export_name attribute to be specified without arguments on
functions and global variables. When no argument is provided, the symbol
is exported using its linkage name (its mangled name in C++, or unmangled
name in C / extern "C").
---
 clang/include/clang/Basic/Attr.td             |  2 +-
 clang/lib/CodeGen/Targets/WebAssembly.cpp     | 10 +++++--
 clang/lib/Sema/SemaWasm.cpp                   |  8 +++--
 .../CodeGen/WebAssembly/wasm-export-name.c    |  8 ++++-
 .../CodeGen/WebAssembly/wasm-global-export.c  | 19 +++++++++---
 clang/test/CodeGenCXX/wasm-export-name.cpp    | 29 +++++++++++++++++++
 clang/test/Sema/attr-wasm.c                   |  6 ++--
 7 files changed, 68 insertions(+), 14 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/wasm-export-name.cpp

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index a576411097b9d..d1b8582ede0a2 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2581,7 +2581,7 @@ def BPFFastCall : InheritableAttr,
 def WebAssemblyExportName : InheritableAttr,
                             TargetSpecificAttr<TargetWebAssembly> {
   let Spellings = [Clang<"export_name">];
-  let Args = [StringArgument<"ExportName">];
+  let Args = [StringArgument<"ExportName", 1>];
   let Documentation = [WebAssemblyExportNameDocs];
   let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag>;
 }
diff --git a/clang/lib/CodeGen/Targets/WebAssembly.cpp 
b/clang/lib/CodeGen/Targets/WebAssembly.cpp
index 8f6f58bfb807e..6b988b542c5d6 100644
--- a/clang/lib/CodeGen/Targets/WebAssembly.cpp
+++ b/clang/lib/CodeGen/Targets/WebAssembly.cpp
@@ -89,7 +89,10 @@ class WebAssemblyTargetCodeGenInfo final : public 
TargetCodeGenInfo {
           Global->addAttribute("wasm-import-name", NameAttr->getImportName());
       }
       if (const auto *Attr = VD->getAttr<WebAssemblyExportNameAttr>()) {
-        Global->addAttribute("wasm-export-name", Attr->getExportName());
+        StringRef Name = Attr->getExportName();
+        if (Name.empty())
+          Name = Global->getName();
+        Global->addAttribute("wasm-export-name", Name);
       }
     } else if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
       auto *Fn = cast<llvm::Function>(GV);
@@ -116,7 +119,10 @@ class WebAssemblyTargetCodeGenInfo final : public 
TargetCodeGenInfo {
           Fn->addFnAttr("wasm-import-name", NameAttr->getImportName());
       }
       if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
-        Fn->addFnAttr("wasm-export-name", Attr->getExportName());
+        StringRef Name = Attr->getExportName();
+        if (Name.empty())
+          Name = Fn->getName();
+        Fn->addFnAttr("wasm-export-name", Name);
       }
 
       if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype())
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index cfc0a08a50e5a..07bf922a14482 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -449,9 +449,11 @@ void SemaWasm::handleWebAssemblyExportNameAttr(Decl *D, 
const ParsedAttr &AL) {
   ASTContext &Context = getASTContext();
 
   StringRef Str;
-  SourceLocation ArgLoc;
-  if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
-    return;
+  if (AL.getNumArgs() > 0) {
+    SourceLocation ArgLoc;
+    if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
+      return;
+  }
 
   D->addAttr(::new (Context) WebAssemblyExportNameAttr(Context, AL, Str));
   D->addAttr(UsedAttr::CreateImplicit(Context));
diff --git a/clang/test/CodeGen/WebAssembly/wasm-export-name.c 
b/clang/test/CodeGen/WebAssembly/wasm-export-name.c
index 3793842895a34..f6bfddeeeb70a 100644
--- a/clang/test/CodeGen/WebAssembly/wasm-export-name.c
+++ b/clang/test/CodeGen/WebAssembly/wasm-export-name.c
@@ -6,8 +6,14 @@ int foo(void) {
   return 43;
 }
 
-// CHECK: @llvm.used = appending global [1 x ptr] [ptr @foo]
+int __attribute__((export_name)) default_func(void) {
+  return 44;
+}
+
+// CHECK: @llvm.used = appending global [2 x ptr] [ptr @foo, ptr @default_func]
 
 // CHECK: define i32 @foo() [[A:#[0-9]+]]
+// CHECK: define i32 @default_func() [[B:#[0-9]+]]
 
 // CHECK: attributes [[A]] = {{{.*}} "wasm-export-name"="bar" {{.*}}}
+// CHECK: attributes [[B]] = {{{.*}} "wasm-export-name"="default_func" {{.*}}}
diff --git a/clang/test/CodeGen/WebAssembly/wasm-global-export.c 
b/clang/test/CodeGen/WebAssembly/wasm-global-export.c
index e20009c1e35b3..898749e0b48d4 100644
--- a/clang/test/CodeGen/WebAssembly/wasm-global-export.c
+++ b/clang/test/CodeGen/WebAssembly/wasm-global-export.c
@@ -4,17 +4,28 @@
 int __attribute__((address_space(1))) exported_g
     __attribute__((export_name("global_g"))) = 42;
 
+// Test export_name without argument on addrspace(1) global
+int __attribute__((address_space(1))) exported_default_g
+    __attribute__((export_name)) = 43;
+
 // Test export_name with explicit name on addrspace(0) memory global
 int exported_mem __attribute__((export_name("mem_g"))) = 100;
 
+// Test export_name without argument on addrspace(0) memory global
+int exported_mem_default __attribute__((export_name)) = 101;
+
 // Test export_name on forward declaration propagating to definition
 extern int var_propagate __attribute__((export_name("exported_propagate")));
 int var_propagate = 102;
 
 // CHECK: @exported_g = addrspace(1) global i32 42, align 4 #0
-// CHECK: @exported_mem = global i32 100, align 4 #1
-// CHECK: @var_propagate = global i32 102, align 4 #2
+// CHECK: @exported_default_g = addrspace(1) global i32 43, align 4 #1
+// CHECK: @exported_mem = global i32 100, align 4 #2
+// CHECK: @exported_mem_default = global i32 101, align 4 #3
+// CHECK: @var_propagate = global i32 102, align 4 #4
 
 // CHECK: attributes #0 = { "wasm-export-name"="global_g" }
-// CHECK: attributes #1 = { "wasm-export-name"="mem_g" }
-// CHECK: attributes #2 = { "wasm-export-name"="exported_propagate" }
+// CHECK: attributes #1 = { "wasm-export-name"="exported_default_g" }
+// CHECK: attributes #2 = { "wasm-export-name"="mem_g" }
+// CHECK: attributes #3 = { "wasm-export-name"="exported_mem_default" }
+// CHECK: attributes #4 = { "wasm-export-name"="exported_propagate" }
diff --git a/clang/test/CodeGenCXX/wasm-export-name.cpp 
b/clang/test/CodeGenCXX/wasm-export-name.cpp
new file mode 100644
index 0000000000000..8d18bb24fb487
--- /dev/null
+++ b/clang/test/CodeGenCXX/wasm-export-name.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | 
FileCheck %s
+
+namespace ns {
+  int __attribute__((export_name)) namespaced_var = 10;
+  void __attribute__((export_name)) namespaced_func() {}
+}
+
+int __attribute__((export_name)) overloaded(int x) { return x; }
+int __attribute__((export_name)) overloaded(double x) { return (int)x; }
+
+extern "C" {
+  int __attribute__((export_name)) extern_c_var = 20;
+  void __attribute__((export_name)) extern_c_func() {}
+}
+
+// CHECK: @_ZN2ns14namespaced_varE = global i32 10, align 4 [[VAR_NS:#[0-9]+]]
+// CHECK: @extern_c_var = global i32 20, align 4 [[VAR_EXTERN_C:#[0-9]+]]
+
+// CHECK: define void @_ZN2ns15namespaced_funcEv() [[FN_NS:#[0-9]+]]
+// CHECK: define {{.*}}i32 @_Z10overloadedi({{.*}}) [[FN_OVI:#[0-9]+]]
+// CHECK: define {{.*}}i32 @_Z10overloadedd({{.*}}) [[FN_OVD:#[0-9]+]]
+// CHECK: define void @extern_c_func() [[FN_EXTERN_C:#[0-9]+]]
+
+// CHECK: attributes [[VAR_NS]] = { 
"wasm-export-name"="_ZN2ns14namespaced_varE" }
+// CHECK: attributes [[VAR_EXTERN_C]] = { "wasm-export-name"="extern_c_var" }
+// CHECK: attributes [[FN_NS]] = { 
{{.*}}"wasm-export-name"="_ZN2ns15namespaced_funcEv" }
+// CHECK: attributes [[FN_OVI]] = { {{.*}}"wasm-export-name"="_Z10overloadedi" 
}
+// CHECK: attributes [[FN_OVD]] = { {{.*}}"wasm-export-name"="_Z10overloadedd" 
}
+// CHECK: attributes [[FN_EXTERN_C]] = { 
{{.*}}"wasm-export-name"="extern_c_func" }
diff --git a/clang/test/Sema/attr-wasm.c b/clang/test/Sema/attr-wasm.c
index 23cb212d6acc9..93ee15b62dcd3 100644
--- a/clang/test/Sema/attr-wasm.c
+++ b/clang/test/Sema/attr-wasm.c
@@ -29,9 +29,9 @@ void module_z(void) __attribute__((import_module("bar"))); 
//expected-warning {{
 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}}
-extern int export_a_var __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_a(void) __attribute__((export_name));
+extern int export_a_var __attribute__((export_name));
+void export_b(void) __attribute__((export_name("foo", "bar"))); 
//expected-error {{'export_name' attribute takes no more than 1 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}}

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

Reply via email to