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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits