lxfind updated this revision to Diff 271801.
lxfind added a comment.
Herald added a subscriber: arphaman.
Address feedback and update failed tests
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D82029/new/
https://reviews.llvm.org/D82029
Files:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaCoroutine.cpp
clang/lib/Sema/SemaExceptionSpec.cpp
clang/test/AST/Inputs/std-coroutine.h
clang/test/AST/coroutine-source-location-crash.cpp
clang/test/Analysis/more-dtors-cfg-output.cpp
clang/test/CodeGenCXX/ubsan-coroutines.cpp
clang/test/CodeGenCoroutines/Inputs/coroutine.h
clang/test/CodeGenCoroutines/coro-alloc.cpp
clang/test/CodeGenCoroutines/coro-always-inline.cpp
clang/test/CodeGenCoroutines/coro-await-domination.cpp
clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
clang/test/CodeGenCoroutines/coro-await.cpp
clang/test/CodeGenCoroutines/coro-dest-slot.cpp
clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
clang/test/CodeGenCoroutines/coro-params.cpp
clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
clang/test/CodeGenCoroutines/coro-ret-void.cpp
clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
clang/test/CodeGenCoroutines/coro-return.cpp
clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
clang/test/Index/coroutines.cpp
clang/test/SemaCXX/Inputs/std-coroutine.h
clang/test/SemaCXX/co_await-range-for.cpp
clang/test/SemaCXX/coreturn-eh.cpp
clang/test/SemaCXX/coreturn.cpp
clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
clang/test/SemaCXX/coroutine-rvo.cpp
clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
clang/test/SemaCXX/coroutines.cpp
Index: clang/test/SemaCXX/coroutines.cpp
===================================================================
--- clang/test/SemaCXX/coroutines.cpp
+++ clang/test/SemaCXX/coroutines.cpp
@@ -52,21 +52,24 @@
};
struct awaitable {
- bool await_ready();
- template <typename F> void await_suspend(F);
- void await_resume();
+ bool await_ready() noexcept;
+ template <typename F>
+ void await_suspend(F) noexcept;
+ void await_resume() noexcept;
} a;
struct suspend_always {
- bool await_ready() { return false; }
- template <typename F> void await_suspend(F);
- void await_resume() {}
+ bool await_ready() noexcept { return false; }
+ template <typename F>
+ void await_suspend(F) noexcept;
+ void await_resume() noexcept {}
};
struct suspend_never {
- bool await_ready() { return true; }
- template <typename F> void await_suspend(F);
- void await_resume() {}
+ bool await_ready() noexcept { return true; }
+ template <typename F>
+ void await_suspend(F) noexcept;
+ void await_resume() noexcept {}
};
struct auto_await_suspend {
@@ -127,7 +130,7 @@
struct promise {
void get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
awaitable yield_value(int); // expected-note 2{{candidate}}
awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
not_awaitable yield_value(void()); // expected-note 2{{candidate}}
@@ -138,7 +141,7 @@
struct promise_void {
void get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
@@ -152,13 +155,13 @@
namespace experimental {
template <class PromiseType = void>
struct coroutine_handle {
- static coroutine_handle from_address(void *);
+ static coroutine_handle from_address(void *) noexcept;
};
template <>
struct coroutine_handle<void> {
template <class PromiseType>
- coroutine_handle(coroutine_handle<PromiseType>);
- static coroutine_handle from_address(void *);
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+ static coroutine_handle from_address(void *) noexcept;
};
}} // namespace std::experimental
@@ -402,7 +405,7 @@
namespace adl_ns {
struct coawait_arg_type {};
-awaitable operator co_await(coawait_arg_type);
+awaitable operator co_await(coawait_arg_type) noexcept;
}
namespace dependent_operator_co_await_lookup {
@@ -434,7 +437,7 @@
typedef transform_awaitable await_arg;
coro<transform_promise> get_return_object();
transformed initial_suspend();
- ::adl_ns::coawait_arg_type final_suspend();
+ ::adl_ns::coawait_arg_type final_suspend() noexcept;
transformed await_transform(transform_awaitable);
void unhandled_exception();
void return_void();
@@ -444,7 +447,7 @@
typedef AwaitArg await_arg;
coro<basic_promise> get_return_object();
awaitable initial_suspend();
- awaitable final_suspend();
+ awaitable final_suspend() noexcept;
void unhandled_exception();
void return_void();
};
@@ -529,7 +532,7 @@
void return_value(int());
suspend_never initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
void get_return_object();
void unhandled_exception();
};
@@ -563,7 +566,7 @@
struct bad_promise_1 {
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_void();
};
@@ -573,7 +576,7 @@
struct bad_promise_2 {
coro<bad_promise_2> get_return_object();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_void();
};
@@ -588,14 +591,14 @@
void unhandled_exception();
void return_void();
};
-coro<bad_promise_3> missing_final_suspend() { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}}
+coro<bad_promise_3> missing_final_suspend() noexcept { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}}
co_await a;
}
struct bad_promise_4 {
coro<bad_promise_4> get_return_object();
not_awaitable initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
};
// FIXME: This diagnostic is terrible.
@@ -607,7 +610,7 @@
struct bad_promise_5 {
coro<bad_promise_5> get_return_object();
suspend_always initial_suspend();
- not_awaitable final_suspend();
+ not_awaitable final_suspend() noexcept;
void return_void();
};
// FIXME: This diagnostic is terrible.
@@ -619,7 +622,7 @@
struct bad_promise_6 {
coro<bad_promise_6> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_void(); // expected-note 2 {{member 'return_void' first declared here}}
void return_value(int) const; // expected-note 2 {{member 'return_value' first declared here}}
@@ -638,7 +641,7 @@
struct bad_promise_7 { // expected-note 2 {{defined here}}
coro<bad_promise_7> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
};
coro<bad_promise_7> no_unhandled_exception() { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}}
@@ -658,7 +661,7 @@
struct bad_promise_8 : bad_promise_base {
coro<bad_promise_8> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception() __attribute__((unavailable)); // expected-note 2 {{marked unavailable here}}
void unhandled_exception() const;
void unhandled_exception(void *) const;
@@ -680,7 +683,7 @@
struct bad_promise_9 {
coro<bad_promise_9> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void await_transform(void *);
awaitable await_transform(int) __attribute__((unavailable)); // expected-note {{explicitly marked unavailable}}
void return_void();
@@ -693,7 +696,7 @@
struct bad_promise_10 {
coro<bad_promise_10> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
int await_transform;
void return_void();
void unhandled_exception();
@@ -712,7 +715,7 @@
struct good_promise_1 {
coro<good_promise_1> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
static const call_operator await_transform;
using Fn = void (*)();
@@ -750,7 +753,7 @@
struct good_promise_2 {
float get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
@@ -783,7 +786,7 @@
struct promise_type {
int get_return_object() {}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
int get_return_object_on_allocation_failure(); // expected-error{{'promise_type': 'get_return_object_on_allocation_failure()' must be a static member function}}
void unhandled_exception();
@@ -797,7 +800,7 @@
struct bad_promise_11 {
coro<bad_promise_11> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_void();
@@ -820,7 +823,7 @@
struct bad_promise_12 {
coro<bad_promise_12> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_void();
static coro<bad_promise_12> get_return_object_on_allocation_failure();
@@ -842,7 +845,7 @@
struct good_promise_13 {
coro<good_promise_13> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_void();
static coro<good_promise_13> get_return_object_on_allocation_failure();
@@ -860,7 +863,7 @@
struct good_promise_custom_new_operator {
coro<good_promise_custom_new_operator> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
void *operator new(SizeT, double, float, int);
@@ -876,7 +879,7 @@
struct good_promise_nonstatic_member_custom_new_operator {
coro<good_promise_nonstatic_member_custom_new_operator> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
void *operator new(SizeT, coroutine_nonstatic_member_struct &, double);
@@ -886,7 +889,7 @@
static coro<good_promise_noexcept_custom_new_operator> get_return_object_on_allocation_failure();
coro<good_promise_noexcept_custom_new_operator> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
void *operator new(SizeT, double, float, int) noexcept;
@@ -903,7 +906,7 @@
struct promise_type {
void get_return_object() {} //expected-note {{member 'get_return_object' declared here}}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception();
};
@@ -920,7 +923,7 @@
struct promise_type {
void *get_return_object() {} //expected-note {{member 'get_return_object' declared here}}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception();
};
@@ -938,7 +941,7 @@
int get_return_object() {}
static void get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared here}}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception();
};
@@ -957,7 +960,7 @@
int get_return_object() {}
static char *get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared}}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception();
};
@@ -971,7 +974,7 @@
struct bad_promise_no_return_func { // expected-note {{'bad_promise_no_return_func' defined here}}
coro<bad_promise_no_return_func> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
};
// FIXME: The PDTS currently specifies this as UB, technically forbidding a
@@ -1083,7 +1086,7 @@
CoroMemberTag get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
AwaitTestT yield_value(int);
@@ -1292,7 +1295,7 @@
bad_promise_deleted_constructor() = delete;
coro<bad_promise_deleted_constructor> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
@@ -1314,7 +1317,7 @@
good_promise_default_constructor() = default;
coro<good_promise_default_constructor> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
@@ -1332,7 +1335,7 @@
good_promise_custom_constructor() = delete;
coro<good_promise_custom_constructor> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
@@ -1359,7 +1362,7 @@
bad_promise_no_matching_constructor() = delete;
coro<bad_promise_no_matching_constructor> get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
@@ -1383,26 +1386,25 @@
class awaitable_no_unused_warn {
public:
using handle_type = std::experimental::coroutine_handle<>;
- constexpr bool await_ready() { return false; }
+ constexpr bool await_ready() noexcept { return false; }
void await_suspend(handle_type) noexcept {}
- int await_resume() { return 1; }
+ int await_resume() noexcept { return 1; }
};
class awaitable_unused_warn {
public:
using handle_type = std::experimental::coroutine_handle<>;
- constexpr bool await_ready() { return false; }
+ constexpr bool await_ready() noexcept { return false; }
void await_suspend(handle_type) noexcept {}
- [[nodiscard]]
- int await_resume() { return 1; }
+ [[nodiscard]] int await_resume() noexcept { return 1; }
};
template <class Await>
struct check_warning_promise {
coro<check_warning_promise> get_return_object();
Await initial_suspend();
- Await final_suspend();
+ Await final_suspend() noexcept;
Await yield_value(int);
void return_void();
void unhandled_exception();
Index: clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
===================================================================
--- clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
+++ clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
@@ -16,7 +16,7 @@
struct promise_type {
coro_t get_return_object() { return {}; }
suspend_never initial_suspend() { return {}; }
- suspend_never final_suspend() { return {}; }
+ suspend_never final_suspend() noexcept { return {}; }
A yield_value(int) { return {}; }
void return_void() {}
static void unhandled_exception() {}
Index: clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
===================================================================
--- clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
+++ clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
@@ -23,7 +23,7 @@
#endif
void get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
};
Index: clang/test/SemaCXX/coroutine-rvo.cpp
===================================================================
--- clang/test/SemaCXX/coroutine-rvo.cpp
+++ clang/test/SemaCXX/coroutine-rvo.cpp
@@ -49,7 +49,7 @@
struct task {
struct promise_type {
auto initial_suspend() { return suspend_never{}; }
- auto final_suspend() { return suspend_never{}; }
+ auto final_suspend() noexcept { return suspend_never{}; }
auto get_return_object() { return task{}; }
static void unhandled_exception() {}
void return_value(T&& value) {}
Index: clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
@@ -0,0 +1,62 @@
+// This file contains references to sections of the Coroutines TS, which can be
+// found at http://wg21.link/coroutines.
+
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result
+
+namespace std {
+namespace experimental {
+
+template <class Ret, typename... T>
+struct coroutine_traits { using promise_type = typename Ret::promise_type; };
+
+template <class Promise = void>
+struct coroutine_handle {
+ static coroutine_handle from_address(void *); // expected-note {{must be declared with 'noexcept'}}
+};
+template <>
+struct coroutine_handle<void> {
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>); // expected-note {{must be declared with 'noexcept'}}
+};
+
+struct suspend_never {
+ bool await_ready() { return true; } // expected-note {{must be declared with 'noexcept'}}
+ void await_suspend(coroutine_handle<>) {} // expected-note {{must be declared with 'noexcept'}}
+ void await_resume() {} // expected-note {{must be declared with 'noexcept'}}
+ ~suspend_never() noexcept(false); // expected-note {{must be declared with 'noexcept'}}
+};
+
+struct suspend_always {
+ bool await_ready() { return false; }
+ void await_suspend(coroutine_handle<>) {}
+ void await_resume() {}
+ suspend_never operator co_await(); // expected-note {{must be declared with 'noexcept'}}
+ ~suspend_always() noexcept(false); // expected-note {{must be declared with 'noexcept'}}
+};
+
+} // namespace experimental
+} // namespace std
+
+using namespace std::experimental;
+
+struct A {
+ bool await_ready();
+ void await_resume();
+ template <typename F>
+ void await_suspend(F);
+};
+
+struct coro_t {
+ struct promise_type {
+ coro_t get_return_object();
+ suspend_never initial_suspend();
+ suspend_always final_suspend(); // expected-note {{must be declared with 'noexcept'}}
+ void return_void();
+ static void unhandled_exception();
+ };
+};
+
+coro_t f(int n) { // expected-error {{all code generated by co_await __promise.final_suspend() must not throw}}
+ A a{};
+ co_await a;
+}
Index: clang/test/SemaCXX/coreturn.cpp
===================================================================
--- clang/test/SemaCXX/coreturn.cpp
+++ clang/test/SemaCXX/coreturn.cpp
@@ -13,7 +13,7 @@
struct promise_void {
void get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
@@ -21,7 +21,7 @@
struct promise_void_return_value {
void get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_value(int);
};
@@ -30,7 +30,7 @@
struct promise_type {
VoidTagNoReturn get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
};
};
@@ -39,7 +39,7 @@
struct promise_type {
VoidTagReturnValue get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_value(int);
};
@@ -49,7 +49,7 @@
struct promise_type {
VoidTagReturnVoid get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_void();
};
@@ -58,7 +58,7 @@
struct promise_float {
float get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
@@ -66,7 +66,7 @@
struct promise_int {
int get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_value(int);
void unhandled_exception();
};
Index: clang/test/SemaCXX/coreturn-eh.cpp
===================================================================
--- clang/test/SemaCXX/coreturn-eh.cpp
+++ clang/test/SemaCXX/coreturn-eh.cpp
@@ -17,7 +17,7 @@
struct promise_void_return_value {
void get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_value(object);
};
@@ -26,7 +26,7 @@
struct promise_type {
VoidTagReturnValue get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void unhandled_exception();
void return_value(object);
};
Index: clang/test/SemaCXX/co_await-range-for.cpp
===================================================================
--- clang/test/SemaCXX/co_await-range-for.cpp
+++ clang/test/SemaCXX/co_await-range-for.cpp
@@ -44,7 +44,7 @@
void return_void();
void unhandled_exception();
suspend_never initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
template <class T>
Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly deleted}}
};
@@ -62,7 +62,7 @@
void return_void();
void unhandled_exception();
suspend_never initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
template <class T>
Awaiter<T> await_transform(BeginTag<T>) = delete; // expected-note 1+ {{explicitly deleted}}
@@ -96,7 +96,7 @@
void return_void();
void unhandled_exception();
suspend_never initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
template <class T>
Awaiter<T> await_transform(BeginTag<T> e);
@@ -137,7 +137,7 @@
void return_void();
void unhandled_exception();
suspend_never initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
template <class T>
CoawaitTag<T, false> await_transform(BeginTag<T> e);
template <class T>
Index: clang/test/SemaCXX/Inputs/std-coroutine.h
===================================================================
--- clang/test/SemaCXX/Inputs/std-coroutine.h
+++ clang/test/SemaCXX/Inputs/std-coroutine.h
@@ -10,25 +10,25 @@
template <class Promise = void>
struct coroutine_handle {
- static coroutine_handle from_address(void *);
+ static coroutine_handle from_address(void *) noexcept;
};
template <>
struct coroutine_handle<void> {
template <class PromiseType>
- coroutine_handle(coroutine_handle<PromiseType>);
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
static coroutine_handle from_address(void *);
};
struct suspend_always {
- bool await_ready() { return false; }
- void await_suspend(coroutine_handle<>) {}
- void await_resume() {}
+ bool await_ready() noexcept { return false; }
+ void await_suspend(coroutine_handle<>) noexcept {}
+ void await_resume() noexcept {}
};
struct suspend_never {
- bool await_ready() { return true; }
- void await_suspend(coroutine_handle<>) {}
- void await_resume() {}
+ bool await_ready() noexcept { return true; }
+ void await_suspend(coroutine_handle<>) noexcept {}
+ void await_resume() noexcept {}
};
} // namespace experimental
Index: clang/test/Index/coroutines.cpp
===================================================================
--- clang/test/Index/coroutines.cpp
+++ clang/test/Index/coroutines.cpp
@@ -7,7 +7,7 @@
struct promise_void {
void get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
Index: clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
+++ clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
@@ -17,7 +17,7 @@
return {};
}
coro::suspend_never initial_suspend() { return {}; }
- coro::suspend_never final_suspend() { return {}; }
+ coro::suspend_never final_suspend() noexcept { return {}; }
void return_void(){}
void unhandled_exception() noexcept;
};
@@ -48,11 +48,9 @@
// CHECK: [[CATCHRETDEST]]:
// CHECK-NEXT: br label %[[TRYCONT:.+]]
// CHECK: [[TRYCONT]]:
-// CHECK-NEXT: br label %[[RESUMECONT:.+]]
-// CHECK: [[RESUMECONT]]:
// CHECK-NEXT: br label %[[COROFIN:.+]]
// CHECK: [[COROFIN]]:
-// CHECK-NEXT: invoke void @"?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"(
+// CHECK-NEXT: call void @"?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"(
// CHECK-LPAD: @_Z1fv(
// CHECK-LPAD: invoke void @_Z9may_throwv()
@@ -69,8 +67,6 @@
// CHECK-LPAD: [[CATCHRETDEST]]:
// CHECK-LPAD-NEXT: br label %[[TRYCONT:.+]]
// CHECK-LPAD: [[TRYCONT]]:
-// CHECK-LPAD: br label %[[RESUMECONT:.+]]
-// CHECK-LPAD: [[RESUMECONT]]:
-// CHECK-LPAD-NEXT: br label %[[COROFIN:.+]]
+// CHECK-LPAD: br label %[[COROFIN:.+]]
// CHECK-LPAD: [[COROFIN]]:
-// CHECK-LPAD-NEXT: invoke void @_ZN6coro_t12promise_type13final_suspendEv(
+// CHECK-LPAD-NEXT: call void @_ZN6coro_t12promise_type13final_suspendEv(
Index: clang/test/CodeGenCoroutines/coro-return.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-return.cpp
+++ clang/test/CodeGenCoroutines/coro-return.cpp
@@ -5,27 +5,27 @@
template <class Promise = void> struct coroutine_handle {
coroutine_handle() = default;
- static coroutine_handle from_address(void *) { return {}; }
+ static coroutine_handle from_address(void *) noexcept { return {}; }
};
template <> struct coroutine_handle<void> {
static coroutine_handle from_address(void *) { return {}; }
coroutine_handle() = default;
template <class PromiseType>
- coroutine_handle(coroutine_handle<PromiseType>) {}
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
};
}
struct suspend_always {
- bool await_ready();
- void await_suspend(std::experimental::coroutine_handle<>);
- void await_resume();
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
};
template <> struct std::experimental::coroutine_traits<void> {
struct promise_type {
void get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
};
};
@@ -44,7 +44,7 @@
struct promise_type {
int get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_value(int);
};
};
Index: clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
+++ clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
@@ -14,7 +14,7 @@
struct coroutine_handle<> {};
template <typename>
struct coroutine_handle : coroutine_handle<> {
- static coroutine_handle from_address(void *);
+ static coroutine_handle from_address(void *) noexcept;
};
struct e {
int await_ready();
@@ -29,13 +29,13 @@
struct f;
struct g {
struct h {
- int await_ready();
+ int await_ready() noexcept;
template <typename al>
- void await_suspend(std::experimental::coroutine_handle<al>);
- void await_resume();
+ void await_suspend(std::experimental::coroutine_handle<al>) noexcept;
+ void await_resume() noexcept;
};
std::experimental::e initial_suspend();
- h final_suspend();
+ h final_suspend() noexcept;
template <typename ag>
auto await_transform(ag) { return ah(ag()); }
};
Index: clang/test/CodeGenCoroutines/coro-ret-void.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-ret-void.cpp
+++ clang/test/CodeGenCoroutines/coro-ret-void.cpp
@@ -8,7 +8,7 @@
struct promise_type {
coro1 get_return_object();
coro::suspend_never initial_suspend();
- coro::suspend_never final_suspend();
+ coro::suspend_never final_suspend() noexcept;
void return_void();
};
};
@@ -39,7 +39,7 @@
struct promise_type {
coro2 get_return_object();
coro::suspend_never initial_suspend();
- coro::suspend_never final_suspend();
+ coro::suspend_never final_suspend() noexcept;
void return_value(int);
};
};
Index: clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
+++ clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
@@ -11,7 +11,7 @@
struct promise_type {
coro_t get_return_object();
coro::suspend_never initial_suspend();
- coro::suspend_never final_suspend();
+ coro::suspend_never final_suspend() noexcept;
void return_void();
promise_type();
~promise_type();
Index: clang/test/CodeGenCoroutines/coro-params.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-params.cpp
+++ clang/test/CodeGenCoroutines/coro-params.cpp
@@ -142,7 +142,7 @@
promise_type() = delete;
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
@@ -166,7 +166,7 @@
promise_type(some_class&, float);
method get_return_object();
suspend_always initial_suspend();
- suspend_always final_suspend();
+ suspend_always final_suspend() noexcept;
void return_void();
void unhandled_exception();
};
Index: clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
+++ clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
@@ -33,19 +33,19 @@
struct handle {};
struct awaitable {
- bool await_ready() { return true; }
- void await_suspend(handle) {}
- bool await_resume() { return true; }
+ bool await_ready() noexcept { return true; }
+ void await_suspend(handle) noexcept {}
+ bool await_resume() noexcept { return true; }
};
template <typename T> struct coroutine_handle {
- static handle from_address(void *address) { return {}; }
+ static handle from_address(void *address) noexcept { return {}; }
};
template <typename T = void> struct coroutine_traits {
struct promise_type {
awaitable initial_suspend() { return {}; }
- awaitable final_suspend() { return {}; }
+ awaitable final_suspend() noexcept { return {}; }
void return_void() {}
T get_return_object() { return T(); }
void unhandled_exception() {}
Index: clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
+++ clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
@@ -21,7 +21,7 @@
struct promise_type {
RetObject get_return_object();
suspend_always initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
void return_void();
static void unhandled_exception();
};
@@ -52,7 +52,7 @@
static RetObject get_return_object_on_allocation_failure();
RetObject get_return_object();
suspend_always initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
void return_void();
static void unhandled_exception();
};
Index: clang/test/CodeGenCoroutines/coro-dest-slot.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-dest-slot.cpp
+++ clang/test/CodeGenCoroutines/coro-dest-slot.cpp
@@ -8,7 +8,7 @@
struct promise_type {
coro get_return_object();
suspend_always initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
void return_void();
static void unhandled_exception();
};
Index: clang/test/CodeGenCoroutines/coro-await.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-await.cpp
+++ clang/test/CodeGenCoroutines/coro-await.cpp
@@ -17,7 +17,7 @@
template <typename Promise>
struct coroutine_handle : coroutine_handle<> {
- static coroutine_handle from_address(void *);
+ static coroutine_handle from_address(void *) noexcept;
};
}
@@ -29,9 +29,9 @@
void await_resume();
};
struct final_susp {
- bool await_ready();
- void await_suspend(std::experimental::coroutine_handle<>);
- void await_resume();
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
};
struct suspend_always {
@@ -46,7 +46,7 @@
struct promise_type {
void get_return_object();
init_susp initial_suspend();
- final_susp final_suspend();
+ final_susp final_suspend() noexcept;
void return_void();
};
};
@@ -119,7 +119,7 @@
struct promise_type {
void get_return_object();
init_susp initial_suspend();
- final_susp final_suspend();
+ final_susp final_suspend() noexcept;
void return_void();
suspend_maybe yield_value(int);
};
@@ -295,7 +295,7 @@
struct promise_type {
void get_return_object();
init_susp initial_suspend();
- final_susp final_suspend();
+ final_susp final_suspend() noexcept;
void return_void();
AwaitResumeReturnsLValue yield_value(int);
};
Index: clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
+++ clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
@@ -22,7 +22,7 @@
struct promise_type {
auto get_return_object() { return throwing_task{}; }
auto initial_suspend() { return throwing_awaitable{}; }
- auto final_suspend() { return coro::suspend_never{}; }
+ auto final_suspend() noexcept { return coro::suspend_never{}; }
void return_void() {}
void unhandled_exception() {}
};
@@ -76,7 +76,7 @@
// CHECK-NEXT: br label %[[COROFINAL]]
// CHECK: [[COROFINAL]]:
- // CHECK-NEXT: invoke void @_ZN13throwing_task12promise_type13final_suspendEv
+ // CHECK-NEXT: call void @_ZN13throwing_task12promise_type13final_suspendEv
co_return;
}
@@ -90,7 +90,7 @@
struct promise_type {
auto get_return_object() { return noexcept_task{}; }
auto initial_suspend() { return noexcept_awaitable{}; }
- auto final_suspend() { return coro::suspend_never{}; }
+ auto final_suspend() noexcept { return coro::suspend_never{}; }
void return_void() {}
void unhandled_exception() {}
};
Index: clang/test/CodeGenCoroutines/coro-await-domination.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-await-domination.cpp
+++ clang/test/CodeGenCoroutines/coro-await-domination.cpp
@@ -7,7 +7,7 @@
struct promise_type {
coro get_return_object();
suspend_never initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
void return_void();
static void unhandled_exception();
};
@@ -35,4 +35,3 @@
x = co_await A{};
consume(x);
}
-
Index: clang/test/CodeGenCoroutines/coro-always-inline.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-always-inline.cpp
+++ clang/test/CodeGenCoroutines/coro-always-inline.cpp
@@ -14,22 +14,22 @@
struct handle {};
struct awaitable {
- bool await_ready() { return true; }
+ bool await_ready() noexcept { return true; }
// CHECK-NOT: await_suspend
- inline void __attribute__((__always_inline__)) await_suspend(handle) {}
- bool await_resume() { return true; }
+ inline void __attribute__((__always_inline__)) await_suspend(handle) noexcept {}
+ bool await_resume() noexcept { return true; }
};
template <typename T>
struct coroutine_handle {
- static handle from_address(void *address) { return {}; }
+ static handle from_address(void *address) noexcept { return {}; }
};
template <typename T = void>
struct coroutine_traits {
struct promise_type {
awaitable initial_suspend() { return {}; }
- awaitable final_suspend() { return {}; }
+ awaitable final_suspend() noexcept { return {}; }
void return_void() {}
T get_return_object() { return T(); }
void unhandled_exception() {}
Index: clang/test/CodeGenCoroutines/coro-alloc.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-alloc.cpp
+++ clang/test/CodeGenCoroutines/coro-alloc.cpp
@@ -10,7 +10,7 @@
template <class Promise = void>
struct coroutine_handle {
coroutine_handle() = default;
- static coroutine_handle from_address(void *) { return {}; }
+ static coroutine_handle from_address(void *) noexcept { return {}; }
};
template <>
@@ -18,7 +18,7 @@
static coroutine_handle from_address(void *) { return {}; }
coroutine_handle() = default;
template <class PromiseType>
- coroutine_handle(coroutine_handle<PromiseType>) {}
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
};
} // end namespace experimental
@@ -36,9 +36,9 @@
struct suspend_always {
- bool await_ready() { return false; }
- void await_suspend(std::experimental::coroutine_handle<>) {}
- void await_resume() {}
+ bool await_ready() noexcept { return false; }
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept {}
+ void await_resume() noexcept {}
};
struct global_new_delete_tag {};
@@ -48,7 +48,7 @@
struct promise_type {
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
};
};
@@ -89,7 +89,7 @@
void *operator new(unsigned long);
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
};
};
@@ -115,7 +115,7 @@
int, float, double);
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
};
};
@@ -145,7 +145,7 @@
struct promise_type {
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
};
};
@@ -168,7 +168,7 @@
void operator delete(void*);
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
};
};
@@ -193,7 +193,7 @@
void operator delete(void*, unsigned long);
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
};
};
@@ -218,7 +218,7 @@
struct promise_type {
int get_return_object() { return 0; }
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
static int get_return_object_on_allocation_failure() { return -1; }
};
Index: clang/test/CodeGenCoroutines/Inputs/coroutine.h
===================================================================
--- clang/test/CodeGenCoroutines/Inputs/coroutine.h
+++ clang/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -72,9 +72,9 @@
void await_resume() {}
};
struct suspend_never {
- bool await_ready() { return true; }
- void await_suspend(coroutine_handle<>) {}
- void await_resume() {}
+ bool await_ready() noexcept { return true; }
+ void await_suspend(coroutine_handle<>) noexcept {}
+ void await_resume() noexcept {}
};
}}}
Index: clang/test/CodeGenCXX/ubsan-coroutines.cpp
===================================================================
--- clang/test/CodeGenCXX/ubsan-coroutines.cpp
+++ clang/test/CodeGenCXX/ubsan-coroutines.cpp
@@ -32,7 +32,7 @@
struct promise_type {
task get_return_object() { return task(); }
suspend_always initial_suspend() { return {}; }
- suspend_always final_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
Index: clang/test/Analysis/more-dtors-cfg-output.cpp
===================================================================
--- clang/test/Analysis/more-dtors-cfg-output.cpp
+++ clang/test/Analysis/more-dtors-cfg-output.cpp
@@ -278,16 +278,16 @@
namespace std::experimental {
template <typename Promise>
struct coroutine_handle {
- static coroutine_handle from_address(void *);
+ static coroutine_handle from_address(void *) noexcept;
};
}
struct TestPromise {
TestPromise initial_suspend();
- TestPromise final_suspend();
- bool await_ready();
- void await_suspend(const std::experimental::coroutine_handle<TestPromise> &);
- void await_resume();
+ TestPromise final_suspend() noexcept;
+ bool await_ready() noexcept;
+ void await_suspend(const std::experimental::coroutine_handle<TestPromise> &) noexcept;
+ void await_resume() noexcept;
Foo return_value(const Bar &);
Bar get_return_object();
void unhandled_exception();
Index: clang/test/AST/coroutine-source-location-crash.cpp
===================================================================
--- clang/test/AST/coroutine-source-location-crash.cpp
+++ clang/test/AST/coroutine-source-location-crash.cpp
@@ -15,7 +15,7 @@
struct promise_type {
coro_t get_return_object();
suspend_never initial_suspend();
- suspend_never final_suspend();
+ suspend_never final_suspend() noexcept;
void return_void();
static void unhandled_exception();
};
Index: clang/test/AST/Inputs/std-coroutine.h
===================================================================
--- clang/test/AST/Inputs/std-coroutine.h
+++ clang/test/AST/Inputs/std-coroutine.h
@@ -10,12 +10,12 @@
template <class Promise = void>
struct coroutine_handle {
- static coroutine_handle from_address(void *);
+ static coroutine_handle from_address(void *) noexcept;
};
template <>
struct coroutine_handle<void> {
template <class PromiseType>
- coroutine_handle(coroutine_handle<PromiseType>);
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
static coroutine_handle from_address(void *);
};
@@ -26,9 +26,9 @@
};
struct suspend_never {
- bool await_ready() { return true; }
- void await_suspend(coroutine_handle<>) {}
- void await_resume() {}
+ bool await_ready() noexcept { return true; }
+ void await_suspend(coroutine_handle<>) noexcept {}
+ void await_resume() noexcept {}
};
} // namespace experimental
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -999,10 +999,8 @@
return R;
}
-/// Determine whether the callee of a particular function call can throw.
-/// E and D are both optional, but at least one of E and Loc must be specified.
-static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
- SourceLocation Loc = SourceLocation()) {
+CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+ SourceLocation Loc) {
// As an extension, we assume that __attribute__((nothrow)) functions don't
// throw.
if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
@@ -1048,7 +1046,8 @@
if (!FT)
return CT_Can;
- FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
+ if (Loc.isValid() || (Loc.isInvalid() && E))
+ FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
if (!FT)
return CT_Can;
@@ -1069,7 +1068,7 @@
VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
if (auto *Dtor = RD->getDestructor()) {
CT = mergeCanThrow(
- CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
+ CT, Sema::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
}
}
}
Index: clang/lib/Sema/SemaCoroutine.cpp
===================================================================
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -24,6 +24,7 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/SmallSet.h"
using namespace clang;
using namespace sema;
@@ -604,6 +605,66 @@
return ScopeInfo;
}
+/// Recursively check \p E and all its children to see if any call target
+/// (including constructor call) is declared noexcept. Also any value returned
+/// from the call has a noexcept destructor.
+static void checkNoThrow(Sema &S, const Stmt *E,
+ llvm::SmallPtrSetImpl<const Decl *> &ThrowingDecls) {
+ auto checkDeclNoexcept = [&](const Decl *D, bool IsDtor = false) {
+ // In the case of dtor, the call to dtor is implicit and hence we should
+ // pass nullptr to canCalleeThrow.
+ if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E), D)) {
+ if (ThrowingDecls.empty()) {
+ // First time seeing an error, emit the error message.
+ S.Diag(cast<FunctionDecl>(S.CurContext)->getLocation(),
+ diag::err_coroutine_promise_final_suspend_requires_nothrow);
+ }
+ ThrowingDecls.insert(D);
+ }
+ };
+ auto SC = E->getStmtClass();
+ if (SC == Expr::CXXConstructExprClass) {
+ auto const *Ctor = cast<CXXConstructExpr>(E)->getConstructor();
+ checkDeclNoexcept(Ctor);
+ // Check the corresponding destructor of the constructor.
+ checkDeclNoexcept(Ctor->getParent()->getDestructor(), true);
+ } else if (SC == Expr::CallExprClass || SC == Expr::CXXMemberCallExprClass ||
+ SC == Expr::CXXOperatorCallExprClass) {
+ if (!cast<CallExpr>(E)->isTypeDependent()) {
+ // FIXME: Handle dependent types.
+ checkDeclNoexcept(cast<CallExpr>(E)->getCalleeDecl());
+ auto ReturnType = cast<CallExpr>(E)->getCallReturnType(S.getASTContext());
+ // Check the destructor of the call return type, if any.
+ if (ReturnType.isDestructedType() ==
+ QualType::DestructionKind::DK_cxx_destructor) {
+ const auto *T =
+ cast<RecordType>(ReturnType.getCanonicalType().getTypePtr());
+ checkDeclNoexcept(
+ dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(), true);
+ }
+ }
+ }
+ for (const auto *Child : E->children()) {
+ if (!Child)
+ continue;
+ checkNoThrow(S, Child, ThrowingDecls);
+ }
+}
+
+/// Check that the expression co_await promise.final_suspend() shall not be
+/// potentially-throwing.
+static bool checkNoThrow(Sema &S, const Stmt *FinalSuspend) {
+ llvm::SmallPtrSet<const Decl *, 4> ThrowingDecls;
+ // We first collect all declarations that should not throw but not declared
+ // with noexcept. This is to avoid emitting the same note multiple times
+ // on the same declaration.
+ checkNoThrow(S, FinalSuspend, ThrowingDecls);
+ for (const auto *D : ThrowingDecls) {
+ S.Diag(D->getEndLoc(), diag::note_coroutine_function_declare_noexcept);
+ }
+ return ThrowingDecls.empty();
+}
+
bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
StringRef Keyword) {
if (!checkCoroutineContext(*this, KWLoc, Keyword))
@@ -646,7 +707,7 @@
return true;
StmtResult FinalSuspend = buildSuspends("final_suspend");
- if (FinalSuspend.isInvalid())
+ if (FinalSuspend.isInvalid() || !checkNoThrow(*this, FinalSuspend.get()))
return true;
ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1697,6 +1697,11 @@
static QualType GetTypeFromParser(ParsedType Ty,
TypeSourceInfo **TInfo = nullptr);
CanThrowResult canThrow(const Stmt *E);
+ /// Determine whether the callee of a particular function call can throw.
+ /// E and D are both optional, but at least one of E and Loc must be
+ /// specified.
+ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+ SourceLocation Loc = SourceLocation());
const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
const FunctionProtoType *FPT);
void UpdateExceptionSpec(FunctionDecl *FD,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10517,7 +10517,13 @@
def note_await_ready_no_bool_conversion : Note<
"return type of 'await_ready' is required to be contextually convertible to 'bool'"
>;
-}
+def err_coroutine_promise_final_suspend_requires_nothrow : Error<
+ "all code generated by co_await __promise.final_suspend() must not throw"
+>;
+def note_coroutine_function_declare_noexcept : Note<
+ "must be declared with 'noexcept'"
+>;
+} // end of coroutines issue category
let CategoryName = "Documentation Issue" in {
def warn_not_a_doxygen_trailing_member_comment : Warning<
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits