From 88fd5c84408ac7e4cd577a91d29a02864efb5954 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 31 Mar 2019 04:12:27 +0100 Subject: [PATCH] compiler: Fix crash in escape analysis for assigning string literals --- artiq/compiler/validators/escape.py | 28 ++++++++++++++------------- artiq/test/lit/escape/const_string.py | 4 ++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py index de3db9191..000c3ee5b 100644 --- a/artiq/compiler/validators/escape.py +++ b/artiq/compiler/validators/escape.py @@ -51,10 +51,6 @@ class Region: (other.range.begin_pos <= self.range.begin_pos <= other.range.end_pos and \ self.range.end_pos > other.range.end_pos) - def contract(self, other): - if not self.range: - self.range = other.range - def outlives(lhs, rhs): if not isinstance(lhs, Region): # lhs lives nonlexically return True @@ -69,8 +65,11 @@ class Region: class RegionOf(algorithm.Visitor): """ - Visit an expression and return the list of regions that must - be alive for the expression to execute. + Visit an expression and return the region that must be alive for the + expression to execute. + + For expressions involving multiple regions, the shortest-lived one is + returned. """ def __init__(self, env_stack, youngest_region): @@ -301,17 +300,20 @@ class EscapeValidator(algorithm.Visitor): def visit_assignment(self, target, value): value_region = self._region_of(value) - # If this is a variable, we might need to contract the live range. - if isinstance(value_region, Region): - for name in self._names_of(target): - region = self._region_of(name) - if isinstance(region, Region): - region.contract(value_region) - # If we assign to an attribute of a quoted value, there will be no names # in the assignment lhs. target_names = self._names_of(target) or [] + # Adopt the value region for any variables declared on the lhs. + for name in target_names: + region = self._region_of(name) + if isinstance(region, Region) and not region.present(): + # Find the name's environment to overwrite the region. + for env in self.env_stack[::-1]: + if name.id in env: + env[name.id] = value_region + break + # The assigned value should outlive the assignee target_regions = [self._region_of(name) for name in target_names] for target_region in target_regions: diff --git a/artiq/test/lit/escape/const_string.py b/artiq/test/lit/escape/const_string.py index f5f405c86..f5c844c05 100644 --- a/artiq/test/lit/escape/const_string.py +++ b/artiq/test/lit/escape/const_string.py @@ -9,3 +9,7 @@ def foo(): @kernel def entrypoint(): foo() + + # Test reassigning strings. + a = "a" + b = a