Value category of conditional operator
Consider the following code:
int x;
int& f() {
return x ? x : throw 0;
}
With gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
I get the following compilation error:
cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
Note that this compiles just fine in clang. Here is (what I believe to be) the relevant statement from the standard:
N4659 [8.16.2.1] (Conditional Operator):
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression (8.17); the result is of the type and value category of the other.
As far as I understand, x
is an lvalue, so it seems to me that clang
is right. Am I wrong?
If I had to take a guess, the l-to-rvalue conversion is occurring because the two expressions in the conditional don't have the same type, but because the second is a throw this conversion should be preempted. I'm not familiar with submitting bug reports, but perhaps that would be a better forum for this.
Here are some (probably) more helpful questions about the conditional operator:
Why does this function return an lvalue reference given rvalue arguments?
Error: lvalue required in this simple C code? (Ternary with assignment?)
c++ g++ language-lawyer conditional-operator value-categories
add a comment |
Consider the following code:
int x;
int& f() {
return x ? x : throw 0;
}
With gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
I get the following compilation error:
cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
Note that this compiles just fine in clang. Here is (what I believe to be) the relevant statement from the standard:
N4659 [8.16.2.1] (Conditional Operator):
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression (8.17); the result is of the type and value category of the other.
As far as I understand, x
is an lvalue, so it seems to me that clang
is right. Am I wrong?
If I had to take a guess, the l-to-rvalue conversion is occurring because the two expressions in the conditional don't have the same type, but because the second is a throw this conversion should be preempted. I'm not familiar with submitting bug reports, but perhaps that would be a better forum for this.
Here are some (probably) more helpful questions about the conditional operator:
Why does this function return an lvalue reference given rvalue arguments?
Error: lvalue required in this simple C code? (Ternary with assignment?)
c++ g++ language-lawyer conditional-operator value-categories
It is clearly a bug in g++, the change mentioned by Shafik appears in the standard since C+14
– M.M
Nov 16 '18 at 3:47
add a comment |
Consider the following code:
int x;
int& f() {
return x ? x : throw 0;
}
With gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
I get the following compilation error:
cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
Note that this compiles just fine in clang. Here is (what I believe to be) the relevant statement from the standard:
N4659 [8.16.2.1] (Conditional Operator):
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression (8.17); the result is of the type and value category of the other.
As far as I understand, x
is an lvalue, so it seems to me that clang
is right. Am I wrong?
If I had to take a guess, the l-to-rvalue conversion is occurring because the two expressions in the conditional don't have the same type, but because the second is a throw this conversion should be preempted. I'm not familiar with submitting bug reports, but perhaps that would be a better forum for this.
Here are some (probably) more helpful questions about the conditional operator:
Why does this function return an lvalue reference given rvalue arguments?
Error: lvalue required in this simple C code? (Ternary with assignment?)
c++ g++ language-lawyer conditional-operator value-categories
Consider the following code:
int x;
int& f() {
return x ? x : throw 0;
}
With gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
I get the following compilation error:
cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
Note that this compiles just fine in clang. Here is (what I believe to be) the relevant statement from the standard:
N4659 [8.16.2.1] (Conditional Operator):
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression (8.17); the result is of the type and value category of the other.
As far as I understand, x
is an lvalue, so it seems to me that clang
is right. Am I wrong?
If I had to take a guess, the l-to-rvalue conversion is occurring because the two expressions in the conditional don't have the same type, but because the second is a throw this conversion should be preempted. I'm not familiar with submitting bug reports, but perhaps that would be a better forum for this.
Here are some (probably) more helpful questions about the conditional operator:
Why does this function return an lvalue reference given rvalue arguments?
Error: lvalue required in this simple C code? (Ternary with assignment?)
c++ g++ language-lawyer conditional-operator value-categories
c++ g++ language-lawyer conditional-operator value-categories
edited Nov 16 '18 at 1:00
Shafik Yaghmour
127k23327545
127k23327545
asked Nov 15 '18 at 21:52
Nathan ChappellNathan Chappell
1278
1278
It is clearly a bug in g++, the change mentioned by Shafik appears in the standard since C+14
– M.M
Nov 16 '18 at 3:47
add a comment |
It is clearly a bug in g++, the change mentioned by Shafik appears in the standard since C+14
– M.M
Nov 16 '18 at 3:47
It is clearly a bug in g++, the change mentioned by Shafik appears in the standard since C+14
– M.M
Nov 16 '18 at 3:47
It is clearly a bug in g++, the change mentioned by Shafik appears in the standard since C+14
– M.M
Nov 16 '18 at 3:47
add a comment |
1 Answer
1
active
oldest
votes
clang is correct here, the old behavior was to unconditionally convert the value to a prvalue which it looks like gcc still implements.
This was the subject of DR 1560 which was fixed by the resolution of DR 1550. DR 1560 says:
A glvalue appearing as one operand of a conditional-expression in
which the other operand is a throw-expression is converted to a
prvalue, regardless of how the conditional-expression is used:
If either the second or the third operand has type void, then the lvalue-to-rvalue (7.1 [conv.lval]), array-to-pointer (7.2
[conv.array]), and function-to-pointer (7.3 [conv.func]) standard
conversions are performed on the second and third operands, and one of
the following shall hold:
- The second or the third operand (but not both) is a throw-expression (18.1 [except.throw]); the result is of the type of
the other and is a prvalue.
This seems to be gratuitous and surprising.
and DR 1550
changed the wording in [expr.cond] to what we have now:
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression; the result is of the type and value category of the other. The conditional-expression is a bit-field if that operand is a bit-field.
So it looks like gcc is implementing the old behavior while clang is implementing the DR.
This is the patch that applied DR 1560 to clang. It added the following test:
namespace DR1560 { // dr1560: 3.5
void f(bool b, int n) {
(b ? throw 0 : n) = (b ? n : throw 0) = 0;
}
class X { X(const X&); };
const X &get();
const X &x = true ? get() : throw 0;
}
which on godbolt we can see this fails for gcc due to:
error: lvalue required as left operand of assignment
4 | (b ? throw 0 : n) = (b ? n : throw 0) = 0;
|
We have a gcc bug report for a very similar issue which has the following reduced test case:
I wanted to bump this bug and supply a simpler test-case:
void blah(int&) {}
int main() {
int i{};
blah(true ? i : throw);
}
result with gcc 6.0:
prog.cc: In function 'int main()':
prog.cc:6:15: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
blah(true ? i : throw 0);
~~~~~^~~~~~~~~~~~~
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53328407%2fvalue-category-of-conditional-operator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
clang is correct here, the old behavior was to unconditionally convert the value to a prvalue which it looks like gcc still implements.
This was the subject of DR 1560 which was fixed by the resolution of DR 1550. DR 1560 says:
A glvalue appearing as one operand of a conditional-expression in
which the other operand is a throw-expression is converted to a
prvalue, regardless of how the conditional-expression is used:
If either the second or the third operand has type void, then the lvalue-to-rvalue (7.1 [conv.lval]), array-to-pointer (7.2
[conv.array]), and function-to-pointer (7.3 [conv.func]) standard
conversions are performed on the second and third operands, and one of
the following shall hold:
- The second or the third operand (but not both) is a throw-expression (18.1 [except.throw]); the result is of the type of
the other and is a prvalue.
This seems to be gratuitous and surprising.
and DR 1550
changed the wording in [expr.cond] to what we have now:
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression; the result is of the type and value category of the other. The conditional-expression is a bit-field if that operand is a bit-field.
So it looks like gcc is implementing the old behavior while clang is implementing the DR.
This is the patch that applied DR 1560 to clang. It added the following test:
namespace DR1560 { // dr1560: 3.5
void f(bool b, int n) {
(b ? throw 0 : n) = (b ? n : throw 0) = 0;
}
class X { X(const X&); };
const X &get();
const X &x = true ? get() : throw 0;
}
which on godbolt we can see this fails for gcc due to:
error: lvalue required as left operand of assignment
4 | (b ? throw 0 : n) = (b ? n : throw 0) = 0;
|
We have a gcc bug report for a very similar issue which has the following reduced test case:
I wanted to bump this bug and supply a simpler test-case:
void blah(int&) {}
int main() {
int i{};
blah(true ? i : throw);
}
result with gcc 6.0:
prog.cc: In function 'int main()':
prog.cc:6:15: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
blah(true ? i : throw 0);
~~~~~^~~~~~~~~~~~~
add a comment |
clang is correct here, the old behavior was to unconditionally convert the value to a prvalue which it looks like gcc still implements.
This was the subject of DR 1560 which was fixed by the resolution of DR 1550. DR 1560 says:
A glvalue appearing as one operand of a conditional-expression in
which the other operand is a throw-expression is converted to a
prvalue, regardless of how the conditional-expression is used:
If either the second or the third operand has type void, then the lvalue-to-rvalue (7.1 [conv.lval]), array-to-pointer (7.2
[conv.array]), and function-to-pointer (7.3 [conv.func]) standard
conversions are performed on the second and third operands, and one of
the following shall hold:
- The second or the third operand (but not both) is a throw-expression (18.1 [except.throw]); the result is of the type of
the other and is a prvalue.
This seems to be gratuitous and surprising.
and DR 1550
changed the wording in [expr.cond] to what we have now:
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression; the result is of the type and value category of the other. The conditional-expression is a bit-field if that operand is a bit-field.
So it looks like gcc is implementing the old behavior while clang is implementing the DR.
This is the patch that applied DR 1560 to clang. It added the following test:
namespace DR1560 { // dr1560: 3.5
void f(bool b, int n) {
(b ? throw 0 : n) = (b ? n : throw 0) = 0;
}
class X { X(const X&); };
const X &get();
const X &x = true ? get() : throw 0;
}
which on godbolt we can see this fails for gcc due to:
error: lvalue required as left operand of assignment
4 | (b ? throw 0 : n) = (b ? n : throw 0) = 0;
|
We have a gcc bug report for a very similar issue which has the following reduced test case:
I wanted to bump this bug and supply a simpler test-case:
void blah(int&) {}
int main() {
int i{};
blah(true ? i : throw);
}
result with gcc 6.0:
prog.cc: In function 'int main()':
prog.cc:6:15: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
blah(true ? i : throw 0);
~~~~~^~~~~~~~~~~~~
add a comment |
clang is correct here, the old behavior was to unconditionally convert the value to a prvalue which it looks like gcc still implements.
This was the subject of DR 1560 which was fixed by the resolution of DR 1550. DR 1560 says:
A glvalue appearing as one operand of a conditional-expression in
which the other operand is a throw-expression is converted to a
prvalue, regardless of how the conditional-expression is used:
If either the second or the third operand has type void, then the lvalue-to-rvalue (7.1 [conv.lval]), array-to-pointer (7.2
[conv.array]), and function-to-pointer (7.3 [conv.func]) standard
conversions are performed on the second and third operands, and one of
the following shall hold:
- The second or the third operand (but not both) is a throw-expression (18.1 [except.throw]); the result is of the type of
the other and is a prvalue.
This seems to be gratuitous and surprising.
and DR 1550
changed the wording in [expr.cond] to what we have now:
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression; the result is of the type and value category of the other. The conditional-expression is a bit-field if that operand is a bit-field.
So it looks like gcc is implementing the old behavior while clang is implementing the DR.
This is the patch that applied DR 1560 to clang. It added the following test:
namespace DR1560 { // dr1560: 3.5
void f(bool b, int n) {
(b ? throw 0 : n) = (b ? n : throw 0) = 0;
}
class X { X(const X&); };
const X &get();
const X &x = true ? get() : throw 0;
}
which on godbolt we can see this fails for gcc due to:
error: lvalue required as left operand of assignment
4 | (b ? throw 0 : n) = (b ? n : throw 0) = 0;
|
We have a gcc bug report for a very similar issue which has the following reduced test case:
I wanted to bump this bug and supply a simpler test-case:
void blah(int&) {}
int main() {
int i{};
blah(true ? i : throw);
}
result with gcc 6.0:
prog.cc: In function 'int main()':
prog.cc:6:15: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
blah(true ? i : throw 0);
~~~~~^~~~~~~~~~~~~
clang is correct here, the old behavior was to unconditionally convert the value to a prvalue which it looks like gcc still implements.
This was the subject of DR 1560 which was fixed by the resolution of DR 1550. DR 1560 says:
A glvalue appearing as one operand of a conditional-expression in
which the other operand is a throw-expression is converted to a
prvalue, regardless of how the conditional-expression is used:
If either the second or the third operand has type void, then the lvalue-to-rvalue (7.1 [conv.lval]), array-to-pointer (7.2
[conv.array]), and function-to-pointer (7.3 [conv.func]) standard
conversions are performed on the second and third operands, and one of
the following shall hold:
- The second or the third operand (but not both) is a throw-expression (18.1 [except.throw]); the result is of the type of
the other and is a prvalue.
This seems to be gratuitous and surprising.
and DR 1550
changed the wording in [expr.cond] to what we have now:
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression; the result is of the type and value category of the other. The conditional-expression is a bit-field if that operand is a bit-field.
So it looks like gcc is implementing the old behavior while clang is implementing the DR.
This is the patch that applied DR 1560 to clang. It added the following test:
namespace DR1560 { // dr1560: 3.5
void f(bool b, int n) {
(b ? throw 0 : n) = (b ? n : throw 0) = 0;
}
class X { X(const X&); };
const X &get();
const X &x = true ? get() : throw 0;
}
which on godbolt we can see this fails for gcc due to:
error: lvalue required as left operand of assignment
4 | (b ? throw 0 : n) = (b ? n : throw 0) = 0;
|
We have a gcc bug report for a very similar issue which has the following reduced test case:
I wanted to bump this bug and supply a simpler test-case:
void blah(int&) {}
int main() {
int i{};
blah(true ? i : throw);
}
result with gcc 6.0:
prog.cc: In function 'int main()':
prog.cc:6:15: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
blah(true ? i : throw 0);
~~~~~^~~~~~~~~~~~~
edited Dec 30 '18 at 2:58
answered Nov 15 '18 at 21:59
Shafik YaghmourShafik Yaghmour
127k23327545
127k23327545
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53328407%2fvalue-category-of-conditional-operator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
It is clearly a bug in g++, the change mentioned by Shafik appears in the standard since C+14
– M.M
Nov 16 '18 at 3:47