diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -1740,30 +1740,38 @@ return nullptr; } - if (!InStd) { - // Found only in std::experimental. - Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) - << "coroutine_traits"; - } else if (InExp) { - // Found in std and std::experimental. - Diag(KwLoc, - diag::err_mixed_use_std_and_experimental_namespace_for_coroutine); - Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) - << "coroutine_traits"; - return nullptr; - } - // Prefer ::std to std::experimental. auto &Result = InStd ? ResStd : ResExp; CoroTraitsNamespaceCache = InStd ? StdSpace : ExpSpace; // coroutine_traits is required to be a class template. - if (!(StdCoroutineTraitsCache = Result.getAsSingle())) { + StdCoroutineTraitsCache = Result.getAsSingle(); + if (!StdCoroutineTraitsCache) { Result.suppressDiagnostics(); NamedDecl *Found = *Result.begin(); Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); return nullptr; } + + if (InExp) { + // Found in std::experimental + Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) + << "coroutine_traits"; + ResExp.suppressDiagnostics(); + auto *Found = *ResExp.begin(); + Diag(Found->getLocation(), diag::note_entity_declared_at) << Found; + + if (InStd) { + // Also found in std + Diag(KwLoc, + diag::err_mixed_use_std_and_experimental_namespace_for_coroutine); + Diag(StdCoroutineTraitsCache->getLocation(), + diag::note_entity_declared_at) + << StdCoroutineTraitsCache; + + return nullptr; + } + } } Namespace = CoroTraitsNamespaceCache; return StdCoroutineTraitsCache; diff --git a/clang/test/SemaCXX/co_await-range-for-exp-namespace.cpp b/clang/test/SemaCXX/co_await-range-for-exp-namespace.cpp --- a/clang/test/SemaCXX/co_await-range-for-exp-namespace.cpp +++ b/clang/test/SemaCXX/co_await-range-for-exp-namespace.cpp @@ -53,6 +53,7 @@ for co_await (auto i : arr) {} // expected-warning {{support for std::experimental::coroutine_traits will be removed}} // expected-error@-1 {{call to deleted member function 'await_transform'}} // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}} + // expected-note@Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}} } struct ForLoopAwaiterBadBeginTransform { diff --git a/clang/test/SemaCXX/coreturn-eh-exp-namespace.cpp b/clang/test/SemaCXX/coreturn-eh-exp-namespace.cpp --- a/clang/test/SemaCXX/coreturn-eh-exp-namespace.cpp +++ b/clang/test/SemaCXX/coreturn-eh-exp-namespace.cpp @@ -40,6 +40,7 @@ object x = {}; try { co_return {}; // expected-warning {{support for std::experimental::coroutine_traits will be removed}} + // expected-note@Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}} } catch (...) { throw; } diff --git a/clang/test/SemaCXX/coreturn-exp-namespace.cpp b/clang/test/SemaCXX/coreturn-exp-namespace.cpp --- a/clang/test/SemaCXX/coreturn-exp-namespace.cpp +++ b/clang/test/SemaCXX/coreturn-exp-namespace.cpp @@ -84,6 +84,7 @@ struct std::experimental::coroutine_traits { using promise_type = promise_int; }; void test0() { co_await a; } // expected-warning {{support for std::experimental::coroutine_traits will be removed}} +// expected-note@Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}} float test1() { co_await a; } int test2() { diff --git a/clang/test/SemaCXX/coroutine-final-suspend-noexcept-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-final-suspend-noexcept-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutine-final-suspend-noexcept-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutine-final-suspend-noexcept-exp-namespace.cpp @@ -7,6 +7,7 @@ namespace experimental { template struct coroutine_traits { using promise_type = typename Ret::promise_type; }; +// expected-note@-1{{declared here}} template struct coroutine_handle { diff --git a/clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s #include "Inputs/std-coroutine-exp-namespace.h" -#include "Inputs/std-coroutine.h" +#include "Inputs/std-coroutine.h" // Second struct my_awaitable { bool await_ready() noexcept; @@ -25,4 +25,6 @@ void test() { co_return; // expected-error {{mixed use of std and std::experimental namespaces for coroutine components}} // expected-warning@-1{{support for std::experimental::coroutine_traits will be removed}} + // expected-note@Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}} + // expected-note@Inputs/std-coroutine.h:8 {{'coroutine_traits' declared here}} } diff --git a/clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp @@ -1,10 +1,10 @@ // This file is to test the mixed use of `std::experimental::coroutine_traits` and `std::coroutine_traits` -// which is similar to coroutine-mixed-exp-namesapce. This file tests the relative order of +// which is similar to coroutine-mixed-exp-namespace. This file tests the relative order of // included header wouldn't affect the diagnostic messages. // RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s +#include "Inputs/std-coroutine.h" // First #include "Inputs/std-coroutine-exp-namespace.h" -#include "Inputs/std-coroutine.h" struct my_awaitable { bool await_ready() noexcept; @@ -26,4 +26,6 @@ void test() { co_return; // expected-error {{mixed use of std and std::experimental namespaces for coroutine components}} // expected-warning@-1{{support for std::experimental::coroutine_traits will be removed}} + // expected-note@Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}} + // expected-note@Inputs/std-coroutine.h:8 {{'coroutine_traits' declared here}} } diff --git a/clang/test/SemaCXX/coroutine-rvo-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-rvo-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutine-rvo-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutine-rvo-exp-namespace.cpp @@ -30,6 +30,7 @@ template struct coroutine_traits : public traits_sfinae_base {}; +// expected-note@-1{{declared here}} } // namespace std::experimental struct suspend_never { diff --git a/clang/test/SemaCXX/coroutine-seh-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-seh-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutine-seh-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutine-seh-exp-namespace.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -triple x86_64-windows-msvc -fms-extensions namespace std::experimental { template struct coroutine_traits; +// expected-note@-1{{declared here}} template struct coroutine_handle { coroutine_handle() = default; diff --git a/clang/test/SemaCXX/coroutine-traits-undefined-template-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-traits-undefined-template-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutine-traits-undefined-template-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutine-traits-undefined-template-exp-namespace.cpp @@ -6,7 +6,7 @@ namespace std { namespace experimental { template -struct coroutine_traits { +struct coroutine_traits { // expected-note{{declared here}} struct promise_type {}; }; diff --git a/clang/test/SemaCXX/coroutine-unhandled_exception-warning-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-unhandled_exception-warning-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutine-unhandled_exception-warning-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutine-unhandled_exception-warning-exp-namespace.cpp @@ -33,6 +33,7 @@ #ifndef DISABLE_WARNING void test0() { // expected-warning {{'promise_void' is required to declare the member 'unhandled_exception()' when exceptions are enabled}} co_return; // expected-warning {{support for std::experimental::coroutine_traits will be removed}} + // expected-note@Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}} } #else void test0() { // expected-no-diagnostics diff --git a/clang/test/SemaCXX/coroutine_handle-address-return-type-exp-namespace.cpp b/clang/test/SemaCXX/coroutine_handle-address-return-type-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutine_handle-address-return-type-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutine_handle-address-return-type-exp-namespace.cpp @@ -32,6 +32,7 @@ template struct coroutine_traits : public traits_sfinae_base {}; +// expected-note@-1{{declared here}} } // namespace std::experimental struct suspend_never { diff --git a/clang/test/SemaCXX/coroutines-exp-namespace.cpp b/clang/test/SemaCXX/coroutines-exp-namespace.cpp --- a/clang/test/SemaCXX/coroutines-exp-namespace.cpp +++ b/clang/test/SemaCXX/coroutines-exp-namespace.cpp @@ -45,6 +45,7 @@ template struct coroutine_traits : public traits_sfinae_base {}; +// expected-note@-1{{declared here}} } // namespace experimental } // namespace std