跳到正文
cccskills
免费在 GitHub 公开中文介绍

Diagnostics

本技能介绍如何在Carbon工具链中添加或修改错误和警告,包括注册诊断类型、用带类型的参数构造消息、为源码位置添加标签和上下文,以及检查措辞规范和测试覆盖。

原文查看原文说明

Instructions for declaring, formatting, emitting, testing, and styling diagnostic messages (errors, warnings, and the labels that explain them) in the Carbon toolchain.

carbon-language/carbon-lang星标 33,929(GitHub 33,929 + cccskills 0)

实测评分 未实测

查看安装方法

适用场景

  • 添加诊断消息
  • 为源码位置添加标签
  • 统一诊断措辞
  • 检查诊断测试覆盖

中文介绍

功能

本技能说明如何在Carbon工具链中添加或修改错误和警告,涵盖从注册、显示到验证的流程。内容包括注册诊断类型并确保每种类型只有一处声明、使用带类型的参数构造消息,以及为源码位置附加标签和上下文。还会介绍诊断文本的格式约定,例如以小写字母开头且末尾不加句号,并说明如何使用测试数据检查每条诊断是否都得到覆盖。

适用场景

在开发Carbon编译器、添加错误或警告,或整理现有诊断文本以便阅读时,可以参考本技能。如果需要把消息关联到具体代码位置,或核对诊断声明、标签与测试之间的对应关系,也适用。

使用示例

  • “这个错误的源码位置应如何添加标签?”
  • “请说明如何新增诊断类型并在测试中覆盖它。”

注意事项

本技能以Carbon工具链的C++实现和测试规范为前提。

本介绍由 AI(OpenAI Codex)根据公开的 SKILL.md 撰写。准确的规格请查看下方原文。

文档检查

AI 根据 SKILL.md 的内容检查了需要注意的操作和使用前提。评分只依据实际运行的结果(实测对比)。

安全性发送数据、删除文件、执行命令等是否有说明
A良好资料涉及诊断定义和测试,未提及删除、外发或读取凭据。
安装难易度所需工具和 API 密钥是否少且有说明
B部分不足资料以Carbon工具链的C++实现和测试规范为前提,但未提供安装步骤。

不计入评分。 由 AI(OpenAI Codex)于 2026年10月26日 评估。仅供参考,安装前请同时查看原文。

如果您认为评估有误,请申请复核

请写明哪一项有误以及原因。无需登录。我们会对照 SKILL.md 重新评估,并在此处更新结果。

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

包含的文件(1)

  • SKILL.md13.9 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Diagnostics in the Carbon Toolchain

<!-- Part of the Carbon Language project, under the Apache License v2.0 with LLVM Exceptions. See /LICENSE for license information. SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -->

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.


Architecture Overview

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:

  1. Registry: Globally enumerated kinds inside kind.def.
  2. Emitters: Specialized formatting pipelines (parameterized on custom phase location types LocT like Token or LocId) that convert raw tokens to standardized physical source locations (file, line, column, and the text of the line).
  3. Consumers: Pipelines that process, track, filter, and sort diagnostics. The default SortingConsumer buffers and stable-sorts diagnostics based on their last_byte_offset matching compiler traversal order to ensure perfect causal ordering.

1. Declaring and Registering Diagnostics

All diagnostic types must pass structural uniqueness and coverage verifications.

The Diagnostic Registry

Every diagnostic kind must be registered globally as an enum option under kind.def:

// toolchain/diagnostics/kind.def
CARBON_DIAGNOSTIC_KIND(RealLiteralTooLargeForUnsizedInt)

The Uniqueness Rule

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.


2. Formatting Diagnostic Arguments

Carbon diagnostics leverage LLVM's formatv engine. Parameters must be passed using strongly-typed arguments to preserve translation capability.

String Lifetimes & Pitfalls

  • 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.
  • Use std::string: If string formatting or custom allocations are required, declare the parameter storage type as std::string.

Format Selectors (format_providers.h)

Use specialized formatting wrappers under format_providers.h to express clean inline options in format strings:

WrapperTarget Format StyleExample UsageOutput
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 Toolchain Type Mappings

Custom structures can define how they serialize inside diagnostics using the DiagnosticType tag mapping to Diagnostics::TypeInfo<StorageType>:

  • Identifiers & Names (declared in 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").
  • Sized Primitives:
    • TypedInt: Formats an APInt constant exactly, extracting target signedness representation automatically from its bound type representation.
  • Type Formatter Hierarchy: When choosing parameter types to print compiler type representations, follow this priority list:
    1. TypeOfInstId (Preferred): Resolves the backing type of an InstId, preserving programmatic aliasing, constraints, and source spelling context. Enclosed under backticks automatically.
    2. InstIdAsType: Converts an InstId for a type expression, printing custom type layouts under backticks.
    3. TypeId (Fallback): Canonical description of the type. Avoid when possible because type canonicalization loses intermediate source program spelling and aliasing metadata.
    4. *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).

