Commit e039ff0f authored by Marius Wachtler's avatar Marius Wachtler

Merge pull request #925 from undingen/lxml3

Misc small fixes for lxml
parents 4cc0a340 f90202c8
......@@ -418,9 +418,13 @@ private:
}
void* visit_name(AST_Name* node) override {
auto name_scope = scope_info->getScopeTypeOfName(node->id);
if (node->lookup_type == ScopeInfo::VarScopeType::UNKNOWN)
node->lookup_type = scope_info->getScopeTypeOfName(node->id);
auto name_scope = node->lookup_type;
if (name_scope == ScopeInfo::VarScopeType::GLOBAL) {
if (node->id.s() == "None")
return NONE;
return UNKNOWN;
}
......
......@@ -1693,7 +1693,7 @@ assembler::Register Rewriter::allocReg(Location dest, Location otherThan) {
// Spill the register whose next use is farthest in the future
assert(found);
spillRegister(best_reg, /* preserve */ otherThan);
assert(vars_by_location.count(best_reg) == 0);
assert(failed || vars_by_location.count(best_reg) == 0);
return best_reg;
} else if (dest.type == Location::Register) {
assembler::Register reg(dest.regnum);
......@@ -1736,6 +1736,8 @@ assembler::XMMRegister Rewriter::allocXMMReg(Location dest, Location otherThan)
}
void Rewriter::addLocationToVar(RewriterVar* var, Location l) {
if (failed)
return;
assert(!var->isInLocation(l));
assert(vars_by_location.count(l) == 0);
......
......@@ -1316,7 +1316,7 @@ static int method_is_overloaded(PyObject* left, PyObject* right, const char* nam
SLOT1(slot_mp_subscript, "__getitem__", PyObject*, "O")
static int slot_mp_ass_subscript(PyObject* self, PyObject* key, PyObject* value) noexcept {
int slot_mp_ass_subscript(PyObject* self, PyObject* key, PyObject* value) noexcept {
STAT_TIMER(t0, "us_timer_slot_mpasssubscript", SLOT_AVOIDABILITY(self));
PyObject* res;
......
......@@ -47,6 +47,7 @@ PyObject* slot_tp_iter(PyObject* self) noexcept;
PyObject* slot_tp_iternext(PyObject* self) noexcept;
PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept;
PyObject* slot_mp_subscript(PyObject* self, PyObject* arg1) noexcept;
int slot_mp_ass_subscript(PyObject* self, PyObject* key, PyObject* value) noexcept;
int slot_sq_contains(PyObject* self, PyObject* value) noexcept;
Py_ssize_t slot_sq_length(PyObject* self) noexcept;
PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept;
......
......@@ -482,7 +482,7 @@ inline BoxedString* internStringMortal(llvm::StringRef s) {
}
// TODO this is an immortal intern for now
inline void internStringMortalInplace(BoxedString*& s) {
inline void internStringMortalInplace(BoxedString*& s) noexcept {
PyString_InternInPlace((PyObject**)&s);
}
......
......@@ -464,7 +464,7 @@ Box* bltinImport(Box* name, Box* globals, Box* locals, Box** args) {
// Well, it gets passed to PyImport_ImportModuleLevel() and then import_module_level(),
// which ignores it. So we don't even pass it through.
name = coerceUnicodeToStr(name);
name = coerceUnicodeToStr<CXX>(name);
if (name->cls != str_cls) {
raiseExcHelper(TypeError, "__import__() argument 1 must be string, not %s", getTypeName(name));
......@@ -479,7 +479,7 @@ Box* bltinImport(Box* name, Box* globals, Box* locals, Box** args) {
}
Box* delattrFunc(Box* obj, Box* _str) {
_str = coerceUnicodeToStr(_str);
_str = coerceUnicodeToStr<CXX>(_str);
if (_str->cls != str_cls)
raiseExcHelper(TypeError, "attribute name must be string, not '%s'", getTypeName(_str));
......@@ -543,15 +543,9 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
}
}
try {
_str = coerceUnicodeToStr(_str);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
_str = coerceUnicodeToStr<S>(_str);
if (S == CAPI && !_str)
return NULL;
if (!PyString_Check(_str)) {
if (S == CAPI) {
......@@ -601,7 +595,7 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
}
Box* setattrFunc(Box* obj, Box* _str, Box* value) {
_str = coerceUnicodeToStr(_str);
_str = coerceUnicodeToStr<CXX>(_str);
if (_str->cls != str_cls) {
raiseExcHelper(TypeError, "setattr(): attribute name must be string");
......@@ -647,19 +641,20 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
// value is fixed.
if (!PyString_CheckExact(_str) && !PyUnicode_CheckExact(_str))
rewrite_args = NULL;
else
else {
if (PyString_CheckExact(_str) && PyString_CHECK_INTERNED(_str) == SSTATE_INTERNED_IMMORTAL) {
// can avoid keeping the extra gc reference
} else {
rewrite_args->rewriter->addGCReference(_str);
}
rewrite_args->arg2->addGuard((intptr_t)arg2);
}
}
try {
_str = coerceUnicodeToStr(_str);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
_str = coerceUnicodeToStr<S>(_str);
if (S == CAPI && !_str)
return NULL;
if (!PyString_Check(_str)) {
if (S == CAPI) {
......
......@@ -56,7 +56,7 @@ BoxedClass* capifunc_cls;
}
extern "C" void _PyErr_BadInternalCall(const char* filename, int lineno) noexcept {
Py_FatalError("unimplemented");
PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", filename, lineno);
}
extern "C" PyObject* PyObject_Format(PyObject* obj, PyObject* format_spec) noexcept {
......@@ -1033,20 +1033,6 @@ extern "C" int PyErr_WarnEx(PyObject* category, const char* text, Py_ssize_t sta
return -1;
}
extern "C" PyObject* PyImport_Import(PyObject* module_name) noexcept {
RELEASE_ASSERT(module_name, "");
RELEASE_ASSERT(module_name->cls == str_cls, "");
try {
std::string _module_name = static_cast<BoxedString*>(module_name)->s();
return importModuleLevel(_module_name, None, None, -1);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
}
}
extern "C" void* PyObject_Malloc(size_t sz) noexcept {
return gc_compat_malloc(sz);
}
......@@ -1388,6 +1374,14 @@ extern "C" PyObject* PyCFunction_GetSelf(PyObject* op) noexcept {
return static_cast<BoxedCApiFunction*>(op)->passthrough;
}
extern "C" int PyCFunction_GetFlags(PyObject* op) noexcept {
if (!PyCFunction_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
return static_cast<BoxedCApiFunction*>(op)->method_def->ml_flags;
}
extern "C" int _PyEval_SliceIndex(PyObject* v, Py_ssize_t* pi) noexcept {
if (v != NULL) {
Py_ssize_t x;
......
......@@ -267,6 +267,27 @@ Box* classobjStr(Box* _obj) {
return boxStringTwine(llvm::Twine(static_cast<BoxedString*>(_mod)->s()) + "." + cls->name->s());
}
Box* classobjRepr(Box* _obj) {
if (!isSubclass(_obj->cls, classobj_cls)) {
raiseExcHelper(TypeError, "descriptor '__repr__' requires a 'classobj' object but received an '%s'",
getTypeName(_obj));
}
BoxedClassobj* cls = static_cast<BoxedClassobj*>(_obj);
static BoxedString* module_str = internStringImmortal("__module__");
Box* mod = cls->getattr(module_str);
const char* name;
if (cls->name == NULL || !PyString_Check(cls->name))
name = "?";
else
name = PyString_AsString(cls->name);
if (mod == NULL || !PyString_Check(mod))
return PyString_FromFormat("<class ?.%s at %p>", name, cls);
else
return PyString_FromFormat("<class %s.%s at %p>", PyString_AsString(mod), name, cls);
}
// Analogous to CPython's instance_getattr2
static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_str,
......@@ -1512,6 +1533,7 @@ void setupClassobj() {
new BoxedFunction(boxRTFunction((void*)classobjGetattribute, UNKNOWN, 2)));
classobj_cls->giveAttr("__setattr__", new BoxedFunction(boxRTFunction((void*)classobjSetattr, UNKNOWN, 3)));
classobj_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)classobjStr, STR, 1)));
classobj_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)classobjRepr, STR, 1)));
classobj_cls->giveAttr("__dict__", dict_descr);
classobj_cls->freeze();
......
......@@ -322,18 +322,20 @@ extern "C" PyObject* PyDict_GetItem(PyObject* dict, PyObject* key) noexcept {
return d->getOrNull(key);
}
// XXX this would be easy to make much faster.
// This path doesn't exist in CPython; we have it to support extension modules that do
// something along the lines of PyDict_GetItem(PyModule_GetDict()):
try {
return getitem(dict, key);
} catch (ExcInfo e) {
// PyDict_GetItem has special error behavior in CPython for backwards-compatibility reasons,
// and apparently it's important enough that we have to follow that.
// The behavior is that all errors get suppressed, and in fact I think it's supposed to
// restore the previous exception afterwards (we don't do that yet).
return NULL;
auto&& tstate = _PyThreadState_Current;
if (tstate != NULL && tstate->curexc_type != NULL) {
/* preserve the existing exception */
PyObject* err_type, *err_value, *err_tb;
PyErr_Fetch(&err_type, &err_value, &err_tb);
Box* b = getitemInternal<CAPI>(dict, key, NULL);
/* ignore errors */
PyErr_Restore(err_type, err_value, err_tb);
return b;
} else {
Box* b = getitemInternal<CAPI>(dict, key, NULL);
if (b == NULL)
PyErr_Clear();
return b;
}
}
......@@ -430,6 +432,7 @@ static int dict_ass_sub(PyDictObject* mp, PyObject* v, PyObject* w) noexcept {
assert(res == None);
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
}
return 0;
}
......
......@@ -594,22 +594,25 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
}
}
extern "C" PyObject* PyImport_ImportModule(const char* name) noexcept {
if (strcmp("__builtin__", name) == 0)
return builtins_module;
extern "C" PyObject* PyImport_Import(PyObject* module_name) noexcept {
RELEASE_ASSERT(module_name, "");
RELEASE_ASSERT(module_name->cls == str_cls, "");
try {
// TODO: check if this has the same behaviour as the cpython implementation
std::string str = name;
BoxedList* silly_list = new BoxedList();
listAppendInternal(silly_list, boxString("__doc__"));
return import(0, silly_list, str);
return import(0, silly_list, ((BoxedString*)module_name)->s());
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
extern "C" PyObject* PyImport_ImportModule(const char* name) noexcept {
return PyImport_Import(boxString(name));
}
/* Get the module object corresponding to a module name.
First check the modules dictionary if there's one there,
if not, create a new one and insert it in the modules dictionary.
......@@ -683,7 +686,7 @@ extern "C" Box* import(int level, Box* from_imports, llvm::StringRef module_name
}
Box* impFindModule(Box* _name, BoxedList* path) {
_name = coerceUnicodeToStr(_name);
_name = coerceUnicodeToStr<CXX>(_name);
RELEASE_ASSERT(_name->cls == str_cls, "");
BoxedString* name = static_cast<BoxedString*>(_name);
......
......@@ -3488,7 +3488,7 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
}
for (const auto& p : *d_kwargs) {
auto k = coerceUnicodeToStr(p.first);
auto k = coerceUnicodeToStr<CXX>(p.first);
if (k->cls != str_cls)
raiseExcHelper(TypeError, "%s() keywords must be strings", func_name);
......@@ -4720,7 +4720,6 @@ static Box* callItemAttr(Box* target, BoxedString* item_str, Box* item, Box* val
template <ExceptionStyle S>
static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* slice_str, Box* slice, Box* value,
CallRewriteArgs* rewrite_args) noexcept(S == CAPI) {
// This function contains a lot of logic for deciding between whether to call
// the slice operator or the item operator, so we can match CPython's behavior
// on custom classes that define those operators. However, for builtin types,
......@@ -4979,6 +4978,12 @@ extern "C" Box* getitem_capi(Box* target, Box* slice) noexcept {
return rtn;
}
static void setitemHelper(Box* target, Box* slice, Box* value) {
int ret = target->cls->tp_as_mapping->mp_ass_subscript(target, slice, value);
if (ret == -1)
throwCAPIException();
}
// target[slice] = value
extern "C" void setitem(Box* target, Box* slice, Box* value) {
STAT_TIMER(t0, "us_timer_slowpath_setitem", 10);
......@@ -4992,6 +4997,23 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
static BoxedString* setitem_str = internStringImmortal("__setitem__");
static BoxedString* setslice_str = internStringImmortal("__setslice__");
auto&& m = target->cls->tp_as_mapping;
if (m && m->mp_ass_subscript && m->mp_ass_subscript != slot_mp_ass_subscript) {
if (rewriter.get()) {
RewriterVar* r_obj = rewriter->getArg(0);
RewriterVar* r_slice = rewriter->getArg(1);
RewriterVar* r_value = rewriter->getArg(2);
RewriterVar* r_cls = r_obj->getAttr(offsetof(Box, cls));
RewriterVar* r_m = r_cls->getAttr(offsetof(BoxedClass, tp_as_mapping));
r_m->addGuardNotEq(0);
rewriter->call(true, (void*)setitemHelper, r_obj, r_slice, r_value);
rewriter->commit();
}
setitemHelper(target, slice, value);
return;
}
Box* rtn;
if (rewriter.get()) {
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
......@@ -5502,7 +5524,7 @@ Box* _typeNew(BoxedClass* metatype, BoxedString* name, BoxedTuple* bases, BoxedD
}
for (const auto& p : *attr_dict) {
auto k = coerceUnicodeToStr(p.first);
auto k = coerceUnicodeToStr<CXX>(p.first);
RELEASE_ASSERT(k->cls == str_cls, "");
BoxedString* s = static_cast<BoxedString*>(k);
......@@ -5831,7 +5853,7 @@ extern "C" Box* importStar(Box* _from_module, Box* to_globals) {
}
idx++;
attr_name = coerceUnicodeToStr(attr_name);
attr_name = coerceUnicodeToStr<CXX>(attr_name);
if (attr_name->cls != str_cls)
raiseExcHelper(TypeError, "attribute name must be string, not '%s'", getTypeName(attr_name));
......
......@@ -813,7 +813,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
ParamReceiveSpec paramspec(4, 3, false, false);
bool rewrite_success = false;
static ParamNames param_names({ "string", "encoding", "errors" }, "", "");
static ParamNames param_names({ "", "string", "encoding", "errors" }, "", "");
static Box* defaults[3] = { NULL, NULL, NULL };
Box* oargs[1];
......@@ -2246,7 +2246,7 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr(_key);
_key = coerceUnicodeToStr<CXX>(_key);
RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key);
......@@ -2256,11 +2256,27 @@ public:
return None;
}
static int ass_sub(PyDictObject* mp, PyObject* v, PyObject* w) noexcept {
try {
Box* res;
if (w == NULL) {
res = AttrWrapper::delitem((Box*)mp, v);
} else {
res = AttrWrapper::setitem((Box*)mp, v, w);
}
assert(res == None);
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
}
return 0;
}
static Box* setdefault(Box* _self, Box* _key, Box* value) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr(_key);
_key = coerceUnicodeToStr<CXX>(_key);
RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key);
......@@ -2277,7 +2293,7 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr(_key);
_key = coerceUnicodeToStr<CXX>(_key);
RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key);
......@@ -2289,19 +2305,25 @@ public:
return r;
}
static Box* getitem(Box* _self, Box* _key) {
template <ExceptionStyle S> static Box* getitem(Box* _self, Box* _key) noexcept(S == CAPI) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr(_key);
_key = coerceUnicodeToStr<S>(_key);
if (S == CAPI && !_key)
return NULL;
RELEASE_ASSERT(_key->cls == str_cls, "%s", _key->cls->tp_name);
BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key);
Box* r = self->b->getattr(key);
if (!r)
raiseExcHelper(KeyError, "'%s'", key->data());
if (!r) {
if (S == CXX)
raiseExcHelper(KeyError, "'%s'", key->data());
else
PyErr_Format(KeyError, "'%s'", key->data());
}
return r;
}
......@@ -2309,7 +2331,7 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr(_key);
_key = coerceUnicodeToStr<CXX>(_key);
RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key);
......@@ -2330,7 +2352,7 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr(_key);
_key = coerceUnicodeToStr<CXX>(_key);
RELEASE_ASSERT(_key->cls == str_cls, "%s", _key->cls->tp_name);
BoxedString* key = static_cast<BoxedString*>(_key);
......@@ -2367,11 +2389,13 @@ public:
return boxString(os.str());
}
static Box* contains(Box* _self, Box* _key) {
template <ExceptionStyle S> static Box* contains(Box* _self, Box* _key) noexcept(S == CAPI) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr(_key);
_key = coerceUnicodeToStr<S>(_key);
if (S == CAPI && !_key)
return NULL;
RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key);
......@@ -2381,6 +2405,13 @@ public:
return r ? True : False;
}
static int sq_contains(Box* _self, Box* _key) noexcept {
Box* rtn = contains<CAPI>(_self, _key);
if (!rtn)
return -1;
return rtn == True;
}
static Box* keys(Box* _self) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
......@@ -2702,7 +2733,7 @@ Box* objectHash(Box* obj) {
}
Box* objectSetattr(Box* obj, Box* attr, Box* value) {
attr = coerceUnicodeToStr(attr);
attr = coerceUnicodeToStr<CXX>(attr);
if (attr->cls != str_cls) {
raiseExcHelper(TypeError, "attribute name must be string, not '%s'", attr->cls->tp_name);
}
......@@ -3839,10 +3870,13 @@ void setupRuntime() {
static PyMappingMethods attrwrapper_as_mapping;
attrwrapper_cls->tp_as_mapping = &attrwrapper_as_mapping;
static PySequenceMethods attrwrapper_as_sequence;
attrwrapper_cls->tp_as_sequence = &attrwrapper_as_sequence;
attrwrapper_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::setitem, UNKNOWN, 3)));
attrwrapper_cls->giveAttr(
"pop", new BoxedFunction(boxRTFunction((void*)AttrWrapper::pop, UNKNOWN, 3, false, false), { NULL }));
attrwrapper_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::getitem, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("__getitem__",
new BoxedFunction(boxRTFunction((void*)AttrWrapper::getitem<CXX>, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::delitem, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("setdefault",
new BoxedFunction(boxRTFunction((void*)AttrWrapper::setdefault, UNKNOWN, 3)));
......@@ -3850,7 +3884,7 @@ void setupRuntime() {
"get", new BoxedFunction(boxRTFunction((void*)AttrWrapper::get, UNKNOWN, 3, false, false), { None }));
attrwrapper_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::str, UNKNOWN, 1)));
attrwrapper_cls->giveAttr("__contains__",
new BoxedFunction(boxRTFunction((void*)AttrWrapper::contains, UNKNOWN, 2)));
new BoxedFunction(boxRTFunction((void*)AttrWrapper::contains<CXX>, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::eq, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::ne, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("keys", new BoxedFunction(boxRTFunction((void*)AttrWrapper::keys, LIST, 1)));
......@@ -3868,6 +3902,9 @@ void setupRuntime() {
new BoxedFunction(boxRTFunction((void*)AttrWrapper::update, NONE, 1, true, true)));
attrwrapper_cls->freeze();
attrwrapper_cls->tp_iter = AttrWrapper::iter;
attrwrapper_cls->tp_as_mapping->mp_subscript = (binaryfunc)AttrWrapper::getitem<CAPI>;
attrwrapper_cls->tp_as_mapping->mp_ass_subscript = (objobjargproc)AttrWrapper::ass_sub;
attrwrapper_cls->tp_as_sequence->sq_contains = (objobjproc)AttrWrapper::sq_contains;
attrwrapperiter_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)AttrWrapperIter::hasnext, UNKNOWN, 1)));
......
......@@ -104,19 +104,28 @@ Box* noneIfNull(Box* b) {
}
}
Box* coerceUnicodeToStr(Box* unicode) {
template <ExceptionStyle S> Box* coerceUnicodeToStr(Box* unicode) noexcept(S == CAPI) {
if (!isSubclass(unicode->cls, unicode_cls))
return unicode;
Box* r = PyUnicode_AsASCIIString(unicode);
if (!r) {
PyErr_Clear();
raiseExcHelper(TypeError, "Cannot use non-ascii unicode strings as attribute names or keywords");
if (S == CAPI) {
PyErr_SetString(TypeError, "Cannot use non-ascii unicode strings as attribute names or keywords");
return NULL;
} else {
PyErr_Clear();
raiseExcHelper(TypeError, "Cannot use non-ascii unicode strings as attribute names or keywords");
}
}
return r;
}
// force instantiation:
template Box* coerceUnicodeToStr<CXX>(Box* unicode);
template Box* coerceUnicodeToStr<CAPI>(Box* unicode);
Box* boxStringFromCharPtr(const char* s) {
return boxString(s);
}
......
......@@ -56,7 +56,7 @@ Box* boxStringFromCharPtr(const char* s);
// strings and a string that happens to be its encoding. It seems safer to just encode as ascii,
// which will throw an exception if you try to pass something that might run into this risk.
// (We wrap the unicode error and throw a TypeError)
Box* coerceUnicodeToStr(Box* unicode);
template <ExceptionStyle S> Box* coerceUnicodeToStr(Box* unicode) noexcept(S == CAPI);
extern "C" bool hasnext(Box* o);
extern "C" void dump(void* p);
......
......@@ -165,3 +165,4 @@ class C(object):
return MyUnicode("hello world")
print type(unicode(C()))
print unicode("test", encoding="UTF-8")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment