Skip to content

Commit e82cb3d

Browse files
author
andreasfertig
authored
Merge pull request andreasfertig#22 from andreasfertig/improveStructuredBindings
Improve structured bindings
2 parents e3da53b + ace9afe commit e82cb3d

15 files changed

+227
-258
lines changed

CodeGenerator.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -227,21 +227,13 @@ void CodeGenerator::InsertArg(const BinaryOperator* stmt)
227227

228228
static bool IsReference(const QualType& type)
229229
{
230-
return GetDesugarType(type)->isReferenceType();
231-
}
232-
//-----------------------------------------------------------------------------
233-
234-
static bool IsRValueReference(const QualType& type)
235-
{
236-
return GetDesugarType(type)->isRValueReferenceType();
230+
return GetDesugarType(type)->isLValueReferenceType();
237231
}
238232
//-----------------------------------------------------------------------------
239233

240234
static std::string GetReferenceOrRValueReferenceOrEmpty(const QualType& type)
241235
{
242-
if(IsRValueReference(type)) {
243-
return "&&";
244-
} else if(IsReference(type)) {
236+
if(IsReference(type)) {
245237
return "&";
246238
}
247239

@@ -347,14 +339,21 @@ void CodeGenerator::InsertArg(const DecompositionDecl* decompositionDeclStmt)
347339

348340
mOutputFormatHelper.Append(GetName(bindingDecl->getType()), refOrRefRef, " ", GetName(*bindingDecl), " = ");
349341

342+
const auto* holdingVarOrMemberExpr = [&]() -> const Expr* {
343+
if(const auto* holdingVar = bindingDecl->getHoldingVar()) {
344+
return holdingVar->getAnyInitializer();
345+
}
346+
347+
return dyn_cast_or_null<MemberExpr>(binding);
348+
}();
349+
350350
// tuple decomposition
351-
if(const auto* holdingVar = bindingDecl->getHoldingVar()) {
351+
if(holdingVarOrMemberExpr) {
352352
DPrint("4444\n");
353-
const auto* initializer = holdingVar->getAnyInitializer();
354353

355354
StructuredBindingsCodeGenerator structuredBindingsCodeGenerator{mOutputFormatHelper, tmpVarName};
356355
CodeGenerator& codeGenerator = structuredBindingsCodeGenerator;
357-
codeGenerator.InsertArg(initializer);
356+
codeGenerator.InsertArg(holdingVarOrMemberExpr);
358357

359358
// array decomposition
360359
} else if(const auto* arraySubscription = dyn_cast_or_null<ArraySubscriptExpr>(binding)) {

tests/Issue20.cerr

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/Issue20.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ int main()
44
{
55
std::map<int, int> map{ std::initializer_list<std::pair<const int, int> >{ std::pair<const int, int>(1, 2) } };
66
std::pair<const int, int> __operator6 = std::pair<const int, int>(map.begin().operator*());
7-
std::tuple_element<0, std::pair<const int, int> >::type&& key = std::get<0ul>(__operator6);
8-
std::tuple_element<1, std::pair<const int, int> >::type&& value = std::get<1ul>(__operator6);
7+
std::tuple_element<0, std::pair<const int, int> >::type key = std::get<0ul>(__operator6);
8+
std::tuple_element<1, std::pair<const int, int> >::type value = std::get<1ul>(__operator6);
99

1010
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include <cstdio>
2+
3+
int main() {
4+
struct SP
5+
{
6+
int x;
7+
int y;
8+
};
9+
10+
SP sp{1, 2};
11+
12+
auto[sx, sy] = sp;
13+
14+
class CP
15+
{
16+
public:
17+
int x;
18+
int y;
19+
};
20+
21+
CP cp{1,2};
22+
23+
auto [ c1, c2 ] = cp;
24+
25+
printf("c1: %d c2: %d\n", c1, c2);
26+
++c1;
27+
++c2;
28+
printf("c1: %d c2: %d\n", c1, c2);
29+
30+
auto& [ c3, c4 ] = cp;
31+
32+
printf("c3: %d c4: %d\n", c3, c4);
33+
++c3;
34+
++c4;
35+
printf("c3: %d c4: %d\n", c3, c4);
36+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <cstdio>
2+
3+
int main() {
4+
struct SP
5+
{
6+
int x;
7+
int y;
8+
/* public: inline SP(); */
9+
/* public: inline constexpr SP(const SP &) noexcept; */
10+
/* public: inline constexpr SP(SP &&); */
11+
};
12+
13+
SP sp{1, 2};
14+
15+
SP __sp12 = SP(sp);
16+
int sx = __sp12.x;
17+
int sy = __sp12.y;
18+
19+
20+
class CP
21+
{
22+
public:
23+
int x;
24+
int y;
25+
/* public: inline CP(); */
26+
/* public: inline constexpr CP(const CP &) noexcept; */
27+
/* public: inline constexpr CP(CP &&); */
28+
};
29+
30+
CP cp{1,2};
31+
32+
CP __cp23 = CP(cp);
33+
int c1 = __cp23.x;
34+
int c2 = __cp23.y;
35+
36+
37+
printf("c1: %d c2: %d\n", c1, c2);
38+
++c1;
39+
++c2;
40+
printf("c1: %d c2: %d\n", c1, c2);
41+
42+
CP & __cp30 = cp;
43+
int c3 = __cp30.x;
44+
int c4 = __cp30.y;
45+
46+
47+
printf("c3: %d c4: %d\n", c3, c4);
48+
++c3;
49+
++c4;
50+
printf("c3: %d c4: %d\n", c3, c4);
51+
}
Lines changed: 61 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,61 @@
1-
.tmp.cpp:73:29: error: template argument ‘(long unsigned int)N’ involves template parameter(s)
2-
template<int N> struct std::tuple_element<N, constant::Q> { typedef int type; };
3-
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4-
.tmp.cpp:78:39: error: invalid use of incomplete type ‘struct std::tuple_element<0, constant::Q>’
5-
std::tuple_element<0, constant::Q>::type&& a = constant::get(constant::);
6-
^~~~
7-
.tmp.cpp:5:51: note: declaration of ‘struct std::tuple_element<0, constant::Q>’
8-
namespace std { template<size_t, typename> struct tuple_element;
9-
^~~~~~~~~~~~~
10-
.tmp.cpp:79:39: error: invalid use of incomplete type ‘struct std::tuple_element<1, constant::Q>’
11-
std::tuple_element<1, constant::Q>::type&& b = constant::get(constant::);
12-
^~~~
13-
.tmp.cpp:5:51: note: declaration of ‘struct std::tuple_element<1, constant::Q>’
14-
namespace std { template<size_t, typename> struct tuple_element;
15-
^~~~~~~~~~~~~
16-
.tmp.cpp:80:39: error: invalid use of incomplete type ‘struct std::tuple_element<2, constant::Q>’
17-
std::tuple_element<2, constant::Q>::type&& c = constant::get(constant::);
18-
^~~~
19-
.tmp.cpp:5:51: note: declaration of ‘struct std::tuple_element<2, constant::Q>’
20-
namespace std { template<size_t, typename> struct tuple_element;
21-
^~~~~~~~~~~~~
22-
.tmp.cpp: In function ‘constexpr bool constant::f()’:
23-
.tmp.cpp:85:5: error: incomplete type ‘std::tuple_element<0, constant::Q>’ used in nested name specifier
24-
std::tuple_element<0, constant::Q>::type&& a = constant::get(__q20);
25-
^~~
26-
.tmp.cpp:85:48: error: ‘a’ was not declared in this scope
27-
std::tuple_element<0, constant::Q>::type&& a = constant::get(__q20);
28-
^
29-
.tmp.cpp:85:71: error: no matching function for call to ‘get(constant::Q&)’
30-
std::tuple_element<0, constant::Q>::type&& a = constant::get(__q20);
31-
^
32-
.tmp.cpp:40:33: note: candidate: template<int N> constexpr int constant::get(constant::Q&&)
33-
template<int N> constexpr int get(Q &&) { return N * N; }
34-
^~~
35-
.tmp.cpp:40:33: note: template argument deduction/substitution failed:
36-
.tmp.cpp:85:71: note: couldn't deduce template parameter ‘N’
37-
std::tuple_element<0, constant::Q>::type&& a = constant::get(__q20);
38-
^
39-
.tmp.cpp:86:5: error: incomplete type ‘std::tuple_element<1, constant::Q>’ used in nested name specifier
40-
std::tuple_element<1, constant::Q>::type&& b = constant::get(__q20);
41-
^~~
42-
.tmp.cpp:86:48: error: ‘b’ was not declared in this scope
43-
std::tuple_element<1, constant::Q>::type&& b = constant::get(__q20);
44-
^
45-
.tmp.cpp:86:71: error: no matching function for call to ‘get(constant::Q&)’
46-
std::tuple_element<1, constant::Q>::type&& b = constant::get(__q20);
47-
^
48-
.tmp.cpp:40:33: note: candidate: template<int N> constexpr int constant::get(constant::Q&&)
49-
template<int N> constexpr int get(Q &&) { return N * N; }
50-
^~~
51-
.tmp.cpp:40:33: note: template argument deduction/substitution failed:
52-
.tmp.cpp:86:71: note: couldn't deduce template parameter ‘N’
53-
std::tuple_element<1, constant::Q>::type&& b = constant::get(__q20);
54-
^
55-
.tmp.cpp:87:5: error: incomplete type ‘std::tuple_element<2, constant::Q>’ used in nested name specifier
56-
std::tuple_element<2, constant::Q>::type&& c = constant::get(__q20);
57-
^~~
58-
.tmp.cpp:87:48: error: ‘c’ was not declared in this scope
59-
std::tuple_element<2, constant::Q>::type&& c = constant::get(__q20);
60-
^
61-
.tmp.cpp:87:71: error: no matching function for call to ‘get(constant::Q&)’
62-
std::tuple_element<2, constant::Q>::type&& c = constant::get(__q20);
63-
^
64-
.tmp.cpp:40:33: note: candidate: template<int N> constexpr int constant::get(constant::Q&&)
65-
template<int N> constexpr int get(Q &&) { return N * N; }
66-
^~~
67-
.tmp.cpp:40:33: note: template argument deduction/substitution failed:
68-
.tmp.cpp:87:71: note: couldn't deduce template parameter ‘N’
69-
std::tuple_element<2, constant::Q>::type&& c = constant::get(__q20);
70-
^
71-
.tmp.cpp: In function ‘constexpr int constant::g()’:
72-
.tmp.cpp:96:7: error: incomplete type ‘std::tuple_element<0, constant::Q>’ used in nested name specifier
73-
std::tuple_element<0, constant::Q>::type&& a = constant::get(__q27);
74-
^~~
75-
.tmp.cpp:96:50: error: ‘a’ was not declared in this scope
76-
std::tuple_element<0, constant::Q>::type&& a = constant::get(__q27);
77-
^
78-
.tmp.cpp:96:73: error: no matching function for call to ‘get(constant::Q&)’
79-
std::tuple_element<0, constant::Q>::type&& a = constant::get(__q27);
80-
^
81-
.tmp.cpp:40:33: note: candidate: template<int N> constexpr int constant::get(constant::Q&&)
82-
template<int N> constexpr int get(Q &&) { return N * N; }
83-
^~~
84-
.tmp.cpp:40:33: note: template argument deduction/substitution failed:
85-
.tmp.cpp:96:73: note: couldn't deduce template parameter ‘N’
86-
std::tuple_element<0, constant::Q>::type&& a = constant::get(__q27);
87-
^
88-
.tmp.cpp:97:7: error: incomplete type ‘std::tuple_element<1, constant::Q>’ used in nested name specifier
89-
std::tuple_element<1, constant::Q>::type&& b = constant::get(__q27);
90-
^~~
91-
.tmp.cpp:97:50: error: ‘b’ was not declared in this scope
92-
std::tuple_element<1, constant::Q>::type&& b = constant::get(__q27);
93-
^
94-
.tmp.cpp:97:73: error: no matching function for call to ‘get(constant::Q&)’
95-
std::tuple_element<1, constant::Q>::type&& b = constant::get(__q27);
96-
^
97-
.tmp.cpp:40:33: note: candidate: template<int N> constexpr int constant::get(constant::Q&&)
98-
template<int N> constexpr int get(Q &&) { return N * N; }
99-
^~~
100-
.tmp.cpp:40:33: note: template argument deduction/substitution failed:
101-
.tmp.cpp:97:73: note: couldn't deduce template parameter ‘N’
102-
std::tuple_element<1, constant::Q>::type&& b = constant::get(__q27);
103-
^
104-
.tmp.cpp:98:7: error: incomplete type ‘std::tuple_element<2, constant::Q>’ used in nested name specifier
105-
std::tuple_element<2, constant::Q>::type&& c = constant::get(__q27);
106-
^~~
107-
.tmp.cpp:98:50: error: ‘c’ was not declared in this scope
108-
std::tuple_element<2, constant::Q>::type&& c = constant::get(__q27);
109-
^
110-
.tmp.cpp:98:73: error: no matching function for call to ‘get(constant::Q&)’
111-
std::tuple_element<2, constant::Q>::type&& c = constant::get(__q27);
112-
^
113-
.tmp.cpp:40:33: note: candidate: template<int N> constexpr int constant::get(constant::Q&&)
114-
template<int N> constexpr int get(Q &&) { return N * N; }
115-
^~~
116-
.tmp.cpp:40:33: note: template argument deduction/substitution failed:
117-
.tmp.cpp:98:73: note: couldn't deduce template parameter ‘N’
118-
std::tuple_element<2, constant::Q>::type&& c = constant::get(__q27);
119-
^
1+
.tmp.cpp:78:48: error: no matching function for call to 'get'
2+
std::tuple_element<0, constant::Q>::type a = constant::get<0ul>(constant::__q17);
3+
^~~~~~~~~~~~~~~~~~
4+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
5+
template<int N> constexpr int get(Q &&) { return N * N; }
6+
^
7+
.tmp.cpp:79:48: error: no matching function for call to 'get'
8+
std::tuple_element<1, constant::Q>::type b = constant::get<1ul>(constant::__q17);
9+
^~~~~~~~~~~~~~~~~~
10+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
11+
template<int N> constexpr int get(Q &&) { return N * N; }
12+
^
13+
.tmp.cpp:80:48: error: no matching function for call to 'get'
14+
std::tuple_element<2, constant::Q>::type c = constant::get<2ul>(constant::__q17);
15+
^~~~~~~~~~~~~~~~~~
16+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
17+
template<int N> constexpr int get(Q &&) { return N * N; }
18+
^
19+
.tmp.cpp:85:50: error: no matching function for call to 'get'
20+
std::tuple_element<0, constant::Q>::type a = constant::get<0ul>(__q20);
21+
^~~~~~~~~~~~~~~~~~
22+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
23+
template<int N> constexpr int get(Q &&) { return N * N; }
24+
^
25+
.tmp.cpp:86:50: error: no matching function for call to 'get'
26+
std::tuple_element<1, constant::Q>::type b = constant::get<1ul>(__q20);
27+
^~~~~~~~~~~~~~~~~~
28+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
29+
template<int N> constexpr int get(Q &&) { return N * N; }
30+
^
31+
.tmp.cpp:87:50: error: no matching function for call to 'get'
32+
std::tuple_element<2, constant::Q>::type c = constant::get<2ul>(__q20);
33+
^~~~~~~~~~~~~~~~~~
34+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
35+
template<int N> constexpr int get(Q &&) { return N * N; }
36+
^
37+
.tmp.cpp:85:46: error: variables defined in a constexpr function must be initialized
38+
std::tuple_element<0, constant::Q>::type a = constant::get<0ul>(__q20);
39+
^
40+
.tmp.cpp:96:52: error: no matching function for call to 'get'
41+
std::tuple_element<0, constant::Q>::type a = constant::get<0ul>(__q27);
42+
^~~~~~~~~~~~~~~~~~
43+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
44+
template<int N> constexpr int get(Q &&) { return N * N; }
45+
^
46+
.tmp.cpp:97:52: error: no matching function for call to 'get'
47+
std::tuple_element<1, constant::Q>::type b = constant::get<1ul>(__q27);
48+
^~~~~~~~~~~~~~~~~~
49+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
50+
template<int N> constexpr int get(Q &&) { return N * N; }
51+
^
52+
.tmp.cpp:98:52: error: no matching function for call to 'get'
53+
std::tuple_element<2, constant::Q>::type c = constant::get<2ul>(__q27);
54+
^~~~~~~~~~~~~~~~~~
55+
.tmp.cpp:40:33: note: candidate function not viable: no known conversion from 'constant::Q' to 'constant::Q &&' for 1st argument
56+
template<int N> constexpr int get(Q &&) { return N * N; }
57+
^
58+
.tmp.cpp:96:48: error: variables defined in a constexpr function must be initialized
59+
std::tuple_element<0, constant::Q>::type a = constant::get<0ul>(__q27);
60+
^
61+
11 errors generated.

tests/StructuredBindingsHandler3Test.expect

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,16 @@ namespace constant {
7575
Q q;
7676
// This creates and lifetime-extends a temporary to hold the result of each get() call.
7777
constant::Q __q17 = constant::Q(constant::q);
78-
std::tuple_element<0, constant::Q>::type&& a = constant::get<0ul>(constant::__q17);
79-
std::tuple_element<1, constant::Q>::type&& b = constant::get<1ul>(constant::__q17);
80-
std::tuple_element<2, constant::Q>::type&& c = constant::get<2ul>(constant::__q17);
78+
std::tuple_element<0, constant::Q>::type a = constant::get<0ul>(constant::__q17);
79+
std::tuple_element<1, constant::Q>::type b = constant::get<1ul>(constant::__q17);
80+
std::tuple_element<2, constant::Q>::type c = constant::get<2ul>(constant::__q17);
8181
// expected-note {{temporary}}
8282

8383
constexpr bool f() {
8484
constant::Q __q20 = constant::Q(constant::q);
85-
std::tuple_element<0, constant::Q>::type&& a = constant::get<0ul>(__q20);
86-
std::tuple_element<1, constant::Q>::type&& b = constant::get<1ul>(__q20);
87-
std::tuple_element<2, constant::Q>::type&& c = constant::get<2ul>(__q20);
85+
std::tuple_element<0, constant::Q>::type a = constant::get<0ul>(__q20);
86+
std::tuple_element<1, constant::Q>::type b = constant::get<1ul>(__q20);
87+
std::tuple_element<2, constant::Q>::type c = constant::get<2ul>(__q20);
8888

8989
return a == 0 && b == 1 && c == 4;
9090
}
@@ -93,9 +93,9 @@ namespace constant {
9393
int *p = nullptr;
9494
{
9595
constant::Q __q27 = constant::Q(constant::q);
96-
std::tuple_element<0, constant::Q>::type&& a = constant::get<0ul>(__q27);
97-
std::tuple_element<1, constant::Q>::type&& b = constant::get<1ul>(__q27);
98-
std::tuple_element<2, constant::Q>::type&& c = constant::get<2ul>(__q27);
96+
std::tuple_element<0, constant::Q>::type a = constant::get<0ul>(__q27);
97+
std::tuple_element<1, constant::Q>::type b = constant::get<1ul>(__q27);
98+
std::tuple_element<2, constant::Q>::type c = constant::get<2ul>(__q27);
9999

100100
p = &c;
101101
}

tests/StructuredBindingsHandler5Test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ int main()
6464
auto& [x, y] = p;
6565

6666
printf("x:%lf y:%lf\n", p.GetX(), p.GetY());
67-
x++;
67+
++x;
68+
++y;
6869
printf("x:%lf y:%lf\n", x, y);
6970
printf("x:%lf y:%lf\n", p.GetX(), p.GetY());
7071

0 commit comments

Comments
 (0)