[clang] [clang][bytecode] Use tailcalls via `[[clang::musttail]]` (PR #173756)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 2 03:18:34 PST 2026
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>,
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>,
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>,
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>,
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/173756 at github.com>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/173756
>From 91e1b64929800f76a031fd9a58bea87e497707c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 26 Dec 2025 09:07:13 +0100
Subject: [PATCH 1/6] Test
---
clang/lib/AST/ExprConstant.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8618979d1eba0..72e9193d89f5d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -931,7 +931,7 @@ namespace {
: Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
CallStackDepth(0), NextCallIndex(1),
StepsLeft(C.getLangOpts().ConstexprStepLimit),
- EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
+ EnableNewConstInterp(true),
BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
/*This=*/nullptr,
/*CallExpr=*/nullptr, CallRef()),
>From 8d5e63f54399bb8ef3049a0beabf67730cbec8c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 26 Dec 2025 09:06:45 +0100
Subject: [PATCH 2/6] musttail
---
clang/lib/AST/ByteCode/Interp.cpp | 44 +++++-----
clang/lib/AST/ByteCode/Interp.h | 7 +-
clang/utils/TableGen/ClangOpcodesEmitter.cpp | 87 ++++++++++++++++++++
3 files changed, 114 insertions(+), 24 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 889ac1e1a9a7e..af1bf76db865d 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -28,7 +28,8 @@
using namespace clang;
using namespace clang::interp;
-static bool RetValue(InterpState &S, CodePtr &Pt) {
+__attribute__((preserve_none)) static bool RetValue(InterpState &S,
+ CodePtr &Pt) {
llvm::report_fatal_error("Interpreter cannot return values");
}
@@ -2324,38 +2325,39 @@ bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {
return true;
}
-// https://github.com/llvm/llvm-project/issues/102513
-#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
-#pragma optimize("", off)
-#endif
+__attribute__((preserve_none)) static bool InterpNext(InterpState &S,
+ CodePtr &PC);
+
bool Interpret(InterpState &S) {
// The current stack frame when we started Interpret().
// This is being used by the ops to determine wheter
// to return from this function and thus terminate
// interpretation.
- const InterpFrame *StartFrame = S.Current;
assert(!S.Current->isRoot());
CodePtr PC = S.Current->getPC();
- // Empty program.
- if (!PC)
- return true;
+ return InterpNext(S, PC);
+}
- for (;;) {
- auto Op = PC.read<Opcode>();
- CodePtr OpPC = PC;
+#define GET_INTERPFNS_
+#include "Opcodes.inc"
+#undef GET_INTERPFNS_
- switch (Op) {
-#define GET_INTERP
+using InterpFn = __attribute__((preserve_none)) bool (*)(InterpState &,
+ CodePtr &PC);
+
+const InterpFn InterpFunctions[] = {
+#define GET_INTERPFNS
#include "Opcodes.inc"
-#undef GET_INTERP
- }
- }
+#undef GET_INTERPFNS
+};
+
+__attribute__((preserve_none)) static bool InterpNext(InterpState &S,
+ CodePtr &PC) {
+ auto Op = PC.read<Opcode>();
+ auto Fn = InterpFunctions[Op];
+ [[clang::musttail]] return Fn(S, PC);
}
-// https://github.com/llvm/llvm-project/issues/102513
-#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
-#pragma optimize("", on)
-#endif
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 9accbbc1605a9..c32ade5e125b0 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -221,7 +221,7 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
const Function *Func);
template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool Ret(InterpState &S, CodePtr &PC) {
+__attribute__((preserve_none)) bool Ret(InterpState &S, CodePtr &PC) {
const T &Ret = S.Stk.pop<T>();
assert(S.Current);
@@ -243,7 +243,8 @@ bool Ret(InterpState &S, CodePtr &PC) {
return true;
}
-inline bool RetVoid(InterpState &S, CodePtr &PC) {
+__attribute__((preserve_none)) inline bool RetVoid(InterpState &S,
+ CodePtr &PC) {
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
@@ -3040,7 +3041,7 @@ static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
// NoRet
//===----------------------------------------------------------------------===//
-inline bool NoRet(InterpState &S, CodePtr OpPC) {
+__attribute__((preserve_none)) inline bool NoRet(InterpState &S, CodePtr OpPC) {
SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
S.FFDiag(EndLoc, diag::note_constexpr_no_return);
return false;
diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp
index d26122aca46bd..84c4a673e133a 100644
--- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp
+++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp
@@ -36,6 +36,8 @@ class ClangOpcodesEmitter {
/// Emits the switch case and the invocation in the interpreter.
void EmitInterp(raw_ostream &OS, StringRef N, const Record *R);
+ void EmitInterpFns(raw_ostream &OS, StringRef N, const Record *R);
+ void EmitInterpFns_(raw_ostream &OS, StringRef N, const Record *R);
/// Emits the disassembler.
void EmitDisasm(raw_ostream &OS, StringRef N, const Record *R);
@@ -92,6 +94,8 @@ void ClangOpcodesEmitter::run(raw_ostream &OS) {
EmitEnum(OS, N, Opcode);
EmitInterp(OS, N, Opcode);
+ EmitInterpFns(OS, N, Opcode);
+ EmitInterpFns_(OS, N, Opcode);
EmitDisasm(OS, N, Opcode);
EmitProto(OS, N, Opcode);
EmitGroup(OS, N, Opcode);
@@ -109,6 +113,89 @@ void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N,
OS << "#endif\n";
}
+void ClangOpcodesEmitter::EmitInterpFns_(raw_ostream &OS, StringRef N,
+ const Record *R) {
+ OS << "#ifdef GET_INTERPFNS_\n";
+ Enumerate(R, N, [&](ArrayRef<const Record *> TS, const Twine &ID) {
+ OS << "__attribute__((preserve_none))\nstatic bool Interp_" << ID
+ << "(InterpState &S, CodePtr &PC) {\n";
+
+ bool CanReturn = R->getValueAsBit("CanReturn");
+ const auto &Args = R->getValueAsListOfDefs("Args");
+ bool ChangesPC = R->getValueAsBit("ChangesPC");
+
+ if (Args.empty()) {
+ if (CanReturn) {
+ OS << " [[clang::musttail]] return " << N;
+ PrintTypes(OS, TS);
+ OS << "(S, PC);\n";
+ OS << "}\n";
+ return;
+ }
+
+ // OS << "llvm::errs() << \"Calling \" << \"" << N << "\\n\";";//'\n';
+ OS << " if (!" << N;
+ PrintTypes(OS, TS);
+ OS << "(S, PC))\n";
+ OS << " return false;\n";
+ OS << "[[clang::musttail]] return InterpNext(S, PC);\n";
+ OS << "}\n";
+ return;
+ }
+
+ OS << "{\n";
+
+ if (!ChangesPC)
+ OS << " CodePtr OpPC = PC;\n";
+
+ // Emit calls to read arguments.
+ for (size_t I = 0, N = Args.size(); I < N; ++I) {
+ const auto *Arg = Args[I];
+ bool AsRef = Arg->getValueAsBit("AsRef");
+
+ if (AsRef)
+ OS << " const auto &V" << I;
+ else
+ OS << " const auto V" << I;
+ OS << " = ";
+ OS << "ReadArg<" << Arg->getValueAsString("Name") << ">(S, PC);\n";
+ }
+
+ OS << " if (!" << N;
+ PrintTypes(OS, TS);
+ OS << "(S";
+ // OS << ", OpPC";
+ if (ChangesPC)
+ OS << ", PC";
+ else
+ OS << ", OpPC";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << ", V" << I;
+ OS << "))\n";
+ OS << " return false;\n";
+
+ OS << "}\n";
+
+ if (!CanReturn)
+ OS << "[[clang::musttail]] return InterpNext(S, PC);\n";
+ else
+ OS << " return true;\n";
+ // OS << " return false;\n";
+
+ OS << "}\n";
+ });
+ OS << "#endif\n";
+}
+
+void ClangOpcodesEmitter::EmitInterpFns(raw_ostream &OS, StringRef N,
+ const Record *R) {
+ OS << "#ifdef GET_INTERPFNS\n";
+ Enumerate(R, N, [&OS](ArrayRef<const Record *>, const Twine &ID) {
+ OS << "&Interp_" << ID << ",\n";
+ });
+ OS << "#endif\n";
+}
+
void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N,
const Record *R) {
OS << "#ifdef GET_INTERP\n";
>From 63ca4e59c10b19eed4b5c2e173b33c4758d889b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sun, 28 Dec 2025 06:37:20 +0100
Subject: [PATCH 3/6] Revert "Test"
This reverts commit 699354a4146e2ebc7e7c7aa84d14c396a4300508.
---
clang/lib/AST/ExprConstant.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 72e9193d89f5d..8618979d1eba0 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -931,7 +931,7 @@ namespace {
: Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
CallStackDepth(0), NextCallIndex(1),
StepsLeft(C.getLangOpts().ConstexprStepLimit),
- EnableNewConstInterp(true),
+ EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
/*This=*/nullptr,
/*CallExpr=*/nullptr, CallRef()),
>From 721741435ec7f21caacd2e6f5e48f0ef5b2a92ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 2 Jan 2026 10:38:31 +0100
Subject: [PATCH 4/6] Use a macro for the preserve_none attribute
---
clang/lib/AST/ByteCode/Interp.cpp | 30 ++++++++++++--------
clang/utils/TableGen/ClangOpcodesEmitter.cpp | 22 +++++++-------
2 files changed, 29 insertions(+), 23 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index af1bf76db865d..dbd0cccd9ba75 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -28,8 +28,13 @@
using namespace clang;
using namespace clang::interp;
-__attribute__((preserve_none)) static bool RetValue(InterpState &S,
- CodePtr &Pt) {
+#ifdef __clang__
+#define PRESERVE_NONE [[clang::preserve_none]]
+#else
+#define PRESERVE_NONE
+#endif
+
+PRESERVE_NONE static bool RetValue(InterpState &S, CodePtr &Pt) {
llvm::report_fatal_error("Interpreter cannot return values");
}
@@ -2325,8 +2330,7 @@ bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {
return true;
}
-__attribute__((preserve_none)) static bool InterpNext(InterpState &S,
- CodePtr &PC);
+PRESERVE_NONE static bool InterpNext(InterpState &S, CodePtr &PC);
bool Interpret(InterpState &S) {
// The current stack frame when we started Interpret().
@@ -2339,21 +2343,23 @@ bool Interpret(InterpState &S) {
return InterpNext(S, PC);
}
-#define GET_INTERPFNS_
+// The dispatcher functions read the opcode arguments from the
+// bytecode and call the implementation function.
+#define GET_INTERPFN_DISPATCHERS
#include "Opcodes.inc"
-#undef GET_INTERPFNS_
+#undef GET_INTERPFN_DISPATCHERS
-using InterpFn = __attribute__((preserve_none)) bool (*)(InterpState &,
- CodePtr &PC);
+using InterpFn = bool (*)(InterpState &, CodePtr &PC) PRESERVE_NONE;
+// Array of the dispatcher functions defined above.
const InterpFn InterpFunctions[] = {
-#define GET_INTERPFNS
+#define GET_INTERPFN_LIST
#include "Opcodes.inc"
-#undef GET_INTERPFNS
+#undef GET_INTERPFN_LIST
};
-__attribute__((preserve_none)) static bool InterpNext(InterpState &S,
- CodePtr &PC) {
+// Read the next opcode and call the dispatcher function.
+PRESERVE_NONE static bool InterpNext(InterpState &S, CodePtr &PC) {
auto Op = PC.read<Opcode>();
auto Fn = InterpFunctions[Op];
[[clang::musttail]] return Fn(S, PC);
diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp
index 84c4a673e133a..ed6934509b4da 100644
--- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp
+++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp
@@ -36,8 +36,8 @@ class ClangOpcodesEmitter {
/// Emits the switch case and the invocation in the interpreter.
void EmitInterp(raw_ostream &OS, StringRef N, const Record *R);
- void EmitInterpFns(raw_ostream &OS, StringRef N, const Record *R);
- void EmitInterpFns_(raw_ostream &OS, StringRef N, const Record *R);
+ void EmitInterpFnList(raw_ostream &OS, StringRef N, const Record *R);
+ void EmitInterpFnDispatchers(raw_ostream &OS, StringRef N, const Record *R);
/// Emits the disassembler.
void EmitDisasm(raw_ostream &OS, StringRef N, const Record *R);
@@ -94,8 +94,8 @@ void ClangOpcodesEmitter::run(raw_ostream &OS) {
EmitEnum(OS, N, Opcode);
EmitInterp(OS, N, Opcode);
- EmitInterpFns(OS, N, Opcode);
- EmitInterpFns_(OS, N, Opcode);
+ EmitInterpFnList(OS, N, Opcode);
+ EmitInterpFnDispatchers(OS, N, Opcode);
EmitDisasm(OS, N, Opcode);
EmitProto(OS, N, Opcode);
EmitGroup(OS, N, Opcode);
@@ -113,11 +113,11 @@ void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N,
OS << "#endif\n";
}
-void ClangOpcodesEmitter::EmitInterpFns_(raw_ostream &OS, StringRef N,
- const Record *R) {
- OS << "#ifdef GET_INTERPFNS_\n";
+void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
+ const Record *R) {
+ OS << "#ifdef GET_INTERPFN_DISPATCHERS\n";
Enumerate(R, N, [&](ArrayRef<const Record *> TS, const Twine &ID) {
- OS << "__attribute__((preserve_none))\nstatic bool Interp_" << ID
+ OS << "PRESERVE_NONE\nstatic bool Interp_" << ID
<< "(InterpState &S, CodePtr &PC) {\n";
bool CanReturn = R->getValueAsBit("CanReturn");
@@ -187,9 +187,9 @@ void ClangOpcodesEmitter::EmitInterpFns_(raw_ostream &OS, StringRef N,
OS << "#endif\n";
}
-void ClangOpcodesEmitter::EmitInterpFns(raw_ostream &OS, StringRef N,
- const Record *R) {
- OS << "#ifdef GET_INTERPFNS\n";
+void ClangOpcodesEmitter::EmitInterpFnList(raw_ostream &OS, StringRef N,
+ const Record *R) {
+ OS << "#ifdef GET_INTERPFN_LIST\n";
Enumerate(R, N, [&OS](ArrayRef<const Record *>, const Twine &ID) {
OS << "&Interp_" << ID << ",\n";
});
>From 6b87a71d03cbe396f6f26044e444047641b7eee5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 2 Jan 2026 12:10:49 +0100
Subject: [PATCH 5/6] Use a macro for musttail attribute
---
clang/lib/AST/ByteCode/Interp.cpp | 10 ++++++++
clang/utils/TableGen/ClangOpcodesEmitter.cpp | 27 +++++++++-----------
2 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index dbd0cccd9ba75..b391171f86682 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -34,6 +34,16 @@ using namespace clang::interp;
#define PRESERVE_NONE
#endif
+#if defined(_MSC_VER) && !defined(__clang__)
+#ifdef NDEBUG
+#define MUSTTAIL [[msvc::musttail]]
+#else
+#define MUSTTAIL
+#endif
+#else
+#define MUSTTAIL [[clang::musttail]]
+#endif
+
PRESERVE_NONE static bool RetValue(InterpState &S, CodePtr &Pt) {
llvm::report_fatal_error("Interpreter cannot return values");
}
diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp
index ed6934509b4da..c89dc632d1137 100644
--- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp
+++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp
@@ -126,27 +126,26 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
if (Args.empty()) {
if (CanReturn) {
- OS << " [[clang::musttail]] return " << N;
+ OS << " MUSTTAIL return " << N;
PrintTypes(OS, TS);
OS << "(S, PC);\n";
OS << "}\n";
return;
}
- // OS << "llvm::errs() << \"Calling \" << \"" << N << "\\n\";";//'\n';
OS << " if (!" << N;
PrintTypes(OS, TS);
OS << "(S, PC))\n";
- OS << " return false;\n";
- OS << "[[clang::musttail]] return InterpNext(S, PC);\n";
+ OS << " return false;\n";
+ OS << " MUSTTAIL return InterpNext(S, PC);\n";
OS << "}\n";
return;
}
- OS << "{\n";
+ OS << " {\n";
if (!ChangesPC)
- OS << " CodePtr OpPC = PC;\n";
+ OS << " CodePtr OpPC = PC;\n";
// Emit calls to read arguments.
for (size_t I = 0, N = Args.size(); I < N; ++I) {
@@ -154,17 +153,16 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
bool AsRef = Arg->getValueAsBit("AsRef");
if (AsRef)
- OS << " const auto &V" << I;
+ OS << " const auto &V" << I;
else
- OS << " const auto V" << I;
+ OS << " const auto V" << I;
OS << " = ";
OS << "ReadArg<" << Arg->getValueAsString("Name") << ">(S, PC);\n";
}
- OS << " if (!" << N;
+ OS << " if (!" << N;
PrintTypes(OS, TS);
OS << "(S";
- // OS << ", OpPC";
if (ChangesPC)
OS << ", PC";
else
@@ -172,15 +170,14 @@ void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
for (size_t I = 0, N = Args.size(); I < N; ++I)
OS << ", V" << I;
OS << "))\n";
- OS << " return false;\n";
+ OS << " return false;\n";
- OS << "}\n";
+ OS << " }\n";
if (!CanReturn)
- OS << "[[clang::musttail]] return InterpNext(S, PC);\n";
+ OS << " MUSTTAIL return InterpNext(S, PC);\n";
else
- OS << " return true;\n";
- // OS << " return false;\n";
+ OS << " return true;\n";
OS << "}\n";
});
>From fc25a33c09dca74ab3869bfa0343ecc3caad23ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 2 Jan 2026 12:18:09 +0100
Subject: [PATCH 6/6] Move preserve_none macro to Interp.h
---
clang/lib/AST/ByteCode/Interp.cpp | 6 ------
clang/lib/AST/ByteCode/Interp.h | 14 +++++++++-----
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index b391171f86682..27d24f867bdb2 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -28,12 +28,6 @@
using namespace clang;
using namespace clang::interp;
-#ifdef __clang__
-#define PRESERVE_NONE [[clang::preserve_none]]
-#else
-#define PRESERVE_NONE
-#endif
-
#if defined(_MSC_VER) && !defined(__clang__)
#ifdef NDEBUG
#define MUSTTAIL [[msvc::musttail]]
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index c32ade5e125b0..e77b389e4fb12 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -35,6 +35,12 @@
#include "llvm/ADT/APSInt.h"
#include <type_traits>
+#ifdef __clang__
+#define PRESERVE_NONE [[clang::preserve_none]]
+#else
+#define PRESERVE_NONE
+#endif
+
namespace clang {
namespace interp {
@@ -221,7 +227,7 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
const Function *Func);
template <PrimType Name, class T = typename PrimConv<Name>::T>
-__attribute__((preserve_none)) bool Ret(InterpState &S, CodePtr &PC) {
+bool Ret(InterpState &S, CodePtr &PC) PRESERVE_NONE {
const T &Ret = S.Stk.pop<T>();
assert(S.Current);
@@ -243,8 +249,7 @@ __attribute__((preserve_none)) bool Ret(InterpState &S, CodePtr &PC) {
return true;
}
-__attribute__((preserve_none)) inline bool RetVoid(InterpState &S,
- CodePtr &PC) {
+inline bool RetVoid(InterpState &S, CodePtr &PC) PRESERVE_NONE {
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
@@ -3040,8 +3045,7 @@ static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
//===----------------------------------------------------------------------===//
// NoRet
//===----------------------------------------------------------------------===//
-
-__attribute__((preserve_none)) inline bool NoRet(InterpState &S, CodePtr OpPC) {
+inline bool NoRet(InterpState &S, CodePtr OpPC) PRESERVE_NONE {
SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
S.FFDiag(EndLoc, diag::note_constexpr_no_return);
return false;
More information about the cfe-commits
mailing list