コマンドラインからGitHub issueの本文やコメントを読み取り専用で確認し、URLや番号から対象リポジトリを指定する手順を案内します。
- issueの本文とコメントを読みたいとき
- URLからissueの内容を確認したいとき
- 別リポジトリのissueを参照したいとき
Carbonコンパイラのエラーや警告を定義し、書式やソース位置のラベルを整え、テストで網羅性を確かめる方法を案内します。
Instructions for declaring, formatting, emitting, testing, and styling diagnostic messages (errors, warnings, and the labels that explain them) in the Carbon toolchain.
実行スコア 未検証
インストール方法を見るCarbonツールチェーンでエラーや警告を追加・変更するときの、登録から表示、検証までの手順を確認できます。診断種別を登録して対応する宣言を一つに保つ方法、型付き引数でメッセージを組み立てる方法、ソース上の位置にラベルや文脈を付ける方法を扱います。小文字で始めてピリオドを付けないなど、診断文の表記ルールや、テストデータで各診断を確認するカバレッジ検査についても説明しています。
Carbonコンパイラに新しいエラーや警告を加える開発者や、既存の診断を読みやすく整理したい人に向いています。メッセージとコード上の該当箇所を結び付けたい場合や、診断の宣言・ラベル・テストの対応関係を確認したい場合にも使えます。
CarbonツールチェーンのC++実装とテスト規約を前提とします。
この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。
SKILL.md の記述から、注意が要る操作と導入の前提を AI が確認しました。点数は実際に動かした結果(実行検証)だけで付けています。
点数には入れていません。 2026年10月26日 時点で AI(OpenAI Codex)が判定しました。目安なので、入れる前に原文も確認してください。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
The Carbon compiler features a highly-engineered, context-aware diagnostics framework designed to deliver precise, readable, and highly targetable diagnostic output (errors, warnings, and the labels that explain them). This document establishes strict rules for declaring, formatting, emitting, testing, and styling compiler diagnostics.
graph TD
Kind[kind.def Registry] -->|Registration| Enum[Kind Enum ID]
Enum -->|Build/Emit| Emitter[Emitter LocT]
Emitter -->|ConvertLoc| Loc[Converted Physical Loc]
Emitter -->|formatv serialization| Formatting[format_providers.h / Custom Types]
Emitter -->|Emit Messages| Consumer[Console / Sorting Consumer]
Consumer -->|stable sort| StdErr[Compiler Standard Error]
Diagnostics are handled via three decoupled core components:
LocT like Token or LocId) that convert raw tokens
to standardized physical source locations (file, line, column, and the text
of the line).SortingConsumer buffers and stable-sorts diagnostics based on
their last_byte_offset matching compiler traversal order to ensure perfect
causal ordering.All diagnostic types must pass structural uniqueness and coverage verifications.
Every diagnostic kind must be registered globally as an enum option under kind.def:
// toolchain/diagnostics/kind.def
CARBON_DIAGNOSTIC_KIND(RealLiteralTooLargeForUnsizedInt)
To ensure optimal compile-time and analysis integrity, every diagnostic kind
declared in kind.def MUST be mapped to one and only one C++ macro
declaration (CARBON_DIAGNOSTIC or CARBON_DIAGNOSTIC_ON_SCOPE).
DO NOT duplicate diagnostic definitions across different locations.
The C++ representation of the diagnostic is a static/global constant of type
DiagnosticBase<Args...>.
Local Scope (Recommended): If the diagnostic is unique to a single
block/function body, declare it locally inside the function body
adjacent to its Emit trigger:
void ConvertFloatValueToInt(...) {
CARBON_DIAGNOSTIC(FloatNaNConvertedToInt, Error,
"cannot convert NaN to integer type {0}", SemIR::TypeId);
context.emitter().Emit(loc_id, FloatNaNConvertedToInt, dest_type_id);
}
File Scope: If the diagnostic is shared among multiple functions inside
the same file, declare it at file scope inside the anonymous namespace
of the .cpp file.
Global Scope: If a diagnostic (such as a shared helper label) is reused
across different physical files, define it in a shared header (e.g.
context/check helpers) and mark it extern where applicable, ensuring the
macro is only invoked once.
Carbon diagnostics leverage LLVM's formatv engine. Parameters must be passed
using strongly-typed arguments to preserve translation capability.
llvm::StringRef is DISALLOWED: Do not pass StringRef as a parameter
type to CARBON_DIAGNOSTIC due to unsafe lifetime and buffer-allocation
boundaries.llvm::StringLiteral is DISALLOWED: Do not use literal types as
arguments as they prevent future diagnostic localization and translations.std::string: If string formatting or custom allocations are
required, declare the parameter storage type as std::string.format_providers.h)Use specialized formatting wrappers under format_providers.h to express clean inline options in format strings:
| Wrapper | Target Format Style | Example Usage | Output |
|---|---|---|---|
BoolAsSelect | {Index:true|false} | "{0:is signed|is unsigned}" | Maps bool to selection string. |
IntAsSelect | {Index:=Val:String|:Default} | "{0:=1:is|:are}" | Matches exact options. |
IntAsSelect (Plural) | {Index:s} | "{0} argument{0:s}" | Prints "s" if value != 1 (e.g., "1 argument", "3 arguments"). |
Custom structures can define how they serialize inside diagnostics using the
DiagnosticType tag mapping to Diagnostics::TypeInfo<StorageType>:
check/diagnostic_helpers.h):
NameId: Formats raw identifier spelling, safely escaping keyword
conflicts under backticks automatically.LibraryNameId: Formats custom library descriptors cleanly (e.g.
default library or library "foo").TypedInt: Formats an APInt constant exactly, extracting target
signedness representation automatically from its bound type
representation.TypeOfInstId (Preferred): Resolves the backing type of an
InstId, preserving programmatic aliasing, constraints, and source
spelling context. Enclosed under backticks automatically.InstIdAsType: Converts an InstId for a type expression, printing
custom type layouts under backticks.TypeId (Fallback): Canonical description of the type. Avoid when
possible because type canonicalization loses intermediate source
program spelling and aliasing metadata.*AsRawType (e.g. InstIdAsRawType, TypeIdAsRawType): Formats
the type layout exactly like their counter-structures above, but
omits enclosing backticks (useful when inserting types inside larger
code snippets).A diagnostic is one message plus the labels that mark the source explaining it.
Use Build to state the message and Attach to mark each place the reader has
to look, chained fluently:
CARBON_DIAGNOSTIC_LABEL(ModifierPrevious, Info, "`{0}` previously appeared here",
Lex::TokenKind);
context.emitter()
.Build(second_node, ModifierRepeated, context.token_kind(second_node))
.Attach(first_node, ModifierPrevious, context.token_kind(first_node))
.Emit();
Labels are declared with CARBON_DIAGNOSTIC_LABEL where they are attached, and
are not registered in kind.def; check_diagnostics.py checks that each one is
attached and covered. A label is either Primary -- the range the message
itself is about -- or Info, for somewhere else the reader must look; those two
are the only categories, because anything not read against the code it names is
not a label. Attach(loc) with no label marks a range wordlessly, which is what
to use when a label would only restate the message.
Every diagnostic should attach at least one label; a message with nothing attached has nothing to show. See diagnostics.md for which range to pick and when a label earns words.
[!SAFETY] Emitter builders are marked
[[nodiscard]]. To prevent a developer from creating a builder but failing to terminal-chain.Emit(), the builder uses an rvalue overloadEmit() &&that triggers a compile-timestatic_assert(false). You must save the builder to an lvalue or execute the chain exactly asemitter.Build(...).Attach(...).Emit().
Manage large checking structures requiring blanket context using RAII block scopes:
ContextScope: Attaches a context to every diagnostic emitted within its
scope, describing the higher-level operation that failed because of it. A
context is declared with CARBON_DIAGNOSTIC_CONTEXT, or
CARBON_DIAGNOSTIC_SOFT_CONTEXT for one dropped when the diagnostic
already has a context:
Diagnostics::ContextScope diagnostic_context(
&context.emitter(), [&](auto& builder) {
CARBON_DIAGNOSTIC_CONTEXT(
QualifiedDeclInIncompleteClassScope,
"cannot declare a member of incomplete class {0}", SemIR::TypeId);
builder.Attach(loc_id, QualifiedDeclInIncompleteClassScope,
context.classes().Get(class_id).self_type_id);
});
A context is not a label: its text stands alone as a sentence, which is why it leads the diagnostic rather than following it.
AnnotationScope: RAII block scope that attaches labels to every diagnostic
emitted within it, using the same Builder as a direct emission.
Refer to the official Diagnostic message style guide for complete details.
To maintain message consistency and integrate cleanly with Clang diagnostics in interoperable code, adhere strictly to these rules:
"cannot convert..." or "`self` declared...")."`{0}` is bad").a, an, the) unless necessary for logical
clarity. Semicolons can be used to separate fragments within a message."redeclaration of X" (implies that redeclaration is
not permitted)."`self` declared in invalid context; can only be declared in implicit parameter list"."allowed",
"legal", "permitted", "valid", and related passive wording. You may
use "cannot" if needed, but try to use phrasing that does not require it:
"`export` in `impl` file" (Avoids "allowed")"`export` is only allowed in API files""`extern library` specifies current library" (Avoids
"cannot")"`extern library` cannot specify the current library""cannot implicitly convert `i32` to `String`; add `as String` for explicit conversion""add `as String` to convert `i32` to `String`" (Lacks
the core violation message).Carbon strictly enforces testing coverage at build-time.
Tag Verification Requirement: Every diagnostic kind declared in
kind.def (which is not blacklisted in the UntestedKinds array under
coverage_test.cpp)
MUST be verified by at least one testcase file inside
toolchain/*/testdata/.
Stderr Checklist Matchers: The testcase split verifying the diagnostic must catch it using standard CHECK matchers, explicitly tracking the matching enum tag in standard error comments:
// CHECK:STDERR: fail_bounds.carbon:[[@LINE+1]]:15: error: cannot convert NaN to integer type `i32` [FloatNaNConvertedToInt]
let a: i32 = Convert(nan_val);
Build Enforcement: Failing to provide a diagnostic test check matcher
triggers a failure on the target test
//toolchain/diagnostics:coverage_test.
Label Enforcement: A label is declared where it is attached rather than
in a central registry, so coverage_test has no list of labels to compare a
matched name against and leaves any name that isn't a kind alone.
check_diagnostics.py
is what checks them: it reads the declarations and the testdata directly, so
it catches a label with no test, a name matched on that is neither a kind
nor a label, and a kind registered in kind.def that nothing declares. It
runs as a pre-commit hook, which CI runs too, rather than as a bazel test --
reading every source file is what it needs and what a test in the sandbox
cannot do.
まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
コマンドラインからGitHub issueの本文やコメントを読み取り専用で確認し、URLや番号から対象リポジトリを指定する手順を案内します。
AIアシスタントがCarbonのコードベースを扱う際に、専用ツールでファイルを閲覧・検索・編集し、一時ファイルを管理するためのルールを示します。
Bazeliskを使ったCarbonプロジェクトのビルド、テスト、実行、デバッグの基本手順を確認し、対象を絞った検証やASanの利用方法も把握できます。
Carbonコンパイラに組み込み関数を追加する際の登録、型シグネチャ検証、定数評価、LLVMコード生成、テスト方法を案内します。
Carbonツールチェーンのコードを書く際に、言語ごとの整形方法やコメント、命名、ドキュメント、コミットメッセージの基準を確認できます。
`gh`でGitHubのIssue、プルリクエスト、リポジトリを読み取り専用で検索・確認し、必要な情報を絞り込む方法を案内します。