19#include "llvm/ADT/ScopeExit.h"
20#include "llvm/Support/Casting.h"
21#include "llvm/Support/ConvertUTF.h"
22#include "llvm/Support/Errno.h"
37 return obj.takeError();
38 return obj.get().IsTrue();
44 return obj.takeError();
45 return obj->AsLongLong();
49Expected<unsigned long long>
52 return obj.takeError();
53 return obj->AsUnsignedLongLong();
59 return obj.takeError();
60 PyObject *str_obj = PyObject_Str(obj.get().get());
62 return llvm::make_error<PythonException>();
64 auto utf8 = str.AsUTF8();
66 return utf8.takeError();
67 return std::string(utf8.get());
71 if (
m_py_obj && Py_IsInitialized()) {
72 PyGILState_STATE state = PyGILState_Ensure();
74 PyGILState_Release(state);
82 assert(!PyErr_Occurred());
83 long long r = PyLong_AsLongLong(
m_py_obj);
92 assert(!PyErr_Occurred());
93 long long r = PyLong_AsUnsignedLongLong(
m_py_obj);
103 assert(!PyErr_Occurred());
104 unsigned long long r = PyLong_AsUnsignedLongLongMask(
m_py_obj);
106 if (PyErr_Occurred())
112 s.value(llvm::formatv(
"Python Obj: {0:X}",
GetValue()).str());
123 PyObject *py_str = PyObject_Repr(
m_py_obj);
127 llvm::scope_exit release_py_str([py_str] { Py_DECREF(py_str); });
129 PyObject *py_bytes = PyUnicode_AsEncodedString(py_str,
"utf-8",
"replace");
133 llvm::scope_exit release_py_bytes([py_bytes] { Py_DECREF(py_bytes); });
135 char *buffer =
nullptr;
136 Py_ssize_t length = 0;
137 if (PyBytes_AsStringAndSize(py_bytes, &buffer, &length) == -1)
140 strm << llvm::StringRef(buffer, length);
175 PyObject *repr = PyObject_Repr(
m_py_obj);
184 PyObject *str = PyObject_Str(
m_py_obj);
193 size_t dot_pos = name.find(
'.');
194 llvm::StringRef piece = name.substr(0, dot_pos);
196 if (dot_pos == llvm::StringRef::npos) {
203 return result.
ResolveName(name.substr(dot_pos + 1));
217 size_t dot_pos = name.find(
'.');
218 if (dot_pos == llvm::StringRef::npos) {
231 return parent.
ResolveName(name.substr(dot_pos + 1));
238 return !!PyObject_HasAttr(
m_py_obj, py_attr.
get());
264 if (std::holds_alternative<StructuredData::UnsignedIntegerSP>(int_sp))
265 return std::get<StructuredData::UnsignedIntegerSP>(int_sp);
266 if (std::holds_alternative<StructuredData::SignedIntegerSP>(int_sp))
267 return std::get<StructuredData::SignedIntegerSP>(int_sp);
292 SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
298 return PyBytes_Check(py_obj);
303 return llvm::ArrayRef<uint8_t>();
308 PyBytes_AsStringAndSize(
m_py_obj, &c, &size);
309 return llvm::ArrayRef<uint8_t>(
reinterpret_cast<uint8_t *
>(c), size);
319 const char *data =
reinterpret_cast<const char *
>(bytes.data());
327 PyBytes_AsStringAndSize(
m_py_obj, &c, &size);
328 result->SetValue(std::string(c, size));
336 const char *str =
reinterpret_cast<const char *
>(bytes);
343 return PyByteArray_Check(py_obj);
348 return llvm::ArrayRef<uint8_t>();
350 char *c = PyByteArray_AsString(
m_py_obj);
352 return llvm::ArrayRef<uint8_t>(
reinterpret_cast<uint8_t *
>(c), size);
364 llvm::ArrayRef<uint8_t> bytes =
GetBytes();
365 const char *str =
reinterpret_cast<const char *
>(bytes.data());
366 result->SetValue(std::string(str, bytes.size()));
373 PyObject *str = PyUnicode_FromStringAndSize(
string.data(),
string.size());
375 return llvm::make_error<PythonException>();
385 if (PyUnicode_Check(py_obj))
393 llvm::consumeError(s.takeError());
394 return llvm::StringRef(
"");
408#if defined(Py_LIMITED_API) && (Py_LIMITED_API < 0x030a0000)
409 PyObject *py_bytes = PyUnicode_AsUTF8String(
m_py_obj);
412 llvm::scope_exit release_py_str([py_bytes] { Py_DECREF(py_bytes); });
413 Py_ssize_t size = PyBytes_Size(py_bytes);
414 const char *str = PyBytes_AsString(py_bytes);
422 const char *str = PyUnicode_AsUTF8AndSize(
m_py_obj, &size);
427 return llvm::StringRef(str, size);
433 return PyUnicode_GetLength(
m_py_obj);
440 llvm::consumeError(s.takeError());
443 *
this = std::move(s.get());
463 return PyLong_Check(py_obj);
481 llvm::consumeError(value.takeError());
483 result = std::make_shared<StructuredData::UnsignedInteger>(value.get());
491 llvm::Expected<long long> value =
AsLongLong();
493 llvm::consumeError(value.takeError());
495 result = std::make_shared<StructuredData::SignedInteger>(value.get());
505 return py_obj ? PyBool_Check(py_obj) :
false;
536 return PyList_Check(py_obj);
555 Py_INCREF(
object.
get());
571 for (uint32_t i = 0; i < count; ++i) {
590 m_py_obj = PyTuple_New(objects.size());
593 for (
auto object : objects) {
601 m_py_obj = PyTuple_New(objects.size());
604 for (
auto py_object : objects) {
615 return PyTuple_Check(py_obj);
634 Py_INCREF(
object.
get());
642 for (uint32_t i = 0; i < count; ++i) {
660 return PyDict_Check(py_obj);
667 PythonString key_object(key.isSingleStringRef() ? key.getSingleStringRef()
670 if (
int res = PyDict_Contains(
m_py_obj, key_object.
get()) > 0)
692 llvm::consumeError(item.takeError());
695 return std::move(item.get());
698Expected<PythonObject>
702 PyObject *o = PyDict_GetItemWithError(
m_py_obj, key.
get());
703 if (PyErr_Occurred())
714 if (PyErr_Occurred())
728 return Error::success();
738 return Error::success();
745 llvm::consumeError(std::move(
error));
752 uint32_t num_keys = keys.
GetSize();
753 for (uint32_t i = 0; i < num_keys; ++i) {
757 result->AddItem(key.
Str().
GetString(), structured_value);
767 std::string str =
module.str();
781 PyObject *dict = PyModule_GetDict(
m_py_obj);
784 PyObject *item = PyDict_GetItemString(dict,
NullTerminated(name));
794 return PyModule_Check(py_obj);
815 return PyCallable_Check(function_obj.
release());
818 return PyCallable_Check(py_obj);
822from inspect import signature, Parameter, ismethod
823from collections import namedtuple
824ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs'])
828 for parameter in signature(f).parameters.values():
829 kind = parameter.kind
830 if kind in (Parameter.POSITIONAL_ONLY,
831 Parameter.POSITIONAL_OR_KEYWORD):
833 elif kind == Parameter.VAR_POSITIONAL:
835 elif kind in (Parameter.KEYWORD_ONLY,
836 Parameter.VAR_KEYWORD):
839 raise Exception(f'unknown parameter kind: {kind}')
840 return ArgInfo(count, varargs)
850 Expected<PythonObject> pyarginfo = get_arg_info(*
this);
852 return pyarginfo.takeError();
854 cantFail(
As<long long>(pyarginfo.get().GetAttribute(
"count")));
856 cantFail(
As<bool>(pyarginfo.get().GetAttribute(
"has_varargs")));
893 llvm::consumeError(io_module.takeError());
896 auto iobase = io_module.get().Get(
"IOBase");
898 llvm::consumeError(iobase.takeError());
901 int r = PyObject_IsInstance(py_obj, iobase.get().get());
911 return "unknown exception";
916 assert(PyErr_Occurred());
924 m_repr_bytes = PyUnicode_AsEncodedString(repr,
"utf-8",
nullptr);
943 PyErr_SetString(PyExc_Exception,
toCString());
958 return llvm::inconvertibleErrorCode();
967from traceback import print_exception
968if sys.version_info.major < 3:
969 from StringIO import StringIO
971 from io import StringIO
972def main(exc_type, exc_value, tb):
974 print_exception(exc_type, exc_value, tb, file=f)
990 std::string message =
992 "Traceback unavailable, an error occurred while reading it:\n";
993 return (message + llvm::toString(backtrace.takeError()));
996 return std::move(backtrace.get());
1001llvm::Expected<File::OpenOptions>
1006 return readable.takeError();
1009 return writable.takeError();
1010 if (readable.get() && writable.get())
1012 else if (writable.get())
1014 else if (readable.get())
1023template <
typename Base>
class OwnedPythonFile :
public Base {
1025 template <
typename... Args>
1026 OwnedPythonFile(
const PythonFile &file,
bool borrowed, Args... args)
1027 : Base(args...), m_py_obj(file), m_borrowed(borrowed) {
1031 ~OwnedPythonFile()
override {
1040 bool IsPythonSideValid()
const {
1042 auto closed =
As<bool>(m_py_obj.GetAttribute(
"closed"));
1044 llvm::consumeError(closed.takeError());
1047 return !closed.get();
1050 bool IsValid()
const override {
1051 return IsPythonSideValid() && Base::IsValid();
1054 Status Close()
override {
1056 Status py_error, base_error;
1059 auto r = m_py_obj.CallMethod(
"close");
1061 py_error = Status::FromError(r.takeError());
1063 base_error = Base::Close();
1065 if (py_error.
Fail())
1066 return py_error.
Clone();
1067 return base_error.
Clone();
1070 PyObject *GetPythonObject()
const {
1071 assert(m_py_obj.IsValid());
1072 return m_py_obj.get();
1075 static bool classof(
const File *file) =
delete;
1078 PythonFile m_py_obj;
1086class SimplePythonFile :
public OwnedPythonFile<NativeFile> {
1088 SimplePythonFile(
const PythonFile &file,
bool borrowed,
int fd,
1090 : OwnedPythonFile(file, borrowed, fd, options, false) {}
1093 bool isA(
const void *classID)
const override {
1096 static bool classof(
const File *file) {
return file->
isA(&
ID); }
1098char SimplePythonFile::ID = 0;
1103class PythonIOFile :
public OwnedPythonFile<File> {
1105 PythonIOFile(
const PythonFile &file,
bool borrowed)
1106 : OwnedPythonFile(file, borrowed) {}
1108 ~PythonIOFile()
override { Close(); }
1110 bool IsValid()
const override {
return IsPythonSideValid(); }
1112 Status Close()
override {
1117 auto r = m_py_obj.CallMethod(
"close");
1120 return Status::FromError(r.takeError()).Clone();
1124 Status Flush()
override {
1126 auto r = m_py_obj.CallMethod(
"flush");
1129 return Status::FromError(r.takeError()).Clone();
1133 Expected<File::OpenOptions> GetOptions()
const override {
1139 bool isA(
const void *classID)
const override {
1142 static bool classof(
const File *file) {
return file->
isA(&
ID); }
1144char PythonIOFile::ID = 0;
1148class BinaryPythonFile :
public PythonIOFile {
1153 BinaryPythonFile(
int fd,
const PythonFile &file,
bool borrowed)
1154 : PythonIOFile(file, borrowed),
1155 m_descriptor(
File::DescriptorIsValid(fd) ? fd
1156 :
File::kInvalidDescriptor) {}
1158 int GetDescriptor()
const override {
return m_descriptor; }
1160 Status Write(
const void *buf,
size_t &num_bytes)
override {
1162 PyObject *pybuffer_p = PyMemoryView_FromMemory(
1163 const_cast<char *
>((
const char *)buf), num_bytes,
PyBUF_READ);
1166 return Status::FromError(llvm::make_error<PythonException>()).Clone();
1169 auto bytes_written =
As<long long>(m_py_obj.CallMethod(
"write", pybuffer));
1171 return Status::FromError(bytes_written.takeError());
1172 if (bytes_written.get() < 0)
1173 return Status::FromErrorString(
1174 ".write() method returned a negative number!");
1175 static_assert(
sizeof(
long long) >=
sizeof(size_t),
"overflow");
1176 num_bytes = bytes_written.get();
1180 Status Read(
void *buf,
size_t &num_bytes)
override {
1182 static_assert(
sizeof(
long long) >=
sizeof(size_t),
"overflow");
1184 m_py_obj.CallMethod(
"read", (
unsigned long long)num_bytes);
1187 return Status::FromError(pybuffer_obj.takeError()).Clone();
1189 if (pybuffer_obj.get().IsNone()) {
1194 PythonBytes pybytes(PyRefType::Borrowed, pybuffer_obj->get());
1196 return Status::FromError(llvm::make_error<PythonException>());
1197 llvm::ArrayRef<uint8_t> bytes = pybytes.GetBytes();
1198 memcpy(buf, bytes.begin(), bytes.size());
1199 num_bytes = bytes.size();
1206class TextPythonFile :
public PythonIOFile {
1211 TextPythonFile(
int fd,
const PythonFile &file,
bool borrowed)
1212 : PythonIOFile(file, borrowed),
1213 m_descriptor(
File::DescriptorIsValid(fd) ? fd
1214 :
File::kInvalidDescriptor) {}
1216 int GetDescriptor()
const override {
return m_descriptor; }
1218 Status Write(
const void *buf,
size_t &num_bytes)
override {
1223 return Status::FromError(pystring.takeError());
1225 auto bytes_written =
1226 As<long long>(m_py_obj.CallMethod(
"write", pystring.get()));
1229 return Status::FromError(bytes_written.takeError()).Clone();
1230 if (bytes_written.get() < 0)
1231 return Status::FromErrorString(
1232 ".write() method returned a negative number!");
1233 static_assert(
sizeof(
long long) >=
sizeof(size_t),
"overflow");
1234 num_bytes = bytes_written.get();
1238 Status Read(
void *buf,
size_t &num_bytes)
override {
1240 size_t num_chars = num_bytes / 6;
1241 size_t orig_num_bytes = num_bytes;
1243 if (orig_num_bytes < 6) {
1244 return Status::FromErrorString(
1245 "can't read less than 6 bytes from a utf8 text stream");
1248 m_py_obj.CallMethod(
"read", (
unsigned long long)num_chars));
1251 return Status::FromError(pystring.takeError()).Clone();
1252 if (pystring.get().IsNone()) {
1256 auto stringref = pystring.get().AsUTF8();
1259 return Status::FromError(stringref.takeError()).Clone();
1260 num_bytes = stringref.get().size();
1261 memcpy(buf, stringref.get().begin(), num_bytes);
1269 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1270 "invalid PythonFile");
1272 int fd = PyObject_AsFileDescriptor(
m_py_obj);
1279 return options.takeError();
1289 return r.takeError();
1296 file_sp = std::make_shared<NativeFile>(fd, options.get(),
false);
1298 file_sp = std::static_pointer_cast<File>(
1299 std::make_shared<SimplePythonFile>(*
this, borrowed, fd, options.get()));
1301 if (!file_sp->IsValid())
1302 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1308llvm::Expected<FileSP>
1311 assert(!PyErr_Occurred());
1314 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1315 "invalid PythonFile");
1317 int fd = PyObject_AsFileDescriptor(
m_py_obj);
1325 return io_module.takeError();
1326 auto textIOBase = io_module.get().Get(
"TextIOBase");
1328 return textIOBase.takeError();
1329 auto rawIOBase = io_module.get().Get(
"RawIOBase");
1331 return rawIOBase.takeError();
1332 auto bufferedIOBase = io_module.get().Get(
"BufferedIOBase");
1333 if (!bufferedIOBase)
1334 return bufferedIOBase.takeError();
1338 auto isTextIO =
IsInstance(textIOBase.get());
1340 return isTextIO.takeError();
1342 file_sp = std::static_pointer_cast<File>(
1343 std::make_shared<TextPythonFile>(fd, *
this, borrowed));
1347 return isRawIO.takeError();
1348 auto isBufferedIO =
IsInstance(bufferedIOBase.get());
1350 return isBufferedIO.takeError();
1352 if (isRawIO.get() || isBufferedIO.get()) {
1353 file_sp = std::static_pointer_cast<File>(
1354 std::make_shared<BinaryPythonFile>(fd, *
this, borrowed));
1358 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1359 "python file is neither text nor binary");
1361 if (!file_sp->IsValid())
1362 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1370 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1373 if (
auto *simple = llvm::dyn_cast<SimplePythonFile>(&file))
1375 if (
auto *pythonio = llvm::dyn_cast<PythonIOFile>(&file))
1381 return m.takeError();
1386 file_obj = PyFile_FromFd(file.
GetDescriptor(),
nullptr, mode, -1,
nullptr,
1387 "ignore",
nullptr, 0);
1397 return Error::success();
1401 if (Error
error = globals.
SetItem(
"__builtins__", builtins))
1409 return f.takeError();
1412 return Error::success();
1415llvm::Expected<PythonObject>
1423 Py_CompileString(
NullTerminated(
string),
"<string>", Py_eval_input);
1427 Py_CompileString(
NullTerminated(
string),
"<string>", Py_single_input);
1433 PyObject *result = PyEval_EvalCode(code, globals.
get(), locals.
get());
1441llvm::Expected<PythonObject>
1448 globals.
get(), locals.
get());
1455 PyObject *globals, PyObject *locals) {
1456 const char *filename =
"<string>";
1459 PyObject *code = Py_CompileString(str, filename, start);
1464 PyObject *result = PyEval_EvalCode(code, globals, locals);
1473 PyObject *main_module = PyImport_AddModule(
"__main__");
1477 PyObject *globals = PyModule_GetDict(main_module);
1481 PyObject *result =
RunString(str, Py_file_input, globals, globals);
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
static const char get_arg_info_script[]
llvm::Expected< File::OpenOptions > GetOptionsForPyObject(const PythonObject &obj)
const char read_exception_script[]
A uniqued constant string class.
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
virtual bool isA(const void *classID) const
static int kInvalidDescriptor
virtual int GetDescriptor() const
Get underlying OS file descriptor for this file, or kInvalidDescriptor.
llvm::Expected< const char * > GetOpenMode() const
bool IsValid() const override
IsValid.
bool isA(const void *classID) const override
Status Clone() const
Don't call this function in new code.
bool Fail() const
Test for error condition.
A stream class that can stream formatted output to a file.
std::shared_ptr< UnsignedInteger > UnsignedIntegerSP
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Object > ObjectSP
std::shared_ptr< String > StringSP
std::shared_ptr< Array > ArraySP
std::shared_ptr< Boolean > BooleanSP
std::shared_ptr< SignedInteger > SignedIntegerSP
std::variant< UnsignedIntegerSP, SignedIntegerSP > IntegerSP
StructuredData::BooleanSP CreateStructuredBoolean() const
static bool Check(PyObject *py_obj)
PythonBoolean(bool value)
void SetValue(bool value)
StructuredData::StringSP CreateStructuredString() const
llvm::ArrayRef< uint8_t > GetBytes() const
static bool Check(PyObject *py_obj)
PythonByteArray(llvm::ArrayRef< uint8_t > bytes)
static bool Check(PyObject *py_obj)
StructuredData::StringSP CreateStructuredString() const
void SetBytes(llvm::ArrayRef< uint8_t > stringbytes)
PythonBytes(llvm::ArrayRef< uint8_t > bytes)
llvm::ArrayRef< uint8_t > GetBytes() const
llvm::Expected< ArgInfo > GetArgInfo() const
PythonObject operator()()
static bool Check(PyObject *py_obj)
StructuredData::DictionarySP CreateStructuredDictionary() const
llvm::Expected< PythonObject > GetItem(const PythonObject &key) const
bool HasKey(const llvm::Twine &key) const
static bool Check(PyObject *py_obj)
PythonObject GetItemForKey(const PythonObject &key) const
llvm::Error SetItem(const PythonObject &key, const PythonObject &value) const
PythonList GetKeys() const
void SetItemForKey(const PythonObject &key, const PythonObject &value)
const char * toCString() const
PyObject * m_exception_type
bool Matches(PyObject *exc) const
std::string ReadBacktrace() const
std::error_code convertToErrorCode() const override
void log(llvm::raw_ostream &OS) const override
~PythonException() override
PythonException(const char *caller=nullptr)
llvm::Expected< lldb::FileSP > ConvertToFileForcingUseOfScriptingIOMethods(bool borrowed=false)
llvm::Expected< lldb::FileSP > ConvertToFile(bool borrowed=false)
static bool Check(PyObject *py_obj)
static llvm::Expected< PythonFile > FromFile(File &file, const char *mode=nullptr)
StructuredData::SignedIntegerSP CreateStructuredSignedInteger() const
static bool Check(PyObject *py_obj)
StructuredData::UnsignedIntegerSP CreateStructuredUnsignedInteger() const
StructuredData::IntegerSP CreateStructuredInteger() const
void SetInteger(int64_t value)
PythonObject GetItemAtIndex(uint32_t index) const
void AppendItem(const PythonObject &object)
static bool Check(PyObject *py_obj)
void SetItemAtIndex(uint32_t index, const PythonObject &object)
StructuredData::ArraySP CreateStructuredArray() const
static PythonModule BuiltinsModule()
static PythonModule AddModule(llvm::StringRef module)
static PythonModule MainModule()
llvm::Expected< PythonObject > Get(const llvm::Twine &name)
PythonDictionary GetDictionary() const
static bool Check(PyObject *py_obj)
static llvm::Expected< PythonModule > Import(const llvm::Twine &name)
PythonObject ResolveName(llvm::StringRef name) const
PythonString Repr() const
llvm::Expected< long long > AsLongLong() const
StructuredData::ObjectSP CreateStructuredObject() const
llvm::Expected< unsigned long long > AsModuloUnsignedLongLong() const
PythonObject GetAttributeValue(llvm::StringRef attribute) const
static PythonObject ResolveNameWithDictionary(llvm::StringRef name, const PythonDictionary &dict)
llvm::Expected< unsigned long long > AsUnsignedLongLong() const
llvm::Expected< bool > IsInstance(const PythonObject &cls)
PyObjectType GetObjectType() const
void Dump(Stream &strm) const
bool HasAttribute(llvm::StringRef attribute) const
llvm::Expected< PythonObject > CallMethod(const char *name, const T &... t) const
llvm::Expected< llvm::StringRef > AsUTF8() const
llvm::StringRef GetString() const
void SetString(llvm::StringRef string)
StructuredData::StringSP CreateStructuredString() const
static bool Check(PyObject *py_obj)
static llvm::Expected< PythonString > FromUTF8(llvm::StringRef string)
PythonTuple(PyInitialValue value)
StructuredData::ArraySP CreateStructuredArray() const
void SetItemAtIndex(uint32_t index, const PythonObject &object)
PythonObject GetItemAtIndex(uint32_t index) const
static bool Check(PyObject *py_obj)
void Serialize(llvm::json::OStream &s) const override
llvm::Expected< unsigned long long > As< unsigned long long >(llvm::Expected< PythonObject > &&obj)
llvm::Error exception(const char *s=nullptr)
llvm::Expected< std::string > As< std::string >(llvm::Expected< PythonObject > &&obj)
PyObject * RunString(const char *str, int start, PyObject *globals, PyObject *locals)
llvm::Expected< T > As(llvm::Expected< PythonObject > &&obj)
llvm::Expected< PythonObject > runStringMultiLine(const llvm::Twine &string, const PythonDictionary &globals, const PythonDictionary &locals)
int RunSimpleString(const char *str)
llvm::Expected< long long > As< long long >(llvm::Expected< PythonObject > &&obj)
llvm::Expected< bool > As< bool >(llvm::Expected< PythonObject > &&obj)
llvm::Expected< PythonObject > runStringOneLine(const llvm::Twine &string, const PythonDictionary &globals, const PythonDictionary &locals)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::File > FileSP
unsigned max_positional_args
static constexpr unsigned UNBOUNDED