From 5bf0fc486f8da639558472270131557ef7f0619f Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Thu, 28 May 2020 13:56:53 -0700 Subject: [PATCH] [mypyc] Refactor of load_final_static, make it report NameError (#8915) Pull out handling of of the error checks into ll_builder, and report the right exception. This is groundwork for fixing some potential segfaults involving uninitialized classes. --- mypyc/ir/ops.py | 1 + mypyc/irbuild/builder.py | 18 +++++------------- mypyc/irbuild/ll_builder.py | 22 ++++++++++++++++++++-- mypyc/test-data/fixtures/ir.py | 2 ++ mypyc/test-data/irbuild-basic.test | 6 +++--- mypyc/test-data/run.test | 2 +- 6 files changed, 32 insertions(+), 19 deletions(-) diff --git a/mypyc/ir/ops.py b/mypyc/ir/ops.py index 6e3c1b0875dc..a0f83f10cc21 100644 --- a/mypyc/ir/ops.py +++ b/mypyc/ir/ops.py @@ -1113,6 +1113,7 @@ class RaiseStandardError(RegisterOp): STOP_ITERATION = 'StopIteration' # type: Final UNBOUND_LOCAL_ERROR = 'UnboundLocalError' # type: Final RUNTIME_ERROR = 'RuntimeError' # type: Final + NAME_ERROR = 'NameError' # type: Final def __init__(self, class_name: str, value: Optional[Union[str, Value]], line: int) -> None: super().__init__(line) diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index be634be14150..beed68ca635a 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -34,7 +34,7 @@ BasicBlock, AssignmentTarget, AssignmentTargetRegister, AssignmentTargetIndex, AssignmentTargetAttr, AssignmentTargetTuple, Environment, LoadInt, Value, Register, Op, Assign, Branch, Unreachable, TupleGet, GetAttr, SetAttr, LoadStatic, - InitStatic, PrimitiveOp, OpDescription, NAMESPACE_MODULE, RaiseStandardError + InitStatic, PrimitiveOp, OpDescription, NAMESPACE_MODULE, RaiseStandardError, ) from mypyc.ir.rtypes import ( RType, RTuple, RInstance, int_rprimitive, dict_rprimitive, @@ -315,20 +315,12 @@ def init_final_static(self, lvalue: Lvalue, rvalue_reg: Value, def load_final_static(self, fullname: str, typ: RType, line: int, error_name: Optional[str] = None) -> Value: - if error_name is None: - error_name = fullname - ok_block, error_block = BasicBlock(), BasicBlock() split_name = split_target(self.graph, fullname) assert split_name is not None - value = self.add(LoadStatic(typ, split_name[1], split_name[0], line=line)) - self.add(Branch(value, error_block, ok_block, Branch.IS_ERROR, rare=True)) - self.activate_block(error_block) - self.add(RaiseStandardError(RaiseStandardError.VALUE_ERROR, - 'value for final name "{}" was not set'.format(error_name), - line)) - self.add(Unreachable()) - self.activate_block(ok_block) - return value + module, name = split_name + return self.builder.load_static_checked( + typ, name, module, line=line, + error_msg='value for final name "{}" was not set'.format(error_name)) def load_final_literal_value(self, val: Union[int, str, bytes, float, bool], line: int) -> Value: diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 91a2cde1dc68..607bf4b264ef 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -19,8 +19,9 @@ from mypyc.ir.ops import ( BasicBlock, Environment, Op, LoadInt, Value, Register, Assign, Branch, Goto, Call, Box, Unbox, Cast, GetAttr, - LoadStatic, MethodCall, PrimitiveOp, OpDescription, RegisterOp, - NAMESPACE_TYPE, NAMESPACE_MODULE, LoadErrorValue, CallC + LoadStatic, MethodCall, PrimitiveOp, OpDescription, RegisterOp, CallC, + RaiseStandardError, Unreachable, LoadErrorValue, + NAMESPACE_TYPE, NAMESPACE_MODULE, NAMESPACE_STATIC, ) from mypyc.ir.rtypes import ( RType, RUnion, RInstance, optional_value_type, int_rprimitive, float_rprimitive, @@ -457,6 +458,23 @@ def load_static_unicode(self, value: str) -> Value: static_symbol = self.literal_static_name(value) return self.add(LoadStatic(str_rprimitive, static_symbol, ann=value)) + def load_static_checked(self, typ: RType, identifier: str, module_name: Optional[str] = None, + namespace: str = NAMESPACE_STATIC, + line: int = -1, + error_msg: Optional[str] = None) -> Value: + if error_msg is None: + error_msg = "name '{}' is not defined".format(identifier) + ok_block, error_block = BasicBlock(), BasicBlock() + value = self.add(LoadStatic(typ, identifier, module_name, namespace, line=line)) + self.add(Branch(value, error_block, ok_block, Branch.IS_ERROR, rare=True)) + self.activate_block(error_block) + self.add(RaiseStandardError(RaiseStandardError.NAME_ERROR, + error_msg, + line)) + self.add(Unreachable()) + self.activate_block(ok_block) + return value + def load_module(self, name: str) -> Value: return self.add(LoadStatic(object_rprimitive, name, namespace=NAMESPACE_MODULE)) diff --git a/mypyc/test-data/fixtures/ir.py b/mypyc/test-data/fixtures/ir.py index 9218734b0e76..7faca81dff40 100644 --- a/mypyc/test-data/fixtures/ir.py +++ b/mypyc/test-data/fixtures/ir.py @@ -183,6 +183,8 @@ class TypeError(Exception): pass class AttributeError(Exception): pass +class NameError(Exception): pass + class LookupError(Exception): pass class KeyError(LookupError): pass diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 6392539519e6..024b4e8dba3b 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -3247,7 +3247,7 @@ L0: r0 = __main__.x :: static if is_error(r0) goto L1 else goto L2 L1: - raise ValueError('value for final name "x" was not set') + raise NameError('value for final name "x" was not set') unreachable L2: r2 = 0 @@ -3271,7 +3271,7 @@ L0: r0 = __main__.x :: static if is_error(r0) goto L1 else goto L2 L1: - raise ValueError('value for final name "x" was not set') + raise NameError('value for final name "x" was not set') unreachable L2: r2 = r0[0] @@ -3294,7 +3294,7 @@ L0: r0 = __main__.x :: static if is_error(r0) goto L1 else goto L2 L1: - raise ValueError('value for final name "x" was not set') + raise NameError('value for final name "x" was not set') unreachable L2: r2 = 1 diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index c2448caa9e6e..8c03352d22d6 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -4451,7 +4451,7 @@ def f() -> int: from native import f try: print(f()) -except ValueError as e: +except NameError as e: print(e.args[0]) [out] value for final name "x" was not set