diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 85d373845c818..68e0da72550e2 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -56,7 +56,9 @@ def CoroutineMissingUnhandledException : DiagGroup<"coroutine-missing-unhandled-exception">; def DeprecatedExperimentalCoroutine : DiagGroup<"deprecated-experimental-coroutine">; -def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, DeprecatedExperimentalCoroutine]>; +def DeprecatedCoroutine : + DiagGroup<"deprecated-coroutine", [DeprecatedExperimentalCoroutine]>; +def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, DeprecatedCoroutine]>; def ObjCBoolConstantConversion : DiagGroup<"objc-bool-constant-conversion">; def ConstantConversion : DiagGroup<"constant-conversion", [BitFieldConstantConversion, diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 1bc2e8b0c7ef5..92e877074ad3d 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1548,6 +1548,9 @@ def note_meant_to_use_typename : Note< let CategoryName = "Coroutines Issue" in { def err_for_co_await_not_range_for : Error< "'co_await' modifier can only be applied to range-based for loop">; +def warn_deprecated_for_co_await : Warning< + "'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated">, + InGroup; } let CategoryName = "Concepts Issue" in { diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index bb8718671bb0e..292ab03e8614f 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -2108,6 +2108,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { CoawaitLoc = SourceLocation(); } + if (CoawaitLoc.isValid() && getLangOpts().CPlusPlus20) + Diag(CoawaitLoc, diag::warn_deprecated_for_co_await); + // We need to perform most of the semantic analysis for a C++0x for-range // statememt before parsing the body, in order to be able to deduce the type // of an auto-typed loop variable. diff --git a/clang/test/SemaCXX/co_await-range-for.cpp b/clang/test/SemaCXX/co_await-range-for.cpp index e43f55a3434d1..a3feffab4bb27 100644 --- a/clang/test/SemaCXX/co_await-range-for.cpp +++ b/clang/test/SemaCXX/co_await-range-for.cpp @@ -50,7 +50,7 @@ struct MyForLoopArrayAwaiter { }; MyForLoopArrayAwaiter g() { int arr[10] = {0}; - for co_await(auto i : arr) {} + for co_await(auto i : arr) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}} // expected-error@-1 {{call to deleted member function 'await_transform'}} // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}} } @@ -72,14 +72,14 @@ struct ForLoopAwaiterBadBeginTransform { }; ForLoopAwaiterBadBeginTransform bad_begin() { Range R; - for co_await(auto i : R) {} + for co_await(auto i : R) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}} // expected-error@-1 {{call to deleted member function 'await_transform'}} // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}} } template ForLoopAwaiterBadBeginTransform bad_begin_template(Dummy) { Range R; - for co_await(auto i : R) {} + for co_await(auto i : R) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}} // expected-error@-1 {{call to deleted member function 'await_transform'}} // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}} } @@ -106,7 +106,7 @@ struct ForLoopAwaiterBadIncTransform { }; ForLoopAwaiterBadIncTransform bad_inc_transform() { Range R; - for co_await(auto i : R) {} + for co_await(auto i : R) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}} // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}} // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range'}} } @@ -114,7 +114,7 @@ ForLoopAwaiterBadIncTransform bad_inc_transform() { template ForLoopAwaiterBadIncTransform bad_inc_transform_template(Dummy) { Range R; - for co_await(auto i : R) {} + for co_await(auto i : R) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}} // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}} // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range'}} } @@ -125,7 +125,7 @@ template ForLoopAwaiterBadIncTransform bad_inc_transform_template(long); // expe template constexpr void never_instant(T) { static_assert(sizeof(T) != sizeof(T), "function should not be instantiated"); - for co_await(auto i : foo(T{})) {} + for co_await(auto i : foo(T{})) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}} // expected-error@-1 {{'co_await' cannot be used in a constexpr function}} } @@ -149,7 +149,7 @@ using NS::ForLoopAwaiterCoawaitLookup; template ForLoopAwaiterCoawaitLookup test_coawait_lookup(T) { Range R; - for co_await(auto i : R) {} + for co_await(auto i : R) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}} // expected-error@-1 {{no member named 'await_ready' in 'CoawaitTag, false>'}} } template ForLoopAwaiterCoawaitLookup test_coawait_lookup(int); // expected-note {{requested here}}