davrec added inline comments.

================
Comment at: clang/lib/AST/ASTContext.cpp:12767
+        Ctx.getQualifiedType(Underlying),
+        ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl()));
+  }
----------------
mizvekov wrote:
> davrec wrote:
> > mizvekov wrote:
> > > davrec wrote:
> > > > This last argument should probably be omitted/nullptr passed, since
> > > > # We probably won't encounter any owned tag decls in the types passed 
> > > > to this function;
> > > > # Even if we did, it would not necessarily be true that they both have 
> > > > non-null owned tag decls, and I don't see any nullptr checks in 
> > > > getCommonDecl; and
> > > > # Even if we checked for nullptr there, and say passed the same 
> > > > argument to X and Y so EX==EY, and that had an owned tag decl, it is 
> > > > not clear to me it would be appropriate to construct a new type with 
> > > > the same owned tag decl as another type.
> > > 1. We can see, a one liner like this will do: `int e = true ? (struct 
> > > S*)0 : (struct S*)0;`
> > > 
> > > Though normally in an example like the above, you would only see the 
> > > owned decl on X, because when we get to Y the name has already been 
> > > introduced into the scope.
> > > 
> > > I have an idea for a test case, but it's a bit convoluted:
> > > 
> > > This also introduces an OwnedTagDecl: `(struct S<T>*)0`.
> > > 
> > > So with resugaring, if we resugar T, it might be possible to construct 
> > > this situatiation. Given if it's appropriate to keep the OwnedTagDecl 
> > > when resugaring, of course, which goes to 3)
> > > 
> > > 2. This is handled by `declaresSameEntity`, if either or both decls are 
> > > null, we say they are not the same decl.
> > > 
> > > 3. That I am not sure. I see that this OwnedTagDecl is only used by the 
> > > type printer, and it replaces printing the rest of the type by printing 
> > > the OwnedDecl instead. So why do you think it would not be appropriate 
> > > that the rebuilt type keeps this?
> > (Re #3) Because I think the sense ownership is respected in how 
> > ownedTagDecls are presently handled: at most one ElaboratedType owns a 
> > particular TagDecl, *and* that type does not seem to be reused elsewhere in 
> > the AST.  (This is relied on in https://reviews.llvm.org/D131685, which was 
> > on my mind when I looked at this.)
> > 
> > E.g. consider this expansion of your example:
> > ```
> > auto e = true ? (struct S*)0 : (true ? (struct S*)0 : (struct S*)0);
> > ```
> > The first ElaboratedType has an ownedTagDecl; the second is a distinct 
> > ElaboratedType without an ownedTagDecl, and the third equals the second.  
> > 
> > Now in practice what this means is that `getCommonDecl` when used on binary 
> > expressions of this sort will always be nullptr, so no harm done.  But 
> > suppose it is called with X=Y=some ET with an ownedTagDecl (which is the 
> > only time I believe we could see a non null getCommonDecl result here).  
> > Should the type that is returned have that same owned tag decl?  I think 
> > that would violate the sense of the original type "owning" that decl that 
> > seems to be respected elsewhere in the AST.
> > 
> > Re type printing, I believe that ownedTagDecls only affects printing of 
> > defined TagDecls like `struct S { int i; } x;` (which is what I was mostly 
> > thinking re ownedTagDecls - I don't think we will see those here); for 
> > undefined ones like `struct S x;`, printing should be unaffected whether 
> > there is an ownedTagDecl or not.
> > 
> With type deduction this can happen:
> 
> ```
> auto x = (struct S*)0; // it will also appear in the type of x
> using t = decltype(x); // and now also in t
> ```
> 
> With your second example, it can also happen:
> 
> ```
> struct S { int i; } x;
> int e = true ? &x : (struct S*)0;
> ```
> 
> In those cases, the type node that owns the decl will be the same object, but 
> that is only because of uniquing.
> 
> It may be possible that two different objects end up in this situation, if 
> for example they come from different modules that got merged.
> With type deduction this can happen:
> ```
> auto x = (struct S*)0; // it will also appear in the type of x
> using t = decltype(x); // and now also in t
> ```

My local clang is out of date - the type of `x` for me is just an AutoType 
wrapping a PointerType to a RecordType.  In light of the addition of the 
ElaboratedType there, it seems fine to be consistent here with however that 
case handles ownedTagDecls, but FWIW I do not think that deduced ElaboratedType 
should have an ownedTagDecl either.  Only the original type should be the owner 
- not any type deduced from it.

This is a minor issue with few if any observable effects for now, but should be 
kept in mind if issues arise later: the fact the ownership of ownedTagDecls is 
respected was the only factor that made 
https://discourse.llvm.org/t/ast-parent-of-class-in-a-friend-declaration/64275 
easily solvable.

> With your second example, it can also happen:
> 
> ```
> struct S { int i; } x;
> int e = true ? &x : (struct S*)0;
> ```

The DeclRefExpr `x` indeed reuses the ElaboratedType used in the VarDecl `x`, 
with its ownedTagDecl and all.  That seems fair, a special case.  For all other 
type deductions I would mildly object to including an ownedTagDecl.



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130308

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

Reply via email to