[clang] More informative mixed namespace diagnostics

First, let's check we get a TemplateDecl, before complaining about
where it might have been found.

Second, if it came from an unexpected place, show where that location is.

Reviewed By: ChuanqiXu

Differential Revision: https://reviews.llvm.org/D116164
This commit is contained in:
Nathan Sidwell 2021-12-25 13:29:58 -05:00
parent b1a333f0fe
commit d4f09786e0
13 changed files with 39 additions and 18 deletions

View File

@ -1740,30 +1740,38 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
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<ClassTemplateDecl>())) {
StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>();
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;

View File

@ -53,6 +53,7 @@ MyForLoopArrayAwaiter g() {
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 {

View File

@ -40,6 +40,7 @@ VoidTagReturnValue test() {
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;
}

View File

@ -84,6 +84,7 @@ template <typename... T>
struct std::experimental::coroutine_traits<int, T...> { 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() {

View File

@ -7,6 +7,7 @@ namespace std {
namespace experimental {
template <class Ret, typename... T>
struct coroutine_traits { using promise_type = typename Ret::promise_type; };
// expected-note@-1{{declared here}}
template <class Promise = void>
struct coroutine_handle {

View File

@ -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 @@ struct std::coroutine_traits<void> { using promise_type = promise_void; };
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}}
}

View File

@ -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 @@ struct std::coroutine_traits<void> { using promise_type = promise_void; };
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}}
}

View File

@ -30,6 +30,7 @@ struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
template <class Ret, class... Args>
struct coroutine_traits : public traits_sfinae_base<Ret> {};
// expected-note@-1{{declared here}}
} // namespace std::experimental
struct suspend_never {

View File

@ -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 <typename... T> struct coroutine_traits;
// expected-note@-1{{declared here}}
template <class Promise = void> struct coroutine_handle {
coroutine_handle() = default;

View File

@ -6,7 +6,7 @@
namespace std {
namespace experimental {
template <typename... T>
struct coroutine_traits {
struct coroutine_traits { // expected-note{{declared here}}
struct promise_type {};
};

View File

@ -33,6 +33,7 @@ struct std::experimental::coroutine_traits<void, T...> { using promise_type = pr
#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

View File

@ -32,6 +32,7 @@ struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
template <class Ret, class... Args>
struct coroutine_traits : public traits_sfinae_base<Ret> {};
// expected-note@-1{{declared here}}
} // namespace std::experimental
struct suspend_never {

View File

@ -45,6 +45,7 @@ struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
template <class Ret, class... Args>
struct coroutine_traits : public traits_sfinae_base<Ret> {};
// expected-note@-1{{declared here}}
} // namespace experimental
} // namespace std