[clang] [WebAssembly] Enable musttail only when tail-call is enabled (PR #163618)
Jasmine Tang via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 15 12:22:48 PDT 2025
https://github.com/badumbatish created https://github.com/llvm/llvm-project/pull/163618
Fixes https://github.com/llvm/llvm-project/issues/163256
I'm unsure if this follows closely from the following so reviews are much appreciated
> We should add something to TargetInfo.h in Clang that different targets can override and then check that from SemaStmt.cpp. That handles the attribute being accepted at all. Then Attr.td should be modified to make MustTail a TargetSpecificAttr so that __has_attribute support behaves according to the target. This should be pretty straightforward, so marking as a good first issue. However, this might be the first target-specific statement attribute we support, so there could be some extra work involved.
>From f9c22f861739e52e77960ae8083490dfdf62d19e Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Wed, 15 Oct 2025 12:13:58 -0700
Subject: [PATCH 1/2] Precommit
---
clang/test/CodeGen/WebAssembly/musttail.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 clang/test/CodeGen/WebAssembly/musttail.c
diff --git a/clang/test/CodeGen/WebAssembly/musttail.c b/clang/test/CodeGen/WebAssembly/musttail.c
new file mode 100644
index 0000000000000..da100484e94f2
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/musttail.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=good
+// RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=good
+// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -o /dev/null -emit-llvm -verify=notail
+
+int foo(int x) {
+ return x;
+}
+
+#if __has_attribute(musttail)
+// good-warning at +2 {{HAS IT}}
+// notail-warning at +1 {{HAS IT}}
+#warning HAS IT
+#else
+#warning DOES NOT HAVE
+#endif
+
+int bar(int x)
+{
+ [[clang::musttail]] return foo(1);
+}
>From 26b9025acc1eaecd473196691ed5e23cfbabf88e Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Wed, 15 Oct 2025 12:14:04 -0700
Subject: [PATCH 2/2] Add must tail support
---
clang/include/clang/Basic/Attr.td | 7 ++++++-
clang/include/clang/Basic/DiagnosticCommonKinds.td | 2 ++
clang/include/clang/Basic/TargetInfo.h | 3 +++
clang/lib/Basic/TargetInfo.cpp | 1 +
clang/lib/Basic/Targets/WebAssembly.cpp | 3 +++
clang/lib/Sema/SemaStmt.cpp | 1 -
clang/lib/Sema/SemaStmtAttr.cpp | 6 ++++++
clang/test/CodeGen/WebAssembly/musttail.c | 8 ++++----
8 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 3cde249e286fa..fab4e1dca024b 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -483,6 +483,7 @@ def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
def TargetSPIRV : TargetArch<["spirv", "spirv32", "spirv64"]>;
def TargetWebAssembly : TargetArch<["wasm32", "wasm64"]>;
def TargetNVPTX : TargetArch<["nvptx", "nvptx64"]>;
+def TargetPowerPC : TargetArch<["ppc", "ppcle", "ppc64", "ppc64le"]>;
def TargetWindows : TargetSpec {
let OSes = ["Win32"];
}
@@ -508,6 +509,10 @@ def TargetMicrosoftRecordLayout : TargetArch<["x86", "x86_64", "arm", "thumb",
let CustomCode = [{ Target.hasMicrosoftRecordLayout() }];
}
+def TargetMustTailAvaiable: TargetArch<!listconcat(TargetARM.Arches, TargetAArch64.Arches, TargetAnyX86.Arches, TargetWebAssembly.Arches, TargetPowerPC.Arches)> {
+ let CustomCode = [{ Target.hasMustTail() }];
+}
+
def TargetELF : TargetSpec {
let ObjectFormats = ["ELF"];
}
@@ -1896,7 +1901,7 @@ def NoMerge : DeclOrStmtAttr {
"functions, statements and variables">;
}
-def MustTail : StmtAttr {
+def MustTail : StmtAttr, TargetSpecificAttr<TargetMustTailAvaiable> {
let Spellings = [Clang<"musttail">];
let Documentation = [MustTailDocs];
let Subjects = SubjectList<[ReturnStmt], ErrorDiag, "return statements">;
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 6e50e225a8cc1..b0a928018cccd 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -374,6 +374,8 @@ def err_ppc_impossible_musttail: Error<
>;
def err_aix_musttail_unsupported: Error<
"'musttail' attribute is not supported on AIX">;
+def err_wasm_musttail_unsupported: Error<
+ "'musttail' attribute is not supported on this target without tail-call feature">;
// Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index ceb16174e13e7..e2768bea1902e 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -229,6 +229,7 @@ class TargetInfo : public TransferrableTargetInfo,
protected:
// Target values set by the ctor of the actual target implementation. Default
// values are specified by the TargetInfo constructor.
+ bool HasMustTail;
bool BigEndian;
bool TLSSupported;
bool VLASupported;
@@ -669,6 +670,8 @@ class TargetInfo : public TransferrableTargetInfo,
: getLongFractScale() + 1;
}
+ virtual bool hasMustTail() const { return HasMustTail; }
+
/// Determine whether the __int128 type is supported on this target.
virtual bool hasInt128Type() const {
return (getPointerWidth(LangAS::Default) >= 64) ||
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index f4d7c1288cc04..9a5db6e164f66 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -59,6 +59,7 @@ static const LangASMap FakeAddrSpaceMap = {
TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
// Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
// SPARC. These should be overridden by concrete targets as needed.
+ HasMustTail = true;
BigEndian = !T.isLittleEndian();
TLSSupported = true;
VLASupported = true;
diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index 55ffe1df0ba08..5bbb7af4c2ca1 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -213,6 +213,7 @@ bool WebAssemblyTargetInfo::initFeatureMap(
bool WebAssemblyTargetInfo::handleTargetFeatures(
std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
+ HasMustTail = false;
for (const auto &Feature : Features) {
if (Feature == "+atomics") {
HasAtomics = true;
@@ -345,10 +346,12 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
}
if (Feature == "+tail-call") {
HasTailCall = true;
+ HasMustTail = true;
continue;
}
if (Feature == "-tail-call") {
HasTailCall = false;
+ HasMustTail = false;
continue;
}
if (Feature == "+wide-arithmetic") {
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index ae0bb616beb82..afd6fa617058b 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -695,7 +695,6 @@ bool Sema::checkMustTailAttr(const Stmt *St, const Attr &MTA) {
const Expr *E = cast<ReturnStmt>(St)->getRetValue();
const auto *CE = dyn_cast_or_null<CallExpr>(IgnoreParenImplicitAsWritten(E));
-
if (!CE) {
Diag(St->getBeginLoc(), diag::err_musttail_needs_call) << &MTA;
return false;
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 50acc83f1841c..6ba8832d2e76a 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -672,6 +672,12 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
!(A.existsInTarget(S.Context.getTargetInfo()) ||
(S.Context.getLangOpts().SYCLIsDevice && Aux &&
A.existsInTarget(*Aux)))) {
+ // Special case: musttail on WebAssembly without tail-call feature
+ if (A.getKind() == ParsedAttr::AT_MustTail &&
+ !S.Context.getTargetInfo().hasMustTail()) {
+ S.Diag(A.getLoc(), diag::err_wasm_musttail_unsupported);
+ return nullptr;
+ }
if (A.isRegularKeywordAttribute()) {
S.Diag(A.getLoc(), diag::err_keyword_not_supported_on_target)
<< A << A.getRange();
diff --git a/clang/test/CodeGen/WebAssembly/musttail.c b/clang/test/CodeGen/WebAssembly/musttail.c
index da100484e94f2..75ed7657a8087 100644
--- a/clang/test/CodeGen/WebAssembly/musttail.c
+++ b/clang/test/CodeGen/WebAssembly/musttail.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=good
-// RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=good
+// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=tail
// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -o /dev/null -emit-llvm -verify=notail
int foo(int x) {
@@ -7,14 +6,15 @@ int foo(int x) {
}
#if __has_attribute(musttail)
-// good-warning at +2 {{HAS IT}}
-// notail-warning at +1 {{HAS IT}}
+// tail-warning at +1 {{HAS IT}}
#warning HAS IT
#else
+// notail-warning at +1 {{DOES NOT HAVE}}
#warning DOES NOT HAVE
#endif
int bar(int x)
{
+ // notail-error at +1 {{'musttail' attribute is not supported on this target without tail-call feature}}
[[clang::musttail]] return foo(1);
}
More information about the cfe-commits
mailing list