[clang] [WebAssembly] Enable musttail only when tail-call is enabled (PR #163618)
Jasmine Tang via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 31 15:19:20 PDT 2025
https://github.com/badumbatish updated https://github.com/llvm/llvm-project/pull/163618
>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/4] 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/4] 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);
}
>From 4e4c93923a7d8f774ab85c958fb8b42703653cae Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Fri, 31 Oct 2025 14:29:01 -0700
Subject: [PATCH 3/4] Address PR comments
---
clang/include/clang/Basic/Attr.td | 3 +--
clang/include/clang/Basic/DiagnosticCommonKinds.td | 2 --
clang/lib/Sema/SemaStmt.cpp | 1 +
clang/lib/Sema/SemaStmtAttr.cpp | 6 ------
clang/test/CodeGen/WebAssembly/musttail.c | 2 +-
5 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index fab4e1dca024b..a4e0899799871 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -483,7 +483,6 @@ 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"];
}
@@ -509,7 +508,7 @@ 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)> {
+def TargetMustTailAvaiable: TargetSpec {
let CustomCode = [{ Target.hasMustTail() }];
}
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index b0a928018cccd..6e50e225a8cc1 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -374,8 +374,6 @@ 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/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index afd6fa617058b..ae0bb616beb82 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -695,6 +695,7 @@ 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 6ba8832d2e76a..50acc83f1841c 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -672,12 +672,6 @@ 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 75ed7657a8087..37fed70028bbc 100644
--- a/clang/test/CodeGen/WebAssembly/musttail.c
+++ b/clang/test/CodeGen/WebAssembly/musttail.c
@@ -15,6 +15,6 @@ int foo(int x) {
int bar(int x)
{
- // notail-error at +1 {{'musttail' attribute is not supported on this target without tail-call feature}}
+ // notail-warning at +1 {{unknown attribute 'clang::musttail' ignored}}
[[clang::musttail]] return foo(1);
}
>From 7ea334eee72e0f24e7955f4c3c5b6bc98b496e42 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Fri, 31 Oct 2025 15:18:41 -0700
Subject: [PATCH 4/4] Add to changelog
---
clang/docs/ReleaseNotes.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 65b086caf3652..ffd2881453894 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -546,6 +546,8 @@ NetBSD Support
WebAssembly Support
^^^^^^^^^^^^^^^^^^^
+- Fix a bug so that __has_attribute(musttail) should not be true anymore when notail is not enabled.
+
AVR Support
^^^^^^^^^^^
More information about the cfe-commits
mailing list