rsmith added a comment.

In D62988#1539230 <https://reviews.llvm.org/D62988#1539230>, @ahatanak wrote:

> In D62988#1538577 <https://reviews.llvm.org/D62988#1538577>, @rsmith wrote:
>
> > How do you write correct (non-leaking, non-double-freeing, 
> > non-releasing-invalid-pointers) code with this attribute? For example, 
> > suppose I have a `__strong` union member: does storing to it release the 
> > old value (which might be a different union member)? If so, how do you work 
> > around that? 
> > https://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership-qualified-fields-of-structs-and-unions
> >  should be updated to say what happens. If manual reference counting code 
> > is required to make any use of this feature correct (which seems 
> > superficially likely), is this a better programming model than 
> > `__unsafe_unretained`?
>
>
> I should first make it clear that this attribute is a dangerous feature that 
> makes it easier for users to write incorrect code if they aren't careful.
>
> To write correct code, users have to manually (I don't mean 
> manual-retain-release, this is compiled with ARC) do assignments to the 
> fields that are annotated with the attribute to patch up the code generated 
> by the compiler since the compiler isn't generating the kind of special 
> functions it generates for non-trivial structs. For example:
>
>   union U1 {
>     id __weak __attribute__((non_trivial_union_member)) a;
>     id __attribute__((non_trivial_union_member)) b;
>   };
>    
>   id getObj(int);
>  
>   void foo() {
>     union U1 u1 = { .b = 0}; // zero-initialize 'b'.
>     u1.b = getObj(1); // assign to __strong field 'b'.
>     u1.b = getObj(2); // retain and assign another object to 'b' and release 
> the previously referenced object.


This is what I expected and what I was worried about. I could be missing 
something, but this approach appears to me to cause this feature to not be 
useful in many cases. If a store to a union member now first reads from (and 
releases) that union member, then you cannot change the active union member to 
a member with lifetime type, because that would trigger a load of an inactive 
union member with undefined behavior. For example, consider:

  union U {
    float f;
    __attribute__((non_trivial_union_member)) id b;
  };
  void f() {
    union U u = {.f = 1.0f};
    u.b = getObj(1); // undefined behavior: tries to release existing value of 
u.b, which is not active union member; the implied `[u.b release]` is going to 
do Very Bad Things.

In C, storing to a union member is the way you change the active member, and I 
can't off-hand think of any sensible workaround for this problem. But maybe I 
overlooked it: can you demonstrate how you would correctly write the last line 
of the above example? If that can't be done reasonably, I do not think we 
should add this attribute.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D62988/new/

https://reviews.llvm.org/D62988



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to