Error when using emitter.Build().Emit() (#5152)

I've found myself cleaning up other cases of this, so moving to disallow
it.

```
In file included from toolchain/check/merge.cpp:5:
In file included from ./toolchain/check/merge.h:8:
In file included from ./toolchain/check/context.h:13:
In file included from ./toolchain/check/decl_introducer_state.h:8:
In file included from ./toolchain/check/keyword_modifier_set.h:11:
In file included from ./toolchain/sem_ir/name_scope.h:10:
In file included from ./toolchain/sem_ir/ids.h:12:
./toolchain/diagnostics/diagnostic_emitter.h:95:11: error: static assertion failed: Use `emitter.Emit(...)` or `emitter.Build(...).Note(...).Emit(...)` instead of `emitter.Build(...).Emit(...)`
   95 |           false,
      |           ^~~~~
toolchain/check/merge.cpp:92:61: note: in instantiation of function template specialization 'Carbon::DiagnosticEmitter<Carbon::Check::SemIRLoc>::DiagnosticBuilder::Emit<>' requested here
   92 |   context.emitter().Build(loc, ExternRequiresDeclInApiFile).Emit();
      |                                                             ^
1 error generated.
```
This commit is contained in:
Jon Ross-Perkins
2025-03-19 23:33:52 +00:00
committed by GitHub
parent 584426dfa2
commit 84a8c458f9
2 changed files with 26 additions and 5 deletions
+1 -1
View File
@@ -89,7 +89,7 @@ auto DiagnoseExternRequiresDeclInApiFile(Context& context, SemIRLoc loc)
CARBON_DIAGNOSTIC(
ExternRequiresDeclInApiFile, Error,
"`extern` entities must have a declaration in the API file");
context.emitter().Build(loc, ExternRequiresDeclInApiFile).Emit();
context.emitter().Emit(loc, ExternRequiresDeclInApiFile);
}
auto DiagnoseIfInvalidRedecl(Context& context, Lex::TokenKind decl_kind,
+25 -4
View File
@@ -86,7 +86,11 @@ class DiagnosticEmitter {
// Emits the built diagnostic and its attached notes.
// For the expected usage see the builder API: `DiagnosticEmitter::Build`.
template <typename... Args>
auto Emit() -> void;
auto Emit() & -> void;
// Prevent trivial uses of the builder; always `static_assert`s.
template <typename... Args>
auto Emit() && -> void;
// Returns true if this DiagnosticBuilder may emit a diagnostic. Can be used
// to avoid excess work computing notes, etc, if no diagnostic is going to
@@ -282,7 +286,7 @@ auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Note(
template <typename LocT>
template <typename... Args>
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Emit() -> void {
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Emit() & -> void {
if (!emitter_) {
return;
}
@@ -292,6 +296,22 @@ auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Emit() -> void {
emitter_->consumer_->HandleDiagnostic(std::move(diagnostic_));
}
namespace Internal {
template <typename LocT>
concept AlwaysFalse = false;
} // namespace Internal
template <typename LocT>
template <typename... Args>
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Emit() && -> void {
// TODO: This is required by clang-16, but `false` may work in newer clang
// versions. Replace when possible.
static_assert(Internal::AlwaysFalse<LocT>,
"Use `emitter.Emit(...)` or "
"`emitter.Build(...).Note(...).Emit(...)` "
"instead of `emitter.Build(...).Emit(...)`");
}
template <typename LocT>
template <typename... Args>
DiagnosticEmitter<LocT>::DiagnosticBuilder::DiagnosticBuilder(
@@ -364,8 +384,9 @@ template <typename... Args>
auto DiagnosticEmitter<LocT>::Emit(
LocT loc, const DiagnosticBase<Args...>& diagnostic_base,
Internal::NoTypeDeduction<Args>... args) -> void {
DiagnosticBuilder(this, loc, diagnostic_base, {MakeAny<Args>(args)...})
.Emit();
DiagnosticBuilder builder(this, loc, diagnostic_base,
{MakeAny<Args>(args)...});
builder.Emit();
}
template <typename LocT>