comperr 1.0.0

A minimal, lightweight crate for emitting span-accurate compile-time errors from procedural macros.
Documentation
<div align="center">

# comperr

[![Rust Version](https://img.shields.io/badge/rustc-2024%20edition-blue.svg)](https://doc.rust-lang.org/edition-guide/rust-2024/)
[![Crates.io Version](https://img.shields.io/crates/v/comperr)](https://crates.io/crates/comperr)
[![docs.rs](https://img.shields.io/docsrs/comperr)](https://docs.rs/comperr)
[![License MIT](https://img.shields.io/crates/l/comperr)](https://codeberg.org/razkar/comperr/src/branch/main/LICENSE-MIT)
[![License Apache-2.0](https://img.shields.io/crates/l/comperr)](https://codeberg.org/razkar/comperr/src/branch/main/LICENSE-APACHE)
[![Crates.io Downloads](https://img.shields.io/crates/d/comperr)](https://crates.io/crates/comperr)
[![Deps.rs](https://deps.rs/repo/codeberg/razkar/comperr/status.svg)](https://deps.rs/repo/codeberg/razkar/comperr)
[![Maintenance](https://img.shields.io/badge/maintenance-actively--developed-brightgreen)](https://codeberg.org/razkar/comperr)

Span-accurate compile-time errors for proc-macro authors.

```rust
return comperr::error(span, "expected a string literal");
```

</div>

## The Problem

The obvious way to emit a `compile_error!` from a proc-macro:

```rust
format!("compile_error!(\"{}\");", msg)
    .parse::<TokenStream>()
    .unwrap()
```

produces tokens with no source location. The compiler points at the macro call site, not the token that caused the problem. Your users see the wrong line.

`comperr` builds the `compile_error!(...)` invocation token by token, calling `.set_span()` on each one. The diagnostic lands where you intended.

## Installation

```sh
cargo add comperr
```

MSRV: **Rust 1.85** (2024 edition). One dependency: `proc_macro2`.

## Usage

**Single error, return immediately:**

```rust
use comperr::error;
use proc_macro2::{Span, TokenStream};

pub fn my_macro(input: TokenStream) -> TokenStream {
    return error(span, "expected a string literal");
}
```

**Multiple errors, emit them all at once:**

```rust
use comperr::Error;
use proc_macro2::TokenStream;

pub fn my_macro(input: TokenStream) -> TokenStream {
    let mut errors = Error::empty();

    for field in &fields {
        if !is_valid(field) {
            errors.combine(Error::new(field.span(), "unsupported field type"));
        }
    }

    if !errors.is_empty() {
        return errors.to_compile_error();
    }

    // emit normal output
    TokenStream::new()
}
```

**Collect errors from an iterator:**

```rust
use comperr::Error;

let errors: Error = fields
    .iter()
    .filter_map(|f| validate(f).err())
    .collect();

if !errors.is_empty() {
    return errors.to_compile_error();
}
```

## API

| Item | Purpose |
|------|---------|
| `error(span, msg)` | One-shot: build and return a single-error `TokenStream`. |
| `Error::new(span, msg)` | Create a single `Error`. |
| `Error::empty()` | Create an empty accumulator, safe to `combine` into. |
| `Error::is_empty()` | Check whether any messages have been added. |
| `Error::combine(other)` | Merge another `Error` in. All messages emit together. |
| `Error::to_compile_error()` | Produce the `TokenStream` to return from your macro. |
| `Error::from_token_stream(ts)` | Reconstruct an `Error` from a `compile_error!` token stream. |
| `impl Extend<Error>` | Push errors from an iterator into an existing `Error`. |
| `impl FromIterator<Error>` | Collect an iterator of errors into a single `Error`. |

`Error` also implements `Display`, `Debug`, `Clone`, and `std::error::Error`.

## How It Works

Every token in a `TokenStream` carries a `Span` recording its source location. When the compiler processes a `compile_error!` invocation, it reads the span off the argument token to decide where to point the diagnostic. `comperr` calls `.set_span()` on every token it constructs, so the span you pass in is what the compiler sees, not some anonymous internal position.

## License

Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT]LICENSE-MIT or <http://opensource.org/licenses/MIT>)

at your option.

Cheers, RazkarStudio

© 2026 RazkarStudio. All rights reserved.