-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
c++: implicit move with throw [PR113853]
Here we have template<class T> auto is_throwable(T t) -> decltype(throw t, true) { ... } where we didn't properly mark 't' as IMPLICIT_RVALUE_P, which caused the wrong overload to have been chosen. Jason figured out it's because we don't correctly implement [expr.prim.id.unqual]#4.2, which post-P2266 says that an id-expression is move-eligible if "the id-expression (possibly parenthesized) is the operand of a throw-expression, and names an implicitly movable entity that belongs to a scope that does not contain the compound-statement of the innermost lambda-expression, try-block, or function-try-block (if any) whose compound-statement or ctor-initializer contains the throw-expression." I worked out that it's trying to say that given struct X { X(); X(const X&); X(X&&) = delete; }; the following should fail: the scope of the throw is an sk_try, and it's also x's scope S, and S "does not contain the compound-statement of the *try-block" so x is move-eligible, so we move, so we fail. void f () try { X x; throw x; // use of deleted function } catch (...) { } Whereas here: void g (X x) try { throw x; } catch (...) { } the throw is again in an sk_try, but x's scope is an sk_function_parms which *does* contain the {} of the *try-block, so x is not move-eligible, so we don't move, so we use X(const X&), and the code is fine. The current code also doesn't seem to handle void h (X x) { void z (decltype(throw x, true)); } where there's no enclosing lambda or sk_try so we should move. I'm not doing anything about lambdas because we shouldn't reach the code at the end of the function: the DECL_HAS_VALUE_EXPR_P check shouldn't let us go further. PR c++/113789 PR c++/113853 gcc/cp/ChangeLog: * typeck.cc (treat_lvalue_as_rvalue_p): Update code to better reflect [expr.prim.id.unqual]#4.2. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/sfinae69.C: Remove dg-bogus. * g++.dg/cpp0x/sfinae70.C: New test. * g++.dg/cpp0x/sfinae71.C: New test. * g++.dg/cpp0x/sfinae72.C: New test. * g++.dg/cpp2a/implicit-move4.C: New test.
- Loading branch information
Showing
6 changed files
with
152 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// PR c++/113789 | ||
// { dg-do compile { target c++11 } } | ||
|
||
struct AutoPtr { | ||
AutoPtr() = default; | ||
AutoPtr(AutoPtr&) {} | ||
}; | ||
|
||
template<class T> auto f(T p, int) -> decltype(throw p, 1) = delete; | ||
template<class T> void f(T p, long); | ||
|
||
void | ||
g () | ||
{ | ||
f (AutoPtr (), 42); // { dg-error "use of deleted function" "" { target c++20_down } } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// PR c++/113789 | ||
// { dg-do compile { target c++11 } } | ||
// Like sfinae70.C but T&&. | ||
|
||
struct AutoPtr { | ||
AutoPtr() = default; | ||
AutoPtr(AutoPtr&) {} | ||
}; | ||
|
||
template<class T> auto f(T&& p, int) -> decltype(throw p, 1) = delete; | ||
template<class T> void f(T p, long); | ||
|
||
void | ||
g () | ||
{ | ||
f (AutoPtr (), 42); // { dg-error "use of deleted function" "" { target c++20_down } } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// PR c++/113789 | ||
// { dg-do compile { target c++11 } } | ||
// Like sfinae70.C but (). | ||
|
||
struct AutoPtr { | ||
AutoPtr() = default; | ||
AutoPtr(AutoPtr&) {} | ||
}; | ||
|
||
template<class T> auto f(T p, int) -> decltype(throw (p), 1) = delete; | ||
template<class T> void f(T p, long); | ||
|
||
void | ||
g () | ||
{ | ||
f (AutoPtr (), 42); // { dg-error "use of deleted function" "" { target c++20_down } } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// PR c++/113853 | ||
// { dg-do compile { target c++20 } } | ||
|
||
struct X { | ||
X(); | ||
X(const X&); | ||
X(X&&) = delete; | ||
}; | ||
|
||
void | ||
f1 () | ||
{ | ||
try { | ||
; | ||
} catch (X x) { | ||
throw x; // { dg-error "use of deleted function" } | ||
} | ||
} | ||
|
||
void | ||
f2 (X x) | ||
try { | ||
; | ||
} catch (...) { | ||
throw x; // { dg-error "use of deleted function" } | ||
} | ||
|
||
void | ||
f2b (X x) | ||
try { | ||
; | ||
} catch (...) { | ||
{ | ||
throw x; // { dg-error "use of deleted function" } | ||
} | ||
} | ||
|
||
void | ||
f3 () | ||
try { | ||
X x; | ||
throw x; // { dg-error "use of deleted function" } | ||
} catch (...) { | ||
} | ||
|
||
void | ||
f3b () | ||
try { | ||
{ | ||
X x; | ||
throw x; // { dg-error "use of deleted function" } | ||
} | ||
} catch (...) { | ||
} | ||
|
||
void | ||
f4 (X x) | ||
try { | ||
throw x; | ||
} catch (...) { | ||
} | ||
|
||
void | ||
f4b (X x) | ||
try { | ||
{ | ||
throw x; | ||
} | ||
} catch (...) { | ||
} | ||
|
||
void | ||
f5 (X x) | ||
{ | ||
void g (decltype(throw x, true)); // { dg-error "use of deleted function|expected" } | ||
} | ||
|
||
// The "expected" shouldn't be here, c++/113924. | ||
void | ||
f6 (X x, int = decltype(throw x, true){}) // { dg-error "use of deleted function|expected" } | ||
{ | ||
} | ||
|
||
void | ||
f7 (X x) | ||
{ | ||
[&] { throw x; }; | ||
} |