Error codes
Every C+ diagnostic carries a numbered code, a source span, and often a machine-applicable suggestion. cpc --diagnostics=json emits the same information in a machine-readable shape for editors and agents. Codes prefixed with W are non-fatal warnings; the build continues. The normative ranges and what each phase owns are fixed in §20 of the language specification.
This is the complete index — 146 codes. Each entry gives the meaning, a minimal example that triggers it, and the typical fix. 114 of the examples are reproduced directly by cpc check; the rest need a multi-file project, a --target, or a build-time file, and say so in the example.
Lexical
E0001 · Unexpected character
The lexer hit a byte it cannot start a token with (also fired for a bad char literal such as an empty '', a multi-byte 'ab', or a non-ASCII 'á').
fn main() -> i32 { let x = 'ab'; return 0; }
Fix. Remove or correct the stray character; for UTF-8 text use a str instead of a char literal.
E0002 · Unterminated block comment
A /* ... */ block comment was opened but never closed before end of input.
/* hello
Fix. Close the comment with */.
E0003 · Invalid number literal
A numeric literal has no valid digits or a malformed exponent (e.g. 0x with no hex digits, or 1e with no exponent).
fn main() -> i32 { let x = 0x; return 0; }
Fix. Write a well-formed literal with at least one digit.
E0004 · Invalid numeric type suffix
A number literal carries a type suffix that is not one of i8/i16/i32/i64/u8/u16/u32/u64/isize/usize/f32/f64.
fn main() -> i32 { let x = 42xyz; return 0; }
Fix. Use a valid suffix or drop it.
E0005 · Unterminated string literal
A string literal was opened with " but reached end of line or end of input before a closing quote.
fn main() -> i32 { let s = "oops; return 0; }
Fix. Add the closing " (or use a """...""" triple-quoted string for multi-line text).
Parser
E0100 · Unexpected token
The parser found a token where a different one was expected (the most common case is a missing ;).
fn main() -> i32 { let x = 1 0 }
Fix. Insert the expected token; the compiler often suggests ;.
E0101 · Unexpected end of input
Input ended while the parser was still expecting more tokens (e.g. an unmatched {).
fn main() -> i32 {
Fix. Close the open construct (e.g. add the missing }).
E0102 · Non-chainable comparison
Comparison operators were chained (e.g. a < b < c), which is not allowed.
fn main() -> i32 { let r = 1 < 2 < 3; 0 }
Fix. Split into separate comparisons joined with &&, e.g. a < b && b < c.
Names, types, and items
E0300 · Undefined name
A referenced name (variable, function, or self outside a method) is not in scope.
fn main() -> i32 { return x; }
Fix. Fix the typo, add the missing import, or remember a forgotten pub.
E0301 · Duplicate definition
Two items (functions, or types/interfaces) share the same name.
fn f() -> i32 { 0 }
fn f() -> i32 { 1 }
fn main() -> i32 { return f(); }
Fix. Rename one of the conflicting items.
E0302 · Type mismatch
An expression's type does not match the type required by its context (declared type, argument, condition, etc.).
fn main() -> i32 { let x: i32 = true; return 0; }
Fix. Insert an as cast or change the declared type.
E0303 · Unknown type
A named type cannot be resolved to any declared type, enum, or in-scope generic parameter.
fn main() -> Foo { return 0; }
Fix. Typo, missing import, or a generic param not in scope. The owned string type was removed: use Text and import "stdlib/text".
E0304 · Condition must be bool
The condition of an if or while is not of type bool.
fn main() -> i32 { return if 1 { 1 } else { 2 }; }
Fix. Use a boolean expression, e.g. compare with != 0.
E0305 · Assignment to immutable binding
An assignment targets a binding (or a place rooted at one) that was not declared let mut.
fn main() -> i32 { let x = 1; x = 2; return 0; }
Fix. Declare the binding as let mut.
E0306 · Block produces no value but one is required
A function whose return type is non-Unit reaches the end of its body without an explicit return ...; or a diverging tail.
fn f() -> i32 { 1; }
fn main() -> i32 { return f(); }
Fix. End the body with an explicit return EXPR;.
E0307 · return without a value
A bare return; appears in a function that declares a non-Unit return type.
fn f() -> i32 { return; }
fn main() -> i32 { return f(); }
Fix. Return a value: return EXPR;.
E0308 · Wrong number of arguments
A call passes a different number of arguments than the function (or intrinsic) declares.
fn main() -> i32 { #println(1, 2); return 0; }
Fix. Match the function's parameter count.
E0309 · Wrong main signature
main is declared with parameters or a return type other than fn main() -> i32.
fn main() { }
Fix. Declare it as fn main() -> i32.
E0312 · Function used as value
A function name is used as a bare value (or another unsupported form such as &x, a range outside for, or a malformed path) where a callable or value of the right shape was required.
fn main() -> i32 { let x = 1; let y = &x; return 0; }
Fix. Assign it to a fn(...)-typed binding to take the address.
E0313 · Assignment target is not a place
The left-hand side of an assignment is not a place expression (e.g. a literal or temporary).
fn main() -> i32 { 1 = 2; return 0; }
Fix. Assign to a variable, field, or index that names a storage location.
E0315 · Invalid cast
An as cast is between a pair of types that the language forbids.
fn main() -> i32 { let _b: bool = 1 as bool; return 0; }
Fix. Some pairs are forbidden (for example int to bool, *T to i32); restructure the conversion.
E0316 · Modulo on float types
The % operator was applied to a floating-point operand, which is not supported.
fn main() -> i32 { let x: f64 = 1.0 % 2.0; let _y: f64 = x; return 0; }
Fix. Use integer operands, or compute the remainder another way.
E0317 · Unknown enum variant
A path or expression names a variant that the enum does not declare.
enum Color { Red }
fn main() -> i32 { let _c: Color = Color::Purple; return 0; }
Fix. Use a variant the enum actually declares.
E0318 · Duplicate enum variant
Two variants in the same enum share a name.
enum E { A, A }
fn main() -> i32 { return 0; }
Fix. Rename one of the variants.
E0319 · Duplicate field in struct literal
A struct literal lists the same field name twice.
struct E { x: i32, x: i32 }
fn main() -> i32 { return 0; }
Fix. List each field once; match the declaration.
E0320 · Unknown struct field
A field access (s.f) names a field the struct does not declare.
struct A { x: i32 }
fn main() -> i32 { let a: A = A { x: 1 }; let _v: i32 = a.y; return 0; }
Fix. Access a field the struct actually declares.
E0321 · Missing field in struct literal
A struct literal omits a field the struct declares.
struct A { x: i32, y: i32 }
fn main() -> i32 { let _a: A = A { x: 1 }; return 0; }
Fix. Provide every declared field; match the declaration.
E0322 · Extra field in struct literal
A struct literal includes a field the struct does not declare.
struct A { x: i32 }
fn main() -> i32 { let _a: A = A { x: 1, y: 2 }; return 0; }
Fix. Remove the extra field; match the declaration.
E0323 · Field access on non-struct type
A .field access is performed on a value whose type is not a struct.
fn main() -> i32 { let x: i32 = 5; let _v: i32 = x.foo; return 0; }
Fix. Only access fields on struct values.
E0324 · Unknown method
A method call names a method (or free fn in the type's module) that the struct does not have.
struct P {}
impl P {}
fn main() -> i32 { let p: P = P {}; return p.missing(); }
Fix. Call a method the type actually declares, or define it in an impl.
E0325 · impl on an unknown or non-struct type
An impl names a target that is not a declared struct or (non-generic) enum in scope.
impl Foo { fn f(self) {} }
fn main() -> i32 { return 0; }
Fix. The target must be a declared struct or enum in scope.
E0326 · Duplicate method in impl
Two methods in the same impl block share a name.
struct P {}
impl P { fn f(self) {} fn f(self) {} }
fn main() -> i32 { return 0; }
Fix. Rename one of the methods.
E0327 · Wrong call form
An associated function was called as an instance method (or an instance method via the type, or an enum variant was called like a function).
struct P { x: i32 }
impl P { fn make() -> P { return P { x: 0 }; } }
fn main() -> i32 { let p: P = P { x: 0 }; let _q: P = p.make(); return 0; }
Fix. Type::method() for associated, value.method() for instance.
E0328 · Mutable receiver required
A method declared with mut self is called on an immutable receiver.
struct P { x: i32 }
impl P { fn bump(mut self) { self.x = self.x + 1; } }
fn main() -> i32 { let p: P = P { x: 0 }; p.bump(); return 0; }
Fix. Bind the receiver as let mut (or via a mut place).
E0329 · Mixed element types in array literal
Elements of an array literal do not all share one type.
fn main() -> i32 { let _xs: [i32; 2] = [1, true]; return 0; }
Fix. Make every element the same type.
E0330 · Array literal length mismatch
An array literal has a different element count than its declared [T; N] length.
fn main() -> i32 { let _xs: [i32; 3] = [1, 2]; return 0; }
Fix. Match the literal's element count to the declared length.
E0331 · Indexing a non-array type
The [] index operator is applied to a value that is not an array.
fn main() -> i32 { let x: i32 = 5; return x[0 as usize]; }
Fix. Only index array (or array-like) values.
E0332 · Empty array literal
An empty array literal [] was written, which is not supported.
fn main() -> i32 { let _xs: [i32; 0] = []; return 0; }
Fix. Provide at least one element.
E0339 · Fill-array element type is not Copy
A fill-array literal [expr; N] has a non-Copy (owning / drop-carrying) element type. The fill expression is evaluated once and copied into every slot, which would make N elements share one owned resource and double-free when they are dropped.
struct Owner { id: i32 }
impl Owner { fn drop(mut self) {} }
fn mk() -> Owner { return Owner { id: 1 }; }
fn main() -> i32 { let _a: [Owner; 2] = [mk(); 2]; return 0; }
Fix. Use a Copy element type, or construct each element explicitly with [expr0, expr1, ...].
Control flow and matching
E0333 · Implicit return (function body ends with a tail expression)
A function body ends with an implicit tail expression instead of an explicit return; C+ function bodies never use a trailing value expression.
fn f() -> i32 { 42 }
fn main() -> i32 { return f(); }
Fix. Add an explicit return EXPR; (or ; after the closing } when the tail is unit-typed).
E0334 · Mutually-exclusive parameter ownership markers
A parameter carries two ownership markers that cannot combine, such as mut + move, or borrow with move/mut.
fn f(mut move x: i32) -> i32 { return x; }
fn main() -> i32 { return f(1); }
Fix. Keep only one marker: mut, move, or borrow — they are mutually exclusive.
E0335 · Use of a moved value
A non-Copy binding is read after it was moved (into a call, a move parameter, or a let y = x;). Flow-sensitive: a move only on a branch that returns / breaks does not poison the other path, and it also fires for non-Copy types whose Copy-ness depends on a generic payload.
struct P { x: i32 }
impl P { fn drop(mut self) {} }
fn echo(p: P) -> i32 { return p.x; }
fn main() -> i32 {
let p: P = P { x: 1 };
let r: i32 = echo(p);
return p.x;
}
Fix. Do not read after a move; clone the value first, or restructure so the move and the use are on disjoint paths.
E0337 · Cannot move out of a non-binding place
A move was attempted from something other than a whole binding (a struct field, an array slot, or a temporary); partial moves are deferred.
struct Inner { x: i32 }
impl Inner { fn drop(mut self) {} }
struct Outer { i: Inner }
fn take(move i: Inner) -> i32 { return i.x; }
fn main() -> i32 { let o: Outer = Outer { i: Inner { x: 1 } }; return take(o.i); }
Fix. Move a whole binding, or clone/copy the field into a local first.
E0338 · Destructor drop has the wrong signature
A drop method has a signature other than fn drop(mut self) (extra parameters, a return type, or a non-mut self receiver), or a drop was written on an enum.
struct B { x: i32 }
impl B { fn drop(self) {} }
fn main() -> i32 { return 0; }
Fix. Declare it exactly fn drop(mut self) — no extra parameters, no return type; enums get a compiler-synthesized destructor instead.
E0340 · Non-exhaustive match
A match on an enum does not cover every variant and has no catch-all arm.
enum M { A, B, C }
fn main() -> i32 { let m: M = M::A; return match m { M::A => 0 }; }
Fix. Add the missing arm or a _ => catch-all.
E0341 · Pattern type does not match the scrutinee
A match scrutinee is not an enum, a pattern names a different enum than the scrutinee, or a nested variant pattern appears in a payload position.
fn main() -> i32 { let x: i32 = 5; return match x { _ => 0 }; }
Fix. Match on an enum value, and make each pattern name the scrutinee's enum (payload patterns must be _ or a binding).
E0342 · Wrong number of payload values for a variant
A variant pattern or construction supplies a different number of payload values than the variant declares.
enum M { A(i32, i32) }
fn main() -> i32 { let m: M = M::A(1, 2); return match m { M::A(v) => v }; }
Fix. Match the variant's declared payload arity in both the pattern and the constructor.
E0345 · Use of a possibly-unassigned binding
A binding is read on a control-flow path where it is not definitely assigned.
fn main() -> i32 { let x: i32; return x; }
Fix. Initialize the binding on every control-flow path before reading it.
E0346 · Uninitialized let requires a type annotation
A let with no initializer has no type annotation, so there is nothing to infer the type from.
fn main() -> i32 { let x; x = 5; return x; }
Fix. Add a type annotation (let x: T;) or give the let an initializer.
E0347 · Irrefutable if let / while let pattern
An if let or while let uses a pattern that always matches (a bare binding or _), so the conditional form is pointless.
fn main() -> i32 {
if let x = 7 { return x; }
return 0;
}
Fix. Use a plain let (or loop) instead, or write a refutable variant pattern.
E0348 · guard let else block must diverge
The else block of a guard let falls through instead of diverging on every path.
enum Maybe { Some(i32), None }
fn main() -> i32 {
let m: Maybe = Maybe::Some(7);
guard let Maybe::Some(v) = m else { let x: i32 = 1; };
return v;
}
Fix. Make the else block diverge on every path (return / break / continue).
E0350 · guard let complement overlaps the success pattern
The explicit complement pattern in else |Pat| references the same enum variant as the success pattern, so the two overlap.
enum Maybe { Some(i32), None }
fn main() -> i32 {
let m: Maybe = Maybe::Some(7);
guard let Maybe::Some(v) = m else |Maybe::Some(_)| { return 0; };
return v;
}
Fix. Make the complement pattern cover only the cases the success pattern does not.
E0351 · guard let must bind at least one value
A guard let pattern binds no names, so there is nothing for it to extract.
enum Maybe { Some(i32), None }
fn main() -> i32 {
let m: Maybe = Maybe::Some(7);
guard let Maybe::None = m else { return 0; };
return 0;
}
Fix. Use if let for inspection-only, or write a pattern that binds a value.
E0352 · Multi-binding guard let is not supported
A guard let pattern binds more than one value; only single-binding patterns are supported.
enum Pair { Both(i32, i32) }
fn main() -> i32 {
let p: Pair = Pair::Both(1, 2);
guard let Pair::Both(a, b) = p else { return 0; };
return a;
}
Fix. Use one guard let per binding.
E0353 · break / continue outside a loop
A break or continue appears outside any loop body.
fn main() -> i32 { break; return 0; }
Fix. Move it into a loop body.
Ownership and borrowing
E0370 · Move and shared-borrow of the same binding in one call
A non-Copy binding is moved at one argument position while a sibling argument in the same call reads (shared-borrows) the same place.
struct B { x: i32 }
impl B { fn drop(mut self) { return; } }
fn drain(move b: B, n: i32) { return; }
fn peek(borrow b: B) -> i32 { return b.x; }
fn caller() {
let y: B = B { x: 1 };
drain(y, peek(y));
return;
}
In this minimal single-call form cpc reports the broader use-after-move error E0335; E0370 is the borrow checker's name for the move / shared-borrow conflict.
Fix. Split into two statements so the value is read before it is moved: let tmp = peek(y); drain(move y, tmp);
E0371 · Use of a possibly-moved binding
A non-Copy binding is moved on some control-flow branches but not others, then read at a point where it may already be moved (its merged state is MaybePartial).
struct B { x: i32 }
impl B { fn drop(mut self) { return; } }
fn sink(move b: B) { return; }
fn use_it(borrow b: B) -> i32 { return b.x; }
fn caller(c: bool) {
let y: B = B { x: 1 };
if c { sink(y); }
let z: i32 = use_it(y);
return;
}
Reported as E0335 in simple cases; E0371 specifically covers a use of a binding moved on only some control-flow paths.
Fix. Ensure every branch either moves or preserves the binding, or clone it before the branch: let y_owned = y.clone();
E0372 · Move of a binding while it is borrowed
A binding is moved while a live borrower still holds a borrow of it (or one of its sub-places) at an overlapping place.
struct B { x: i32 }
impl B { fn drop(mut self) { return; } }
fn longest(a: B, b: B) -> B {
if a.x > b.x { return a; }
return b;
}
fn drain(move b: B) { return; }
fn caller() {
let a: B = B { x: 1 };
let b: B = B { x: 2 };
let r: B = longest(a, b);
drain(a);
return;
}
In this minimal form cpc reports E0335; E0372 is the borrow checker's classification of moving a value while it is borrowed.
Fix. Drop the borrower before moving the value, or clone it if both bindings must outlive the move.
E0374 · Partial-place borrow conflict
A borrow of a place overlaps a sibling access to one of its sub-places (or vice versa) — a borrow of a place includes all of its sub-places.
struct Inner { v: i32 }
impl Inner { fn drop(mut self) { return; } }
struct Pair { left: Inner, right: Inner }
impl Pair { fn drop(mut self) { return; } }
fn write_pair(mut a: Pair, b: Inner) { return; }
fn caller() {
let p: Pair = Pair { left: Inner { v: 1 }, right: Inner { v: 2 } };
write_pair(p, p.left);
return;
}
A whole-place / sub-field overlap in one call is reported as E0337; E0374 is the borrow checker's partial-place conflict.
Fix. Split into two calls if the operations are independent, or restructure to operate on a single uniform place.
E0380 · Two exclusive borrows of the same place in one call
The same non-Copy binding is exclusively borrowed (mut) at two argument positions in a single call, but at most one exclusive borrow of a place can be live at a time.
struct B { x: i32 }
impl B { fn drop(mut self) { return; } }
fn modify_both(mut a: B, mut b: B) { return; }
fn caller() {
let y: B = B { x: 1 };
modify_both(y, y);
return;
}
Fix. Split into two calls, or borrow distinct sub-places (e.g. f(mut y.left, mut y.right)).
E0381 · Exclusive borrow with a concurrent shared read
A place is exclusively borrowed (mut) while a sibling argument shared-reads it in the same call, or a method is called on a receiver that is currently shared-borrowed.
struct B { x: i32 }
impl B { fn drop(mut self) { return; } }
fn write_thing(mut a: B, n: i32) { return; }
fn peek(borrow b: B) -> i32 { return b.x; }
fn caller() {
let y: B = B { x: 1 };
write_thing(y, peek(y));
return;
}
Fix. Split into two statements: let tmp = peek(y); write_thing(mut y, tmp);
E0382 · Move and exclusive borrow of the same binding in one call
The same non-Copy binding is exclusively borrowed (mut) at one argument position and moved at another in a single call; the exclusive borrow claims access for the whole call, which conflicts with the move's consumption.
struct B { x: i32 }
impl B { fn drop(mut self) { return; } }
fn write_and_take(mut a: B, move b: B) { return; }
fn caller() {
let y: B = B { x: 1 };
write_and_take(y, y);
return;
}
Fix. Split into two statements so the exclusive borrow and the move do not overlap.
E0383 · Read of an exclusively-borrowed place
A place (or a sub-place of it) is read while it is held in an exclusive borrow by a live borrower, including method calls on an exclusively-borrowed receiver.
struct B { x: i32 }
impl B { fn drop(mut self) { return; } }
fn cursor(mut b: B) -> B { return b; }
fn peek(borrow b: B) -> i32 { return b.x; }
fn caller() {
let v: B = B { x: 1 };
let cur: B = cursor(v);
let n: i32 = peek(v);
return;
}
Fix. Drop the exclusive borrower before reading the place, or restructure so the read happens before the borrow is established.
E0384 · Cannot infer which parameter the return borrows from
A function or method has at least one return rooted at a parameter, but the borrow checker cannot determine which parameter every return path derives from.
struct B { x: i32 }
impl B { fn drop(mut self) { return; } }
fn merge(a: B, b: B) -> B {
if a.x > 0 { return a; }
return B { x: 0 };
}
Fix. Annotate the signature explicitly with a borrow region, e.g. fn merge(a: borrow A B, ...) -> borrow A B.
E0503 · Interface impl missing a required method
An impl Type for Interface block omits a method that the interface declares.
interface Two { fn first(self) -> i32; fn second(self) -> i32; }
struct P { x: i32 }
impl P for Two { fn first(self) -> i32 { return 0; } }
fn main() -> i32 { return 0; }
Fix. Implement every method the interface declares.
E0504 · Interface impl declares a method the interface does not
An impl Type for Interface block contains a method that the interface does not declare.
interface One { fn a(self) -> i32; }
struct P { x: i32 }
impl P for One { fn a(self) -> i32 { return 0; } fn extra(self) -> i32 { return 1; } }
fn main() -> i32 { return 0; }
Fix. Move the extra method to an inherent impl Type { ... } block.
E0505 · Interface method signature mismatch
An impl method's signature does not match the interface's declared signature after substituting Self with the target type.
interface One { fn a(self) -> i32; }
struct P { x: i32 }
impl P for One { fn a(self) -> bool { return true; } }
fn main() -> i32 { return 0; }
Fix. Make the impl method's signature match the interface declaration exactly.
E0506 · Duplicate interface impl for the same type
Two impl Type for Interface blocks exist for the same (interface, type) pair; a type may have at most one impl of any given interface.
interface One { fn a(self) -> i32; }
struct P { x: i32 }
impl P for One { fn a(self) -> i32 { return 0; } }
impl P for One { fn a(self) -> i32 { return 1; } }
fn main() -> i32 { return 0; }
Fix. Remove the duplicate impl block.
E0507 · Orphan-rule violation for an interface impl
An impl Type for Interface block lives in a file that declares neither the interface nor the type; the orphan rule requires the impl to be co-located with one of them.
// in a third file that imports both Iface and Ty:
impl Ty for Iface { fn a(self) -> i32 { return 0; } }
Fix. Declare the impl in the same file as either the interface or the type.
E0508 · Self used outside an interface or impl body
The type Self is named where there is no surrounding interface or impl body to give it meaning.
fn loose(x: Self) -> i32 { return 0; }
fn main() -> i32 { return 0; }
Fix. Use a concrete type name, or move the code into an interface / impl body.
E0509 · Move of a field out of a Drop type
A non-Copy value is moved out of a field or index of a place whose type implements drop, which would let the destructor free the moved field a second time.
extern fn malloc(n: usize) -> *u8;
extern fn free(p: *u8);
struct Owned { ptr: *u8 }
impl Owned {
fn make() -> Owned { return Owned { ptr: unsafe { malloc(16 as usize) } }; }
fn drop(mut self) { unsafe { free(self.ptr); } return; }
}
struct Pair { a: Owned, b: Owned }
impl Pair {
fn drop(mut self) { unsafe { free(self.a.ptr); } unsafe { free(self.b.ptr); } return; }
}
fn main() -> i32 {
let p: Pair = Pair { a: Owned::make(), b: Owned::make() };
let q: Owned = p.a;
return 0;
}
Fix. Clone the field, or restructure so it is not owned by a Drop type.
E0510 · Unaccounted raw-pointer field in a Drop type
A struct has a raw-pointer field that is neither released in a drop (no releasing drop, or only via a helper) nor marked opaque.
extern fn malloc(n: usize) -> *u8;
struct Buf { ptr: *u8 }
fn main() -> i32 { return 0; }
Fix. Release it in drop (free(self.f)), or mark the field opaque if another owner frees it.
E0511 · Return type names a borrow region no parameter declares
A return type names a borrow region that no parameter declares, so the borrow it names has no provenance and the annotation is inert.
fn f(a: borrow A str) -> borrow Z str { return a; }
fn main() -> i32 { return 0; }
Fix. Add a same-region parameter, or drop the region.
E0512 · Returned borrow's region differs from the declared return region
A returned borrow is rooted at a parameter whose region differs from the region the signature declares for the return.
fn weird(a: borrow A str, b: borrow B str) -> borrow A str { return b; }
fn main() -> i32 { return 0; }
Fix. Return a borrow from a same-region parameter.
E0513 · Returning a str / T[] view of a local that drops
A returned str / T[] view is rooted at a function-local non-Copy owned value (directly or via as_str / as_slice, including inside a returned aggregate), so the view would dangle when that local is freed at return.
extern fn malloc(n: usize) -> *u8;
extern fn free(p: *u8);
struct Buf { ptr: *u8 }
impl Buf {
fn drop(mut self) { unsafe { free(self.ptr); } return; }
fn as_str(self) -> str { return unsafe { #str_from_raw_parts(self.ptr, 4 as usize) }; }
}
fn mk_buf() -> Buf { return Buf { ptr: unsafe { malloc(4 as usize) } }; }
fn bad() -> str {
let s: Buf = mk_buf();
return s.as_str();
}
Fix. Return an owned value (string / Vec[T]), or borrow from a parameter.
E0612 · Interpolated type does not implement ToText
A ${...} interpolation segment embeds a value whose type does not implement ToText (and is not a blessed/numeric type or an owned Text).
struct Point { x: i32, y: i32 }
fn main() -> i32 {
let p: Point = Point { x: 1, y: 2 };
let s = "point: ${p}";
return 0;
}
Fix. Implement ToText for the type, or interpolate a field that is already ToText-able.
E0613 · Owned string (Text) named without its import
An expression produces an owned string (via .to_text() or string interpolation) but the Text type is not in scope because stdlib/text was not imported.
fn f() -> i32 { let n: i32 = 1; let s = n.to_text(); return 0; }
Fix. Add import "stdlib/text"; borrowed str views need no import.
Modules, paths, and visibility
E0401 · Imported file not found
An import "..." string did not resolve to an existing .cplus file on disk.
import "./missing" as m;
fn main() -> i32 { return 0; }
Fix. Correct the import path (the compiler offers a did-you-mean for the closest existing filename), or create the file.
E0402 · Unknown import prefix
A prefix::Item path uses an as prefix that was never bound by an import declaration in this file.
import "ghost/widget" as g; // `ghost` is not a declared dependency
pub fn use_it() -> i32 { return g::value(); }
Needs a project: the import path's first segment names no dependency in Cplus.toml. A bare unknown name in code is reported as E0300/E0303 instead.
Fix. Add the matching import "./module" as prefix;, or fix the prefix to one that is imported.
E0403 · Private item accessed across a file boundary
A cross-file reference touched a function, type, field, method, const, static, type alias, or interface that is not marked pub in its declaring file.
import "./math" as math;
fn main() -> i32 { return math::square(7); }
Fix. Mark the item pub in its declaration to export it. (Requires an imported module; math.cplus declares fn square without pub.)
E0404 · Cyclic import dependency
The import graph contains a cycle, so the files mutually depend on each other and cannot be ordered.
import "./a" as a;
fn main() -> i32 { return 0; }
Fix. Break the cycle: factor the shared declarations into a third module that both files import. (Requires multiple files; here a.cplus imports b.cplus which imports a.cplus.)
E0405 · No such item in module
A prefix::name path (or duplicate as prefix) names an item that does not exist in the imported module at all, or two imports share an as prefix.
import "./lib" as lib;
fn main() -> i32 { return lib::nope(); }
Fix. Fix the name to one the module actually exports, or give each import a distinct as prefix. (Requires an imported module; lib.cplus has no item named nope.)
E0406 · Malformed or incomplete manifest
Cplus.toml failed to parse, is missing a required field, or names an unsupported edition.
[[[ not valid toml
Fix. Repair the TOML, supply the missing field, or set edition = "2026".
E0407 · Cannot read the manifest
An I/O error occurred while reading Cplus.toml (for example the file is unreadable or vanished mid-build).
[package]
name = "x"
Fix. Ensure Cplus.toml exists and is readable from the build directory.
E0408 · Both [[bin]] and [lib] declared
A single manifest declares both a binary target and a library target, which are mutually exclusive.
[package]
name = "both"
[[bin]]
name = "exe"
[lib]
Fix. A manifest is either an executable or a library; split it into two crates if you need both.
E0409 · fn main defined in a library target
A manifest that declares [lib] also defines a fn main, but a library has no entry point.
pub fn add(a: i32, b: i32) -> i32 { return a + b; }
fn main() -> i32 { return 0; }
Fix. Remove fn main, or use [[bin]] instead of [lib] if you meant to build an executable. (Requires a [lib] manifest.)
E0410 · Type in pub extern fn is not C-ABI compatible
A parameter or return type in a pub extern fn cannot cross the C function-call ABI (for example a str/slice fat pointer, a tagged enum, a non-#[repr(C)] struct, or a Drop type).
pub extern fn echo(s: str) -> i32 { return 0; }
fn main() -> i32 { return 0; }
Fix. Use C-representable types: pass a *u8 plus a usize length instead of a fat pointer, or mark structs #[repr(C)].
E0411 · restrict on a non-pointer parameter
The restrict marker was placed on a parameter whose type is not a raw pointer.
fn bad(restrict x: i32) -> i32 { return x; }
fn main() -> i32 { return bad(0); }
Fix. Only *T accepts restrict; remove it or change the parameter to a raw-pointer type.
E0412 · Unsupported crate-type value
A [lib] crate-type value is not one of the accepted kinds.
[package]
name = "mathlib"
[lib]
crate-type = "rlib"
Fix. Use one of staticlib, cdylib, or both.
Generics and bounds
E0500 · Cannot infer a type parameter
A declared generic parameter never appears in an argument position, so the compiler cannot infer it from the call's arguments.
fn make[T]() -> i32 { return 0; }
fn main() -> i32 { return make(); }
Fix. Supply the name::[T1, T2](...) turbofish, or use the parameter in an argument so inference can pin it.
E0501 · Wrong type-argument count
A turbofish or generic instantiation supplied a different number of type arguments than the generic parameter list declares (including supplying any on a non-generic item).
fn id[T](x: T) -> T { return x; }
fn main() -> i32 { let a: i32 = id::[i32, bool](7); return a; }
Fix. Match the generic parameter list: supply exactly as many type arguments as the declaration has.
E0502 · Bound not satisfied
A concrete type argument does not satisfy a declared bound on its type parameter (also fired for a !Send / !Sync type passed where Send / Sync is required across threads).
fn max[T: Ord](a: T, b: T) -> T { return a; }
struct Point { x: i32 }
fn main() -> i32 { let p: Point = Point { x: 0 }; let r: Point = max(p, p); return 0; }
Fix. T: Ord requires impl Point for Ord; provide the impl, or for thread-crossing use unsafe impl T for Send {} when the marker holds.
Unsafe, FFI, and intrinsics
E0700 · Tuple literal with fewer than two elements
A tuple literal was written with zero or one element, but () is the unit value and (x) is grouping, so a tuple must have at least two elements.
fn main() -> i32 {
let t = (1,);
return 0;
}
Fix. Add a second element, or use ()/(x) if you meant the unit value or a parenthesized expression.
E0801 · Operation (or unsafe fn call) requires unsafe
A raw-pointer dereference, extern/unsafe fn call, atomic op, inline #asm, static mut access, or similar invariant-breaking operation appeared outside an enclosing unsafe { ... } block.
unsafe fn danger() -> i32 { return 1; }
fn main() -> i32 { let d: i32 = danger(); return d; }
Fix. Wrap it in unsafe { ... }.
E0821 · Cannot take the address of a generic function
A generic function name was used as a function-pointer value without specifying its type parameters, so there is no single monomorphized instance to point at.
fn identity[T](x: T) -> T { return x; }
fn main() -> i32 { let f: fn(i32) -> i32 = identity; return 0; }
Fix. Specify the type parameters at the take-address site (turbofish), so a concrete instance is selected.
E0905 · Unknown compiler intrinsic #name
A #name(...) intrinsic is not recognized, or a compiler builtin was called as a bare name instead of with the # sigil.
fn main() -> i32 { return #not_a_real_intrinsic(1); }
Fix. Fix the typo; check the intrinsics list, and spell builtins with the # sigil.
Compile-time builtins
E0870 · #include_bytes/#include_str file not found
The path passed to #include_bytes/#include_str could not be resolved or read relative to the including file at compile time.
fn main() -> i32 { let s: str = #include_str("missing.txt"); return 0; }
Fix. Correct the path (it is resolved relative to the file containing the call) or create the missing file.
E0871 · #include_bytes/#include_str argument must be a string literal
The path argument to #include_bytes/#include_str was not a string literal, so the file cannot be resolved at compile time.
fn main() -> i32 { let s: str = #include_str(some_var); return 0; }
Fix. Pass a string literal path, e.g. #include_str("data.txt").
E0872 · #include_bytes/#include_str file exceeds the 64 MiB cap
The file embedded via #include_bytes/#include_str is larger than the 64 MiB sanity limit the compiler will read at compile time.
fn main() -> i32 { let b: *const [u8; 0] = #include_bytes("huge.bin"); return 0; }
// where huge.bin is larger than 64 MiB
Fix. Embed a smaller file, or load the data at runtime instead of compile time.
E0873 · SIMD lane/shift index must be a literal
A SIMD .lane(...) or shift method was given a non-literal u32 index, but the lane/shift count must be a compile-time literal.
fn main() -> i32 {
let v: f32x4 = f32x4::splat(1.0f32);
let mut i: u32 = 0 as u32;
let x: f32 = v.lane(i);
return 0;
}
Fix. Pass a literal u32 index, e.g. v.lane(0 as u32).
E0874 · SIMD lane/shift index out of range
A SIMD .lane(...) index or shift count is at or beyond the vector's lane count (or the per-lane bit width for shifts).
fn main() -> i32 {
let v: f32x4 = f32x4::splat(1.0f32);
let x: f32 = v.lane(7 as u32);
return 0;
}
Fix. Use an index within range (0..lane_count), or a shift count below the lane bit width.
E0875 · #include_str file is not valid UTF-8
The file embedded via #include_str contains bytes that are not valid UTF-8; the message reports the byte offset of the first invalid byte.
fn main() -> i32 { let s: str = #include_str("bad.bin"); return 0; }
// where bad.bin contains a stray 0xFF byte
Fix. Use #include_bytes for binary data, or fix the file so it is valid UTF-8.
E0876 · #env("X"): env var not set at compile time
The environment variable named in #env("NAME") was not set in the compiler's own process environment when cpc was invoked.
fn main() -> i32 {
let _v: str = #env("CPC_TEST_DEFINITELY_MISSING_99");
return 0;
}
Fix. Set the variable when invoking cpc, or pick a different default.
E1000 · Missing stdlib type for gen fn / Iterator::next
A gen fn was used without Iterator[T] from stdlib/iterator in scope (or Iterator::next was reached without Option[T] from stdlib/option), so the compiler cannot synthesize the iterator/option type.
gen fn count_up(n: i32) -> i32 {
let mut i: i32 = 1;
while i <= n { yield i; i = i +% (1 as i32); }
return;
}
fn main() -> i32 { return 0; }
// fails when `import "stdlib/iterator"` is absent
Fix. Add import "stdlib/iterator" (and import "stdlib/option") so the required generic types are available.
E1001 · yield outside a gen fn body
A yield expression appeared outside the body of a gen fn, where there is no iterator to produce values into.
fn main() -> i32 {
yield 1;
return 0;
}
Fix. Move the yield into a gen fn body, or remove it.
Real-time contracts
E0900 · Borrow-shaped parameter in an async fn
An async fn parameter is borrow-shaped (str / T[]) or a mut-bound non-Copy value (pointer-passed), which may dangle once a borrow lives across an await.
pub struct Future[T] { pub opaque handle: *u8 } async fn fetch(url: str) -> i32 { return 0 as i32; }
Fix. Use Text / Vec[T] instead of str / T[], or move ownership in / bind locally instead of mut.
E0901 · #[no_alloc] violation (or await outside async fn)
A #[no_alloc] function or a callee heap-allocates, builds an interpolated Text, runs allocating drop-glue at scope exit, or calls something not proven non-allocating; the code reused for the contract also rejects await outside an async fn.
fn helper(x: i32) -> i32 { return x +% 1; }
#[no_alloc] fn caller(x: i32) -> i32 { return helper(x); }
fn main() -> i32 { return 0; }
Fix. Remove the allocation (or the offending call), drop the #[no_alloc] contract, or mark the callee #[no_alloc].
E0902 · await of a non-Future expression
An await is applied to an expression that does not evaluate to a Future[T].
pub struct Future[T] { pub opaque handle: *u8 } async fn bad() -> i32 { let x: i32 = await (7 as i32); return x; }
Fix. Await a Future[T] value (the result of calling an async fn).
E0903 · Invalid compiler-intrinsic call shape
A #name(...) intrinsic (such as #selector or #compile_shader) is called with the wrong number/kind of arguments, stray type arguments, or an unsupported -> T return ascription.
fn main() -> i32 {
let n: i32 = 42;
let p: *u8 = #selector(n);
return 0;
}
Fix. Call the intrinsic with the exact argument shape it documents (e.g. #selector takes one string literal).
E0904 · #compile_shader target or toolchain error
A #compile_shader(...) names an unsupported target, or the shader toolchain invocation (xcrun metal / metallib) failed or produced no output.
fn main() -> i32 {
let p: *u8 = #compile_shader("k.spv", "spirv") as *u8;
return 0;
}
Fix. Use a supported target ("msl") and make sure the shader source compiles with the toolchain.
E0906 · #[bounded_recursion] violation
The call graph of a #[bounded_recursion] function cycles back to itself, directly or transitively.
#[bounded_recursion] fn r(x: i32) -> i32 {
if x == 0 { return 0; }
return r(x -% 1);
}
fn main() -> i32 { return 0; }
Fix. Break the recursion so the call graph no longer cycles back to the function.
E0907 · #[no_block] violation
A #[no_block] function or a callee calls a blocking primitive directly or transitively, or an extern/user function not proven non-blocking.
extern fn sleep(secs: u32) -> u32;
#[no_block] fn f() { unsafe { sleep(1); } return; }
fn main() -> i32 { return 0; }
Fix. Use a non-blocking API, or mark the callee #[no_block] if it is known not to block.
E0908 · #[max_stack(N)] exceeded
A function's estimated stack frame (parameters plus locals with known types) is larger than the #[max_stack(N)] byte budget.
#[max_stack(64)] fn f() { let buf: [u8; 100] = [0u8; 100]; return; }
fn main() -> i32 { return 0; }
Fix. Shrink locals/parameters, or raise the N budget.
E0909 · Non-asm statement in a #[naked] function
A #[naked] function body contains a statement (or a value tail) other than inline #asm(...); no prologue/epilogue is emitted, so there is no stack frame to use.
#[naked]
fn bad() -> i64 { let x: i64 = 1; return x; }
fn main() -> i32 { return 0; }
Fix. Keep a #[naked] body inline assembly only; move other code into a normal function the asm calls.
Attributes
E0354 · Unknown attribute
An attribute name is not recognized.
#[tset] fn x() { return; }
Fix. Fix the typo (the compiler suggests a did-you-mean fix).
E0355 · Bad attribute argument shape
An attribute is given the wrong arguments — too many, too few, or the wrong literal kind for what the attribute expects.
#[repr] struct P { x: i32 }
Fix. Supply the exact argument shape the attribute expects (e.g. #[repr(C)]).
E0356 · Wrong attribute target
An attribute is placed on a kind of item it does not apply to; some attributes are function-only, others struct-only.
#[test] struct X { v: i32 }
Fix. Move the attribute to the item kind it is valid on.
E0357 · Duplicate attribute
An attribute that must be unique appears more than once on the same item.
#[test] #[test] fn x() { return; }
Fix. Remove the duplicate; the attribute may appear only once.
E0358 · Invalid #[test] function signature
A #[test] function does not have the signature fn() -> i32 or fn() — it takes parameters or returns some other type.
#[test] fn t(n: i32) { return; }
fn main() -> i32 { return 0; }
Fix. Give the test function the signature fn() -> i32 or fn() (no parameters).
E0359 · #[test] function cannot be pub
A #[test] function is marked pub; tests are project-internal helpers discovered by the runner, never part of the exported API.
#[test] pub fn t() { return; }
fn main() -> i32 { return 0; }
Fix. Remove pub from the test function.
E0890 · Duplicate #asm operand name
Two operands of an inline #asm(...) share the same operand name.
fn f(a: i64) { unsafe { #asm("mov {a}, {a}", a = in(reg) a, a = in(reg) a); } return; }
fn main() -> i32 { return 0; }
Fix. Give each #asm operand a distinct name.
E0892 · Non-register-sized #asm operand
An inline #asm(...) operand has a type that does not fit a register; only integer, pointer, and bool operands are allowed.
struct Owned { x: i32 } impl Owned { fn drop(mut self) { return; } } fn f(a: Owned) { unsafe { #asm("nop {a}", a = in(reg) a); } return; }
fn main() -> i32 { return 0; }
Fix. Pass a register-sized scalar (integer, pointer, or bool) instead of an aggregate.
E0893 · #asm reg operand has no template placeholder
A compiler-chosen (reg) inline-asm operand has no matching {name} placeholder in the template, so the template cannot name the register the compiler picked.
fn f(a: i64) { unsafe { #asm("nop", a = in(reg) a); } return; }
fn main() -> i32 { return 0; }
Fix. Reference the operand by its {name} placeholder in the template, or use an explicit-register operand.
E0895 · #asm out/inout operand must be a variable
An out or inout inline-asm operand binds to a general place (a field or index) rather than a plain variable; those are not yet supported.
struct P { x: i64 }
fn f(mut p: P, a: i64) {
unsafe { #asm("mov {o}, {a}", o = out(reg) p.x, a = in(reg) a); }
return;
}
fn main() -> i32 { return 0; }
Fix. Write the output into a mut variable, then copy it into the field/index afterward.
const / static / char
E0X30 · const/static initializer is not a literal
A const or static initializer used a non-literal shape (arithmetic, an identifier, a call, or a generic struct literal); const is literal-only and static allows only literals, #zero::[T](), array literals/fills, or non-generic struct literals of such.
const FOO: i32 = 1 + 2;
Fix. Use a literal initializer (or an accepted static shape such as #zero::[T]() or an array/struct literal of literals).
E0X33 · Read of static mut requires unsafe
A static mut was read outside an enclosing unsafe { ... } block, where the borrow checker cannot prove absence of data races on module-scope mutable state.
static mut COUNTER: i32 = 0;
fn main() -> i32 { return COUNTER; }
Fix. Wrap the read in unsafe { ... }.
E0X34 · Write to static mut requires unsafe
A static mut was written outside an enclosing unsafe { ... } block, where the borrow checker cannot prove absence of data races on module-scope mutable state.
static mut COUNTER: i32 = 0;
fn main() -> i32 { COUNTER = 5; return 0; }
Fix. Wrap the write in unsafe { ... }.
E0X36 · Unknown const array length
An array length named a const that is not in scope, is not an integer, is negative, or exceeds the u32 maximum.
fn main() -> i32 { let a: [i32; NOPE] = [0; 1]; return a[0]; }
Fix. Use an integer literal, or a const in scope with a non-negative integer literal initializer.
Targets and packages
E0852 · Import names an undeclared dependency (or no manifest is reachable)
An import's first path segment looks like a package name but is not a declared [dependencies] entry in Cplus.toml (or there is no reachable manifest at all, so the bare package/... import has nothing to resolve against).
// bare.cplus, compiled with `cpc --emit-obj bare.cplus` and no Cplus.toml in reach:
import "stdlib/atomic" as atomic;
fn f() -> i32 { return 0; }
// -> [E0852] first segment `stdlib` is not a declared dependency
Fix. Add package = "*" to [dependencies] in Cplus.toml, or change the import to ./path for a file-relative one.
E0853 · Bare import that is neither file-relative nor a declared dependency
An import path is not prefixed with ./ or ../ (so it is not file-relative) and its first segment does not match any declared [dependencies] entry, so the resolver cannot classify it.
import "bare" as b;
fn main() -> i32 { return 0; }
// -> [E0853] bare import `bare` — paths must start with `./`/`../` or match a `[dependencies]` entry
Fix. Use ./bare for a file-relative import, or add bare to [dependencies] in Cplus.toml for a vendor import.
E0854 · Vendor package missing its Cplus.toml
A [dependencies] entry resolves to a vendor/<name>/ directory that has no Cplus.toml, so the vendor package's manifest cannot be loaded.
# consumer Cplus.toml
[package]
name = "app"
[dependencies]
foo = "*"
# but vendor/foo/Cplus.toml does not exist
# -> [E0854] vendor package `foo` is missing `Cplus.toml`
Fix. Create vendor/<name>/Cplus.toml for the dependency, or remove the [dependencies] entry.
E0855 · Vendor package name does not match its directory
A vendor package's Cplus.toml declares a [package].name that differs from the vendor/<name>/ directory it lives in.
# vendor/foo/Cplus.toml
[package]
name = "bar" # but the directory is vendor/foo/
# -> [E0855] declares name `bar` but lives in `vendor/foo/`
Fix. Make [package].name match the directory name (a vendor package's name must equal its directory).
E0857 · Invalid dependency name
A [dependencies] key does not match [a-z][a-z0-9_]* (it contains dots, slashes, or uppercase), so the first segment of an import path would be ambiguous.
[package]
name = "x"
[dependencies]
Stdlib = "*"
# -> [E0857] dependency name `Stdlib` must match `[a-z][a-z0-9_]*`
Fix. Rename the dependency key to a lowercase identifier (no dots, slashes, or uppercase).
E0858 · Import path carries a .cplus extension
An import path ends in .cplus, but Phase 2 imports are extension-less, so the trailing extension is rejected.
import "utils/math.cplus" as math;
fn main() -> i32 { return 0; }
// -> [E0858] import has a `.cplus` extension — drop it
Fix. Drop the .cplus extension from the import path (the compiler offers a machine-applicable suggestion).
E0859 · Vendor import escapes its src/ directory
A vendor import path contains a .. segment, which would let a package reach files outside its own src/ directory — disallowed for security.
import "utils/../escape" as e;
fn main() -> i32 { return 0; }
// -> [E0859] vendor import contains `..` — packages cannot reach outside their own `src/`
Fix. Remove the .. segment; a package may only import files within its own src/ tree.
E0860 · A Send / Sync impl that omits unsafe
A Send or Sync marker is implemented with a bare impl (no unsafe), or with a non-empty body — both are rejected because the marker is an unverifiable thread-safety promise that must be a method-less unsafe impl.
struct Handle { opaque p: *u8 }
impl Handle for Send {}
fn main() -> i32 { return 0; }
// -> [E0860] `Send` is an unsafe assertion — write `unsafe impl Handle for Send {}`
Fix. Write unsafe impl T for Send {} — the marker is a promise you make.
E0861 · unsafe on an impl that is not a Send / Sync marker
An impl block carries unsafe but the interface being implemented is something other than the Send / Sync markers, where unsafe is meaningless.
interface Greet { fn hi(self) -> i32; }
struct S { x: i32 }
unsafe impl S for Greet { fn hi(self) -> i32 { return self.x; } }
fn main() -> i32 { return 0; }
// -> [E0861] `unsafe impl` applies only to the `Send` / `Sync` markers
Fix. Remove unsafe; it applies only to those two markers.
E0862 · Host vs target triple mismatch
A dependency declares bundled binaries but its [link].triples does not include the triple actually being linked (the host triple for a native build, or the selected --target's artifact triple for a cross build), so no matching prebuilt artifact exists.
# vendor/foo/Cplus.toml
[package]
name = "foo"
[link]
bundled = ["libfoo.a"]
triples = ["aarch64-apple-darwin"]
# linking on/ for a triple not in that list:
# -> [E0862] package `foo` does not ship a build for host/target triple `<triple>`
Fix. Add the host/target triple to [link].triples and ship the matching binaries, or build the package from source for that triple.
E0863 · [link].bundled set without [link].triples
A manifest's [link].bundled lists prebuilt binaries but [link].triples is empty, so the compiler cannot tell which host triples those binaries are built for.
# vendor/foo/Cplus.toml
[package]
name = "foo"
[link]
bundled = ["libfoo.a"]
# no triples = [...]
# -> [E0863] `[link].bundled` is non-empty but `[link].triples` is empty
Fix. Declare the host triples your bundled binaries target, e.g. triples = ["aarch64-apple-darwin"].
E0864 · [link] extra-objects entry not found
A [link].extra-objects path (resolved relative to the manifest) does not exist on disk, caught before clang is invoked so the user gets a clean diagnostic instead of a linker error.
[package]
name = "missing-obj"
[[bin]]
name = "missing-obj"
path = "src/main.cplus"
[link]
extra-objects = ["does-not-exist.o"]
# -> [E0864] [link] extra-objects entry `does-not-exist.o` not found
Fix. Provide the object file at the declared path, or remove the entry from [link].extra-objects.
E0865 · [link] ${VAR} not set and has no fallback
A ${VAR} reference in [link].search-paths or [link].extra-objects names an environment variable that is unset at manifest-parse time and the reference carries no :-default fallback.
[package]
name = "x"
[link]
search-paths = ["${CPLUS_DEFINITELY_UNSET_VAR}/lib"]
# with the var unset:
# -> [E0865] cannot expand `${CPLUS_DEFINITELY_UNSET_VAR}/lib` in `[link]`
Fix. Set the variable, or give a default with ${VAR:-/path} (caught at manifest parse time).
E0866 · A stdlib module the target lacks was imported
An import names a stdlib module excluded from the selected target's package profile — on an embedded target (e.g. esp32-xtensa) the POSIX half (thread, net, fs, the async executor/reactor, etc.) is unavailable.
import "stdlib/thread" as m;
pub fn f() -> i32 { return 0; }
// compiled with `cpc check --target esp32-xtensa`
// -> [E0866] import `stdlib/thread` is not available on target `esp32-xtensa`
Fix. On an embedded target the POSIX modules are unavailable; use espidf for the embedded equivalents.
E0867 · async fn on a 32-bit target
An async fn is checked against a target whose pointer width is under 64 bits; the async runtime (reactor plus coroutine frames) is 64-bit-only today.
pub fn helper() -> i32 { return 1; }
async fn fetch() -> i32 { return helper(); }
fn main() -> i32 { return 0; }
// compiled with `cpc check --target esp32-xtensa`
// -> [E0867] async functions are not supported on 32-bit target `esp32-xtensa`
Fix. The coroutine runtime is 64-bit only; restructure without async on that target.
Warnings
W0001 · sum() / product() over narrow integer SIMD lanes silently wraps
A horizontal sum() or product() over integer SIMD lanes narrower than 32 bits returns that same narrow lane type, which cannot hold the reduction of more than a couple of near-max lanes, so the result silently wraps.
fn main() -> i32 {
let a: i8x16 = i8x16::splat(50i8);
let prod: i8x16 = a.mul(i8x16::splat(50i8));
return prod.sum() as i32;
}
// -> W0001 `sum` over narrow integer lanes (`i8x16`) silently wraps
Fix. .widen() the lanes first, or use simd/integer::dot_i32.
W0002 · Conditionally-freed raw-pointer field in a Drop type
A raw-pointer field in a Drop type is freed inside drop only under some condition, so the compiler cannot prove the release always runs on every owning path.
struct Cell { p: *u8 }
impl Cell for Drop {
fn drop(self) {
if some_condition() { free(self.p); } // freed only conditionally
}
}
// -> W0002 raw-pointer field `p` is freed only conditionally in `drop`
Fix. Confirm it frees on every owning path (expected for refcounted types).
W0003 · [[bin]] [link] libs / frameworks ignored
A [[bin]] package declares its own top-level [link] libs / frameworks, but those are read only when a package is a dependency of another — a [[bin]] is never a dependency, so they are ignored when building the binary.
[package]
name = "app"
[[bin]]
name = "app"
path = "src/main.cplus"
[link]
libs = ["boguslib"]
# -> W0003 `[link] libs` on a `[[bin]]` package is ignored when building the binary
Fix. Move them under [[bin]] libs / frameworks (top-level [link] libs apply only when the package is a dependency).