247 lines
8.7 KiB
Markdown
247 lines
8.7 KiB
Markdown
# 011 — Diagnostics
|
|
|
|
- **Status:** Draft
|
|
- **Normative language:** `MUST`, `MUST NOT`, `SHOULD`, `SHOULD NOT`, and `MAY` are to
|
|
be interpreted as described in RFC 2119.
|
|
|
|
## 1. Purpose
|
|
|
|
libVCT has a single central diagnostics service (`vct.diag`). Every module emits
|
|
diagnostics through it; no module prints directly to a stream. This gives embedders one
|
|
uniform surface for errors, warnings, notes, optimizer remarks, and internal compiler
|
|
errors, and it lets the CLI present them in several formats without every module knowing
|
|
which format is active.
|
|
|
|
## 2. Scope
|
|
|
|
This file specifies the diagnostics service, the `Diagnostic` structure and its
|
|
severity and code vocabulary, source maps, output channels, optimizer remarks, the
|
|
internal-compiler-error policy, and process exit codes. The pipeline that produces these
|
|
diagnostics is specified in [010 — Driver & CLI](010-driver-cli.md); the backends that
|
|
consume source maps are specified in [008 — C Backend](008-c-backend.md) and
|
|
[009 — LLVM Backend](009-llvm-backend.md).
|
|
|
|
## 3. Definitions
|
|
|
|
| Term | Meaning |
|
|
|---|---|
|
|
| Diagnostic | One emitted message with severity, code, span, and optional notes and suggestions. |
|
|
| Severity | Error, Warning, Note, Remark, or Ice. |
|
|
| `DiagCode` | A stable, namespaced identifier such as `VCT1002`. |
|
|
| Span | A source range: file, line, column, and length. |
|
|
| Source map | The association of HIR nodes with frontend source locations, resolved for VIR through the lowering map. |
|
|
| Consumer | A `DiagnosticConsumer` callback that receives emitted diagnostics. |
|
|
| ICE | Internal compiler error. |
|
|
|
|
## 4. Model
|
|
|
|
The service is **emit-only** from the perspective of compilation modules. A module
|
|
builds a `Diagnostic` and hands it to the service. The service forwards it to the
|
|
configured consumer. Fatal conditions (an error diagnostic, or an ICE) stop the
|
|
pipeline at the next safe boundary; they never let compilation continue on invalid
|
|
state.
|
|
|
|
The service is GC-allocated, consistent with the cold path rule in
|
|
[001 — Architecture](001-architecture.md).
|
|
|
|
```d
|
|
struct Diagnostic {
|
|
Severity severity; // Error | Warning | Note | Remark | Ice
|
|
DiagCode code; // stable namespaced, e.g. VCT1002
|
|
string message;
|
|
Span primary;
|
|
Span[] notes;
|
|
Suggestion[] suggestions;
|
|
}
|
|
```
|
|
|
|
## 5. Normative requirements
|
|
|
|
### 5.1 Central service
|
|
|
|
**R1.** Every module MUST emit diagnostics through the central service. No module MUST
|
|
print to standard output or standard error directly.
|
|
|
|
**R2.** The service MUST be GC-allocated.
|
|
|
|
**R3.** The service MUST forward each emitted diagnostic to the configured consumer in
|
|
emission order.
|
|
|
|
**R4.** An `Error` or `Ice` diagnostic MUST prevent further compilation on the invalid
|
|
path. The pipeline MUST stop at the next safe boundary after such a diagnostic.
|
|
|
|
### 5.2 Diagnostic structure
|
|
|
|
**R5.** Every diagnostic MUST carry a `Severity` and a `DiagCode`. A diagnostic with no
|
|
code MUST NOT be emitted.
|
|
|
|
**R6.** `Severity` MUST be one of the values in Table 1.
|
|
|
|
**Table 1. Severity levels**
|
|
|
|
| Severity | Meaning |
|
|
|---|---|
|
|
| Error | Compilation cannot proceed correctly. |
|
|
| Warning | Suspicious but continuable. |
|
|
| Note | Supporting context attached to another diagnostic. |
|
|
| Remark | An optimizer decision record. |
|
|
| Ice | Internal compiler error. |
|
|
|
|
**R7.** A `DiagCode` MUST be a stable, namespaced identifier in the form `VCT` followed
|
|
by digits. Once published, a code's meaning MUST NOT change and the code MUST NOT be
|
|
renumbered.
|
|
|
|
**R8.** A diagnostic MUST carry a primary `Span` whenever a source location is known, and it MAY
|
|
carry additional note spans and suggestions. When no location can be resolved, the diagnostic MUST
|
|
carry no location instead (see R12).
|
|
|
|
**R9.** A `Note` diagnostic MUST be attached to a parent diagnostic rather than emitted
|
|
as a standalone top-level message.
|
|
|
|
### 5.3 Source maps
|
|
|
|
**R10.** The frontend MUST be able to register a `SourceLocation` (file, line, column,
|
|
length) against any HIR node.
|
|
|
|
**R11.** For VIR entities, the service MUST resolve source locations through the
|
|
lowering map that associates HIR nodes with the VIR entities they became (see
|
|
[005 — Lowering](005-lowering.md)).
|
|
|
|
**R12.** When a location cannot be resolved, the service MUST degrade gracefully to a
|
|
diagnostic with no location. It MUST NOT fabricate a location.
|
|
|
|
**R13.** The C backend MUST emit `#line` directives from the registered source map (see
|
|
[008 — C Backend](008-c-backend.md)), and the driver MUST re-map compiler errors through
|
|
it (see [010 — Driver & CLI](010-driver-cli.md)).
|
|
|
|
### 5.4 Channels
|
|
|
|
**R14.** The service MUST expose a single canonical `DiagnosticConsumer` callback for
|
|
embedders.
|
|
|
|
**R15.** The CLI MUST provide a human-readable channel that enables color when standard
|
|
error is a terminal.
|
|
|
|
**R16.** The CLI MUST provide a JSON channel selected by `--diagnostics=json`.
|
|
|
|
**R17.** The JSON channel MUST use a versioned schema. The schema version MUST appear in
|
|
the output, and the schema MUST be stable within a major version.
|
|
|
|
**R18.** A single diagnostic MUST render equivalently in content across all channels; the
|
|
channels differ only in presentation.
|
|
|
|
Example JSON shape:
|
|
|
|
```json
|
|
{
|
|
"version": 1,
|
|
"diagnostics": [
|
|
{
|
|
"severity": "error",
|
|
"code": "VCT1002",
|
|
"message": "missing trait at lowering",
|
|
"file": "input.vox",
|
|
"line": 12,
|
|
"column": 5,
|
|
"length": 3,
|
|
"notes": []
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 5.5 Optimizer remarks
|
|
|
|
**R19.** Optimizer remarks MUST be off by default and MUST be enabled by `--remarks`.
|
|
|
|
**R20.** Optimizer remarks MUST be enabled automatically at `-O3`.
|
|
|
|
**R21.** Every remark MUST be tied to a specific trait-pipeline decision, naming the
|
|
request or attribute that drove it.
|
|
|
|
Examples:
|
|
|
|
```
|
|
HIR: replaced 3 uses of node#412 (comptime 64)
|
|
VIR: denied Inline on @foo - CostModel (callee 2.4x size budget)
|
|
```
|
|
|
|
### 5.6 Internal compiler error policy
|
|
|
|
**R22.** The following conditions MUST be treated as internal compiler errors:
|
|
|
|
- a missing or contradictory trait encountered at lowering (see
|
|
[005 — Lowering](005-lowering.md));
|
|
- a VIR invariant violation detected in a debug build (see [006 — VIR](006-vir.md));
|
|
- a `Strong` request denied for reason `Illegality` or `ContradictsTrait` (see
|
|
[007 — VIR Optimizer](007-vir-optimizer.md)).
|
|
|
|
**R23.** In release builds, an internal compiler error MUST return a failure result and
|
|
emit an `Ice` diagnostic that requests a module dump.
|
|
|
|
**R24.** In debug builds, an internal compiler error MUST assert.
|
|
|
|
**R25.** An internal compiler error MUST NEVER be silently continued past.
|
|
|
|
### 5.7 Warning policy
|
|
|
|
**R26.** The trait-mismatch warning raised when a suggested trait conflicts with the
|
|
derived value MUST be promoted to an error under `-Werror`.
|
|
|
|
**R27.** A frontend MUST be able to opt out of warning promotions: `-Wno-error=<category>` MUST
|
|
disable the promotion of that category, and a bare `-Wno-error` MUST disable every promotion.
|
|
|
|
### 5.8 Exit codes
|
|
|
|
**R28.** The CLI MUST exit with the codes in Table 2.
|
|
|
|
**Table 2. Exit codes**
|
|
|
|
| Code | Meaning |
|
|
|---|---|
|
|
| 0 | Success. |
|
|
| 1 | Diagnostics present. |
|
|
| 2 | Usage or configuration error. |
|
|
| 3 | Internal compiler error. |
|
|
|
|
**R29.** Exit code 3 MUST take precedence over exit code 1 when an ICE has been emitted.
|
|
|
|
## 6. Invariants
|
|
|
|
- **I1.** Every emitted diagnostic has a severity and a `DiagCode`.
|
|
- **I2.** No compilation module writes directly to a stream.
|
|
- **I3.** Diagnostics are emitted and rendered in a deterministic order for a fixed
|
|
input and `Config`.
|
|
- **I4.** An ICE never resolves to a success exit code.
|
|
- **I5.** A location is either resolved or omitted; it is never invented.
|
|
- **I6.** The JSON channel's schema version is always present.
|
|
|
|
## 7. Examples
|
|
|
|
A frontend registers a location and a later lowering failure reports it:
|
|
|
|
```d
|
|
diag.registerLocation(node, SourceLocation("input.vox", 12, 5, 3));
|
|
// later, during lowering:
|
|
emit(Diagnostic(Severity.Error, DiagCode(1002),
|
|
"missing trait at lowering", span));
|
|
```
|
|
|
|
A `MustTail` request on GCC becomes a hard error rather than a silent fallback:
|
|
|
|
```
|
|
error[VCT1044]: MustTail requires [[clang::musttail]]; current compiler is GCC
|
|
--> input.vox:7:5
|
|
```
|
|
|
|
## 8. Cross-references
|
|
|
|
- [000 — Overview](000-overview.md) for conformance and determinism.
|
|
- [001 — Architecture](001-architecture.md) for the cold-path GC rule.
|
|
- [002 — Traits](002-traits.md) for the trait vocabulary and mismatch handling.
|
|
- [005 — Lowering](005-lowering.md) for the lowering map and ICE conditions.
|
|
- [006 — VIR](006-vir.md) for the invariants checked in debug.
|
|
- [007 — VIR Optimizer](007-vir-optimizer.md) for request denials and `DenyReason`.
|
|
- [008 — C Backend](008-c-backend.md) for `#line` emission.
|
|
- [010 — Driver & CLI](010-driver-cli.md) for `--remarks`, `--diagnostics`, and exit codes.
|