diff --git a/diagnostics/diagnostic_emitter.h b/diagnostics/diagnostic_emitter.h index a7b697359e73..704f3990667a 100644 --- a/diagnostics/diagnostic_emitter.h +++ b/diagnostics/diagnostic_emitter.h @@ -37,28 +37,30 @@ class DiagnosticEmitter { : callback_(std::move(callback)) {} ~DiagnosticEmitter() = default; - // Emits an error unconditionally. + // Emits an error unconditionally after applying the provided `substitutions`. template - auto EmitError(DiagnosticT diag) -> void { + void EmitError(typename DiagnosticT::Substitutions substitutions) { callback_({.short_name = DiagnosticT::ShortName, - .message = diag.Format()}); + .message = DiagnosticT::Format(substitutions)}); } - // Emits a stateless error unconditionally. + // Emits an error unconditionally when there are no substitutions. template - auto EmitError() -> std::enable_if_t> { + std::enable_if_t> + EmitError() { EmitError({}); } // Emits a warning if `F` returns true. `F` may or may not be called if the // warning is disabled. template - auto EmitWarningIf(llvm::function_ref f) -> void { + void EmitWarningIf( + llvm::function_ref f) { // TODO(kfm): check if this warning is enabled - DiagnosticT diag; - if (f(diag)) { - callback_( - {.short_name = DiagnosticT::ShortName, .message = diag.Format()}); + typename DiagnosticT::Substitutions substitutions; + if (f(substitutions)) { + callback_({.short_name = DiagnosticT::ShortName, + .message = DiagnosticT::Format(substitutions)}); } } @@ -81,7 +83,9 @@ inline auto NullDiagnosticEmitter() -> DiagnosticEmitter& { template struct SimpleDiagnostic { struct Substitutions {}; - static auto Format() -> std::string { return Derived::Message.str(); } + static auto Format(const Substitutions&) -> std::string { + return Derived::Message.str(); + } }; } // namespace Carbon diff --git a/lexer/numeric_literal.cpp b/lexer/numeric_literal.cpp index 0f548901ddbc..3c513292ba52 100644 --- a/lexer/numeric_literal.cpp +++ b/lexer/numeric_literal.cpp @@ -21,14 +21,16 @@ struct EmptyDigitSequence : SimpleDiagnostic { struct InvalidDigit { static constexpr llvm::StringLiteral ShortName = "syntax-invalid-number"; - char digit; - int radix; - - auto Format() -> std::string { - return llvm::formatv("Invalid digit '{0}' in {1} numeric literal.", digit, - (radix == 2 ? "binary" - : radix == 16 ? "hexadecimal" - : "decimal")) + struct Substitutions { + char digit; + int radix; + }; + static auto Format(const Substitutions& subst) -> std::string { + return llvm::formatv("Invalid digit '{0}' in {1} numeric literal.", + subst.digit, + (subst.radix == 2 ? "binary" + : subst.radix == 16 ? "hexadecimal" + : "decimal")) .str(); } }; @@ -43,15 +45,16 @@ struct IrregularDigitSeparators { static constexpr llvm::StringLiteral ShortName = "syntax-irregular-digit-separators"; - int radix; - - auto Format() -> std::string { - assert((radix == 10 || radix == 16) && "unexpected radix"); + struct Substitutions { + int radix; + }; + static auto Format(const Substitutions& subst) -> std::string { + assert((subst.radix == 10 || subst.radix == 16) && "unexpected radix"); return llvm::formatv( "Digit separators in {0} number should appear every {1} " "characters from the right.", - (radix == 10 ? "decimal" : "hexadecimal"), - (radix == 10 ? "3" : "4")) + (subst.radix == 10 ? "decimal" : "hexadecimal"), + (subst.radix == 10 ? "3" : "4")) .str(); } }; @@ -71,10 +74,12 @@ struct BinaryRealLiteral : SimpleDiagnostic { struct WrongRealLiteralExponent { static constexpr llvm::StringLiteral ShortName = "syntax-invalid-number"; - char expected; - - auto Format() -> std::string { - return llvm::formatv("Expected '{0}' to introduce exponent.", expected) + struct Substitutions { + char expected; + }; + static auto Format(const Substitutions& subst) -> std::string { + return llvm::formatv("Expected '{0}' to introduce exponent.", + subst.expected) .str(); } };