3. Fluent Emission Builders & RAII Scopes

Fluent Builder Pattern

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 overload Emit() && that triggers a compile-time static_assert(false). You must save the builder to an lvalue or execute the chain exactly as emitter.Build(...).Attach(...).Emit().

RAII Context & Annotation Scopes

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.


4. Diagnostics Wording Style Guide

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:

  • Start with lowercase and omit periods: Start diagnostic messages with a lowercase letter or quoted code, and do not end them with a period (e.g., "cannot convert..." or "`self` declared...").
  • Use backticks for quoted code: Enclose identifiers, code constructs, and types inside standard backticks (e.g., "`{0}` is bad").
  • Phrase as bullet points without articles: Phrase diagnostics as descriptive bullet points or sentence fragments rather than full sentences. Leave out standard articles (a, an, the) unless necessary for logical clarity. Semicolons can be used to separate fragments within a message.
  • Describe the situation and language rule: Diagnostics should describe the exact situation the toolchain observed. The language rule violated can be mentioned if it wouldn't otherwise be clear:
    • Situation-only: "redeclaration of X" (implies that redeclaration is not permitted).
    • Rule-inclusion: "`self` declared in invalid context; can only be declared in implicit parameter list".
  • Wording Choice ("cannot" vs "allowed"): Explicitly avoid "allowed", "legal", "permitted", "valid", and related passive wording. You may use "cannot" if needed, but try to use phrasing that does not require it:
    • Correct: "`export` in `impl` file" (Avoids "allowed")
    • Incorrect: "`export` is only allowed in API files"
    • Correct: "`extern library` specifies current library" (Avoids "cannot")
    • Incorrect: "`extern library` cannot specify the current library"
  • Developer Intent Hints: It is acceptable for a diagnostic to guess at the developer's intent and provide a hint after explaining the situation and the rule, but never as a substitute for that:
    • Correct: "cannot implicitly convert `i32` to `String`; add `as String` for explicit conversion"
    • Incorrect: "add `as String` to convert `i32` to `String`" (Lacks the core violation message).
  • Structure for Tooling API: Try to structure diagnostics such that parameter inputs can be programmatically extracted without string parsing (prefer strongly-typed parameters over format placeholders where possible).

5. Diagnostics Testing & Coverage Verification

Carbon strictly enforces testing coverage at build-time.

  1. 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/.

  2. 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);
    
  3. Build Enforcement: Failing to provide a diagnostic test check matcher triggers a failure on the target test //toolchain/diagnostics:coverage_test.

  4. 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.

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

本技能介绍如何使用命令行`gh`只读查看GitHub issue正文和评论,支持通过编号或URL定位,也可指定其他仓库,并说明如何提取大量评论。

  • 查看issue正文和评论
  • 通过URL读取issue
  • 查看其他仓库的issue
carbon-language/carbon-lang3.4万2026年10月26日 更新

Agent tools

免费有简介

本技能为在 Carbon 代码库中工作的 AI 助手规定文件查看、搜索和编辑工具,并说明临时文件的存放与清理规则,以及何时可以编写和运行自定义程序。

  • 按规定工具搜索Carbon文件
  • 为文件编辑选择专用工具
  • 确认临时文件的存放与清理规则
carbon-language/carbon-lang3.4万2026年10月26日 更新

Bazel usage

免费有简介

了解如何在 Carbon 项目中通过 Bazelisk 构建、测试和运行程序,包括指定目标、启用 ASan,以及系统依赖变更后重建缓存。

  • 构建 Carbon 代码
  • 运行与修改相关的测试
  • 启动 Bazel 构建的程序
carbon-language/carbon-lang3.4万2026年10月26日 更新

Builtin functions

免费有简介

本技能介绍如何为Carbon编译器添加内置函数,包括类型注册、签名验证、常量求值、运行时LLVM IR生成、Prelude绑定,以及使用最小Prelude编写针对性测试。

  • 注册内置函数
  • 实现常量求值
  • 添加LLVM IR生成
carbon-language/carbon-lang3.4万2026年10月26日 更新

Code style

免费有简介

了解 Carbon 工具链对 Bazel、C++、Carbon、Markdown 和 Python 文件的格式规范,并查看注释、文档、命名、设计及提交说明的写作要求。

  • 整理 Carbon 代码格式
  • 检查注释和文档
  • 确认名称是否符合实际含义
carbon-language/carbon-lang3.4万2026年10月26日 更新

GitHub CLI usage

免费有简介

使用 `gh` 只读搜索和查看 GitHub 的议题、拉取请求、仓库与代码,并了解如何查询 REST 和 GraphQL API、翻页获取结果及筛选或整理输出。

  • 查看议题内容和状态
  • 检查拉取请求差异与检查状态
  • 搜索 GitHub 代码或仓库
carbon-language/carbon-lang3.4万2026年10月26日 更新

查看 carbon-language 的全部技能

报告此技能的问题