-
Notifications
You must be signed in to change notification settings - Fork 15k
[clang][Expr] Teach IgnoreUnlessSpelledInSource about implicit calls to std::get free function #122265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang][Expr] Teach IgnoreUnlessSpelledInSource about implicit calls to std::get free function #122265
Changes from 13 commits
a9e13ad
91dae19
6694000
6ea0f3f
1e2ca23
b156e5a
23b879c
549d18c
f61bde6
7bc878e
4ad1c79
821a5a0
a6d9cd2
6570649
5b2a5e9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2544,6 +2544,19 @@ Stmt *BlockExpr::getBody() { | |||||
| //===----------------------------------------------------------------------===// | ||||||
| // Generic Expression Routines | ||||||
| //===----------------------------------------------------------------------===// | ||||||
| namespace { | ||||||
| /// Helper to determine wether \c E is a CXXConstructExpr constructing | ||||||
| /// a DecompositionDecl. Used to skip Clang-generated calls to std::get | ||||||
| /// for structured bindings. | ||||||
| bool IsDecompositionDeclRefExpr(const Expr *E) { | ||||||
| const Expr *Unrwapped = E->IgnoreUnlessSpelledInSource(); | ||||||
|
||||||
| const Expr *Unrwapped = E->IgnoreUnlessSpelledInSource(); | |
| const Expr *Unwrapped = E->IgnoreUnlessSpelledInSource(); |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const DeclRefExpr *Ref = llvm::dyn_cast_or_null<DeclRefExpr>(Unrwapped); | |
| const auto *Ref = dyn_cast_or_null<DeclRefExpr>(Unrwapped); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think E can be null, so Unwrapped probably cannot be null either, it should just be dyn_cast
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return llvm::isa_and_nonnull<DecompositionDecl>(Ref->getDecl()); | |
| return isa_and_nonnull<DecompositionDecl>(Ref->getDecl()); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,80 @@ | ||
| // Structured binding in C++ can bind identifiers to subobjects of an object. | ||
| // | ||
| // There are three cases we need to test: | ||
| // There are four cases we need to test: | ||
| // 1) arrays | ||
| // 2) tuples like objects | ||
| // 3) non-static data members | ||
| // 2) tuple-like objects with `get` member functions | ||
| // 3) tuple-like objects with `get` free functions | ||
| // 4) non-static data members | ||
| // | ||
| // They can also bind by copy, reference or rvalue reference. | ||
|
|
||
| #include <tuple> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed in favour of |
||
| struct MyPair { | ||
| int m1; | ||
| int m2; | ||
|
|
||
| // Helpers to enable tuple-like decomposition. | ||
| template <unsigned> int get(); | ||
| template <> int get<0>() { return m1; } | ||
| template <> int get<1>() { return m2; } | ||
| }; | ||
|
|
||
| namespace std { | ||
| template <typename T1, typename T2, typename T3> struct mock_tuple { | ||
| T1 m1; | ||
| T2 m2; | ||
| T3 m3; | ||
| }; | ||
|
|
||
| template <typename T> struct tuple_size; | ||
|
|
||
| template <unsigned, typename T> struct tuple_element; | ||
|
|
||
| // Helpers to enable tuple-like decomposition for MyPair | ||
| template <unsigned I> struct tuple_element<I, MyPair> { | ||
| using type = int; | ||
| }; | ||
|
|
||
| template <> struct tuple_size<MyPair> { | ||
| static constexpr unsigned value = 2; | ||
| }; | ||
|
|
||
| // Helpers to enable tuple-like decomposition for mock_tuple | ||
| template <typename T1, typename T2, typename T3> | ||
| struct tuple_element<0, mock_tuple<T1, T2, T3>> { | ||
| using type = T1; | ||
| }; | ||
|
|
||
| template <typename T1, typename T2, typename T3> | ||
| struct tuple_element<1, mock_tuple<T1, T2, T3>> { | ||
| using type = T2; | ||
| }; | ||
|
|
||
| template <typename T1, typename T2, typename T3> | ||
| struct tuple_element<2, mock_tuple<T1, T2, T3>> { | ||
| using type = T3; | ||
| }; | ||
|
|
||
| template <typename T1, typename T2, typename T3> | ||
| struct tuple_size<mock_tuple<T1, T2, T3>> { | ||
| static constexpr unsigned value = 3; | ||
| }; | ||
|
|
||
| template <unsigned I, typename T1, typename T2, typename T3> | ||
| typename tuple_element<I, mock_tuple<T1, T2, T3>>::type | ||
| get(mock_tuple<T1, T2, T3> p) { | ||
| switch (I) { | ||
| case 0: | ||
| return p.m1; | ||
| case 1: | ||
| return p.m2; | ||
| case 2: | ||
| return p.m3; | ||
| default: | ||
| __builtin_trap(); | ||
| } | ||
| } | ||
|
|
||
| } // namespace std | ||
|
|
||
| struct A { | ||
| int x; | ||
|
|
@@ -54,16 +121,18 @@ int main() { | |
| char y{'z'}; | ||
| int z{10}; | ||
|
|
||
| std::tuple<float, char, int> tpl(x, y, z); | ||
| std::mock_tuple<float, char, int> tpl{.m1 = x, .m2 = y, .m3 = z}; | ||
| auto [tx1, ty1, tz1] = tpl; | ||
| auto &[tx2, ty2, tz2] = tpl; | ||
|
|
||
| auto [mp1, mp2] = MyPair{.m1 = 1, .m2 = 2}; | ||
|
|
||
| return a1.x + b1 + c1 + d1 + e1 + f1 + a2.y + b2 + c2 + d2 + e2 + f2 + a3.x + | ||
| b3 + c3 + d3 + e3 + f3 + carr_copy1 + carr_copy2 + carr_copy3 + | ||
| sarr_copy1 + sarr_copy2 + sarr_copy3 + iarr_copy1 + iarr_copy2 + | ||
| iarr_copy3 + carr_ref1 + carr_ref2 + carr_ref3 + sarr_ref1 + | ||
| sarr_ref2 + sarr_ref3 + iarr_ref1 + iarr_ref2 + iarr_ref3 + | ||
| carr_rref1 + carr_rref2 + carr_rref3 + sarr_rref1 + sarr_rref2 + | ||
| sarr_rref3 + iarr_rref1 + iarr_rref2 + iarr_rref3 + tx1 + ty1 + tz1 + | ||
| tx2 + ty2 + tz2; // break here | ||
| tx2 + ty2 + tz2 + mp1 + mp2; // break here | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use static rather than an anonymous namespace here