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
