@@ -2484,7 +2484,7 @@ def apply(self, inits, location, scope):
2484
2484
class StringCStrApply (Expression ):
2485
2485
priority = dml .expr .Apply .priority
2486
2486
2487
- slots = ('type' , 'constant' , 'value' )
2487
+ slots = ('type' ,)
2488
2488
2489
2489
@auto_init
2490
2490
def __init__ (self , site , expr ):
@@ -2493,16 +2493,21 @@ def __init__(self, site, expr):
2493
2493
TNamed ('char' ,
2494
2494
const = (not expr .writable
2495
2495
or safe_realtype_shallow (expr .ctype ()).const )))
2496
- self .constant = expr .constant
2497
- self .value = expr .value if expr .constant else None
2498
2496
2499
2497
def __str__ (self ):
2500
2498
return str_expr_pseudomethod (self .expr , 'c_str()' )
2501
2499
2502
2500
def read (self ):
2503
2501
return f'_dml_string_str({ self .expr .read ()} )'
2504
2502
2503
+ @property
2504
+ def is_pointer_to_stack_allocation (self ):
2505
+ return self .expr .is_stack_allocated
2506
+
2505
2507
def mkStringCStrApply (site , expr ):
2508
+ if expr .constant and isinstance (expr , FromCString ):
2509
+ return mkStringConstant (site , expr .value )
2510
+
2506
2511
if expr .orphan :
2507
2512
expr = mkAdoptedOrphan (expr .site , expr )
2508
2513
return StringCStrApply (site , expr )
@@ -2807,7 +2812,7 @@ def make_simple(cls, site, rh):
2807
2812
2808
2813
@property
2809
2814
def is_pointer_to_stack_allocation (self ):
2810
- return self .rh .writable and self . rh . is_stack_allocated
2815
+ return self .rh .is_stack_allocated
2811
2816
2812
2817
def mkAddressOf (site , rh ):
2813
2818
if dml .globals .compat_dml12_int (site ):
@@ -4612,11 +4617,14 @@ class StructMember(Expression):
4612
4617
priority = 160
4613
4618
explicit_type = True
4614
4619
4620
+ slots = ('orphan' ,)
4621
+
4615
4622
@auto_init
4616
4623
def __init__ (self , site , expr , sub , type , op ):
4617
4624
assert not expr .writable or expr .c_lval
4618
4625
assert_type (site , expr , Expression )
4619
4626
assert_type (site , sub , str )
4627
+ self .orphan = expr .orphan and op == '.'
4620
4628
4621
4629
@property
4622
4630
def writable (self ):
@@ -4643,7 +4651,9 @@ def read(self):
4643
4651
4644
4652
@property
4645
4653
def is_stack_allocated (self ):
4646
- return self .expr .writable and self .expr .is_stack_allocated
4654
+ return (self .expr .is_stack_allocated
4655
+ if self .op == '.' else
4656
+ self .expr .is_pointer_to_stack_allocation )
4647
4657
4648
4658
@property
4649
4659
def is_pointer_to_stack_allocation (self ):
@@ -4697,7 +4707,12 @@ def structmember_expr(): return mkAdoptedOrphan(expr.site, expr)
4697
4707
typ = real_basetype .get_member_qualified (sub )
4698
4708
if not typ :
4699
4709
raise EMEMBER (site , baseexpr , sub )
4700
- return StructMember (site , structmember_expr (), sub , typ , op )
4710
+ subref = StructMember (site , structmember_expr (), sub , typ , op )
4711
+ return (AdoptedOrphan (site , subref )
4712
+ if (subref .orphan
4713
+ and isinstance (safe_realtype_shallow (typ ), TArray ))
4714
+ else subref )
4715
+
4701
4716
elif real_basetype .is_int and real_basetype .is_bitfields :
4702
4717
member = real_basetype .members .get (sub )
4703
4718
if member is None :
@@ -4844,7 +4859,9 @@ class ArrayRef(LValue):
4844
4859
@auto_init
4845
4860
def __init__ (self , site , expr , idx ):
4846
4861
expr_type = realtype_shallow (expr .ctype ())
4847
- self .type = conv_const (expr_type .const , expr_type .base )
4862
+ self .type = conv_const (expr_type .const
4863
+ and isinstance (expr_type , TArray ),
4864
+ expr_type .base )
4848
4865
def __str__ (self ):
4849
4866
return '%s[%s]' % (self .expr , self .idx )
4850
4867
def read (self ):
@@ -4893,6 +4910,8 @@ def mkStringCharRef(site, expr, idx):
4893
4910
# Not considered addressable, as the address of an elem is very easily
4894
4911
# invalidated.
4895
4912
# Users have to use .c_buf() instead to acknowledge that possibility.
4913
+ # TODO(RAII): users may shoot themselves in the foot anyway, if the basetype
4914
+ # is an array or a struct with array member. What do we do about that?
4896
4915
class VectorRef (Expression ):
4897
4916
slots = ('type' ,)
4898
4917
priority = dml .expr .Apply .priority
@@ -4901,6 +4920,7 @@ class VectorRef(Expression):
4901
4920
4902
4921
@auto_init
4903
4922
def __init__ (self , site , expr , idx ):
4923
+ assert not expr .orphan
4904
4924
typ = safe_realtype_shallow (self .expr .ctype ())
4905
4925
self .type = conv_const (typ .const , typ .base )
4906
4926
@@ -4914,6 +4934,15 @@ def read(self):
4914
4934
% (base_typ .declaration ('' ), self .expr .read (),
4915
4935
self .idx .read ()))
4916
4936
4937
+ @property
4938
+ def is_stack_allocated (self ):
4939
+ return self .expr .is_stack_allocated
4940
+
4941
+ @property
4942
+ def is_pointer_to_stack_allocation (self ):
4943
+ return (isinstance (safe_realtype_shallow (self .type ), TArray )
4944
+ and self .is_stack_allocated )
4945
+
4917
4946
def mkVectorRef (site , expr , idx ):
4918
4947
if idx .constant and idx .value < 0 :
4919
4948
raise EOOB (expr )
@@ -5029,6 +5058,8 @@ def mkCast(site, expr, new_type):
5029
5058
# these casts are permitted by C only if old and new are
5030
5059
# the same type, which is useless
5031
5060
return Cast (site , expr , new_type )
5061
+ if isinstance (real , (TVoid , TArray , TFunction )):
5062
+ raise ECAST (site , expr , new_type )
5032
5063
if old_type .cmp (real ) == 0 :
5033
5064
if (old_type .is_int
5034
5065
and not old_type .is_endian
@@ -5041,7 +5072,7 @@ def mkCast(site, expr, new_type):
5041
5072
raise ECAST (site , expr , new_type )
5042
5073
if isinstance (real , TExternStruct ):
5043
5074
raise ECAST (site , expr , new_type )
5044
- if isinstance (real , (TVoid , TArray , TVector , TTraitList , TFunction )):
5075
+ if isinstance (real , (TVector , TTraitList )):
5045
5076
raise ECAST (site , expr , new_type )
5046
5077
if isinstance (old_type , (TVoid , TStruct , TVector , TTraitList , TTrait )):
5047
5078
raise ECAST (site , expr , new_type )
@@ -5599,20 +5630,27 @@ def read(self):
5599
5630
return f'(({ self .type .declaration ("" )} ){ self .init .read ()} )'
5600
5631
5601
5632
class ArrayCompoundLiteral (Expression ):
5602
- slots = ('read_adopted' ,)
5633
+ slots = ('read_adopted' , 'is_stack_allocated' )
5603
5634
# TODO(RAII) writable?
5604
5635
addressable = True
5605
5636
c_lval = True
5606
5637
@auto_init
5607
5638
def __init__ (self , site , init , type ):
5608
5639
assert isinstance (init , (CompoundInitializer , MemsetInitializer ))
5640
+ self .is_stack_allocated = isinstance (TopRAIIScope .active ,
5641
+ MethodRAIIScope )
5609
5642
self .read_adopted = RAIIScope .reserve_orphan_adoption (
5610
5643
site , CompoundLiteral (site , init , type ))
5644
+
5611
5645
def __str__ (self ):
5612
5646
return 'cast(%s, %s)' % (self .init , self .type )
5613
5647
def read (self ):
5614
5648
return self .read_adopted ()
5615
5649
5650
+ @property
5651
+ def is_pointer_to_stack_allocation (self ):
5652
+ return self .is_stack_allocated
5653
+
5616
5654
class VectorCompoundLiteral (Orphan ):
5617
5655
'''Initializer for a variable of vector type, using the
5618
5656
{value1, value2, ...} syntax as in C'''
@@ -5670,14 +5708,14 @@ def discard(self):
5670
5708
5671
5709
class AdoptedOrphan (Expression ):
5672
5710
priority = dml .expr .Apply .priority
5673
- slots = ('read_adopted' , 'constant' , 'value ' )
5711
+ slots = ('read_adopted' , 'is_stack_allocated ' )
5674
5712
c_lval = True
5675
5713
@auto_init
5676
5714
def __init__ (self , site , expr ):
5677
5715
assert expr .orphan
5716
+ self .is_stack_allocated = isinstance (TopRAIIScope .active ,
5717
+ MethodRAIIScope )
5678
5718
self .read_adopted = RAIIScope .reserve_orphan_adoption (site , expr )
5679
- self .constant = expr .constant
5680
- self .value = expr .value if expr .constant else None
5681
5719
5682
5720
def __str__ (self ):
5683
5721
return str (self .expr )
@@ -5947,6 +5985,13 @@ def read():
5947
5985
def scope_stack (self ):
5948
5986
return [self ]
5949
5987
5988
+ # TODO(RAII): Very niche, and currently unleveraged! This is for orphans
5989
+ # adopted in the constant initializers of sessions/saveds. For example...
5990
+ #
5991
+ # session int *p = cast({0, 1, 2, 3}, int[4]);
5992
+ #
5993
+ # But no expression using RAIIScope.reserve_orphan_adoption is currently
5994
+ # considered constant.
5950
5995
class SessionRAIIScope (TopRAIIScope ):
5951
5996
def reserve_orphan_adoption (self , site , expr , subscope ):
5952
5997
assert subscope is self
@@ -6058,7 +6103,6 @@ def toc_stmt(self):
6058
6103
class StringCAppend (Statement ):
6059
6104
@auto_init
6060
6105
def __init__ (self , site , tgt , src ):
6061
- assert not src .orphan
6062
6106
assert tgt .c_lval
6063
6107
6064
6108
def toc_stmt (self ):
@@ -6070,8 +6114,8 @@ def mkStringAppend(site, tgt, src):
6070
6114
raise ERVAL (tgt , '+=' )
6071
6115
elif deep_const (tgt .ctype ()):
6072
6116
raise ENCONST (site )
6073
- if isinstance (src , FromCString ):
6074
- return StringCAppend (site , tgt , src . expr )
6117
+ if isinstance (src , StringConstant ):
6118
+ return StringCAppend (site , tgt , src )
6075
6119
return StringAppend (site , tgt , mkAdoptedOrphan (site , src ))
6076
6120
6077
6121
class VectorAppend (Statement ):
@@ -6177,6 +6221,11 @@ def read(self):
6177
6221
def ctype (self ):
6178
6222
return TPtr (self .basetype )
6179
6223
6224
+ @property
6225
+ def is_pointer_to_stack_allocation (self ):
6226
+ return self .expr .is_stack_allocated
6227
+
6228
+
6180
6229
mkVectorCBuf = VectorCBufRef
6181
6230
6182
6231
class VectorPopRef (PseudoMethodRef ):
0 commit comments