isuckatcs added a comment.
> I'm particularly interested in the case of tuple-like containers, which is a
> little different (though I think the same point holds)
`std::pair<>` is actually tuple-like if that's what you meant. Only tuple-like
types have holding vars inside a `DecompositionDecl`.
> Here, both lines 7 and 13 are blank but seem to be the underlying tuple
> that's being deconstructed. Are these different instances of the
> DecompositionDecl or are they (unprinted) references back to line 4?
Those lines are what you see as `DeclRefExpr Decomposition ''` in the AST.
Which are indeed references back to line 4 as you mentioned.
> I'm still bothered that this seems to violate the design/philosophy of the
> CFG, which I take as ensuring that elements proceed in the order of operation.
I think in this case the elements do proceed in order of operation. When you
create a structured binding by value to a tuple like type, the copy constructor
of the type is invoked first.
Let's assume that you have a tuple-like `std::pair<int, int> p{1, 2};` and you
create the structured binding `auto [a, b] = p;`.
1. The copy constructor of `p` is invoked first and a copy get's created. Let's
call this copy `tmp`. Note that if the copy constructor has side effects, they
will also be visible.
2. A new variable for each element in the tuple is created and is initialized
by `get<idx>(tmp);`. It is important that the initialization happens from the
copy, `tmp` and not from the original tuple `p`.
The CFG resembles this behaviour. If you look at both of the example CFGs in
this discussion, you can see that both of them begin with the constructor
invocation.
7: p
8: [B1.7] (ImplicitCastExpr, NoOp, const pair<int, int>)
9: [B1.8] (CXXConstructExpr, [B1.10], std::pair<int, int>)
10: auto = p;
1: mk
2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, std::tuple<_Bool, int>
(*)(void))
3: [B1.2]() (CXXRecordTypedCall, [B1.4])
4: auto = mk();
Points `4` and `10` are a bit weird, but that's where the copy is created,
however the copy is unnamed. This unnamed copy is what I refered to as `tmp`.
Note that when you do a regular copy-constructor invocation like
std::tuple<bool, int> mk;
std::tuple<bool, int> mk2 = mk;
you would get
3: mk
4: [B1.3] (ImplicitCastExpr, NoOp, const class std::tuple<_Bool, int>)
5: [B1.4] (CXXConstructExpr, [B1.6], std::tuple<_Bool, int>)
6: std::tuple<bool, int> mk2 = mk;
^^^This is the name that's missing from the CFGs
above.
After this the `get<>()` calls simply use this unnamed copy to initialize the
elements from first to last, so everything seems to proceed in order in the CFG.
> Finally, a nit: why doesn't line 13 in your example, and lines 7 and 13 in my
> example, print? Is that something that I could add to the CFG printer?
If I remember correctly (and my intuition is correct based on the examples) a
`DeclRefExpr` in the CFG is the name of the variable being referenced.
So for example `DeclRefExpr 'p'` is simply `p` in the CFG.
If you look at the AST in my example, you can see that the `DeclRefExpr` to the
decomposition is `DeclRefExpr Decomposition ''`, where `''`
is supposed to be the name of the variable. So I think the empty line comes
from here.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D139544/new/
https://reviews.llvm.org/D139544
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits