[DiagnosticInfo] Allow std::string_view in DiagnosticBuilder operator<<. (#190374)

After a68ae7b0cc0922b79114aabe8cf1ec8dc68524d7, calling `<<` with a
`std::string_view` gives:

```
clang/include/clang/Basic/Diagnostic.h:1319:8: error: use of overloaded operator '<<' is ambiguous (with operand types 'const StreamingDiagnostic' and 'const std::string_view')
 1319 |     DB << V;
      |     ~~ ^  ~
```
This commit is contained in:
Jackson Stogel 2026-04-03 15:02:14 -07:00 committed by GitHub
parent 55bcc05a72
commit 3f37512c8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 17 deletions

View File

@ -36,6 +36,7 @@
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
@ -1374,6 +1375,12 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
return DB;
}
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
std::string_view S) {
DB.AddString(S);
return DB;
}
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
const std::string &S) {
DB.AddString(S);

View File

@ -23,6 +23,7 @@
#include "gtest/gtest.h"
#include <memory>
#include <optional>
#include <string_view>
#include <vector>
using namespace llvm;
@ -42,8 +43,19 @@ void clang::DiagnosticsTestHelper(DiagnosticsEngine &diag) {
namespace {
using testing::AllOf;
using testing::ElementsAre;
using testing::HasSubstr;
using testing::IsEmpty;
MATCHER_P(WithMessage, M,
"has diagnostic message that " +
::testing::DescribeMatcher<std::string>(M)) {
return testing::ExplainMatchResult(M, arg.getMessage().str(),
result_listener);
}
MATCHER(IsError, "has error severity") {
return arg.getLevel() == DiagnosticsEngine::Level::Error;
}
// Check that DiagnosticErrorTrap works with SuppressAllDiagnostics.
TEST(DiagnosticTest, suppressAndTrap) {
DiagnosticOptions DiagOpts;
@ -164,20 +176,20 @@ TEST(DiagnosticTest, diagnosticError) {
EXPECT_EQ(Value->first, 20);
}
class CaptureDiagnosticConsumer : public DiagnosticConsumer {
public:
SmallVector<StoredDiagnostic> StoredDiags;
void HandleDiagnostic(DiagnosticsEngine::Level level,
const Diagnostic &Info) override {
StoredDiags.push_back(StoredDiagnostic(level, Info));
}
};
TEST(DiagnosticTest, storedDiagEmptyWarning) {
DiagnosticOptions DiagOpts;
DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts);
class CaptureDiagnosticConsumer : public DiagnosticConsumer {
public:
SmallVector<StoredDiagnostic> StoredDiags;
void HandleDiagnostic(DiagnosticsEngine::Level level,
const Diagnostic &Info) override {
StoredDiags.push_back(StoredDiagnostic(level, Info));
}
};
CaptureDiagnosticConsumer CaptureConsumer;
Diags.setClient(&CaptureConsumer, /*ShouldOwnClient=*/false);
Diags.Report(diag::pp_hash_warning) << "";
@ -187,6 +199,21 @@ TEST(DiagnosticTest, storedDiagEmptyWarning) {
Diags.Report(CaptureConsumer.StoredDiags.front());
}
// std::string_view is used by downstream consumers.
TEST(DiagnosticTest, reportAcceptsStringViewMessage) {
DiagnosticOptions DiagOpts;
DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts);
CaptureDiagnosticConsumer CaptureConsumer;
Diags.setClient(&CaptureConsumer, /*ShouldOwnClient=*/false);
std::string_view SV = "diagnostic";
Diags.Report(diag::err_target_unknown_triple) << SV;
EXPECT_THAT(CaptureConsumer.StoredDiags,
ElementsAre(WithMessage(HasSubstr("diagnostic"))));
}
class SuppressionMappingTest : public testing::Test {
public:
SuppressionMappingTest() {
@ -226,13 +253,6 @@ private:
CaptureDiagnosticConsumer CaptureConsumer;
};
MATCHER_P(WithMessage, Msg, "has diagnostic message") {
return arg.getMessage() == Msg;
}
MATCHER(IsError, "has error severity") {
return arg.getLevel() == DiagnosticsEngine::Level::Error;
}
TEST_F(SuppressionMappingTest, MissingMappingFile) {
Diags.getDiagnosticOptions().DiagnosticSuppressionMappingsFile = "foo.txt";
clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS);