pagurus uses pragma annotations to specify lifetime constraints, drop functions, and borrow management. These annotations guide the borrow checker's analysis and enable move semantics for resource-owning types.
Explicitly release a borrow before its natural scope end (mirrors Rust drop(borrow)):
#pragma pagurus borrow_end(p)This tells the checker that the borrow through pointer p ends at this point, even though p may still be in scope. Useful for manually resolving borrow conflicts.
Place immediately before a function declaration. Space-separated tokens represent pointer parameter lifetimes; comma-grouped tokens represent struct parameter lifetimes.
Both params constrain the return (lifetime 'a for all):
#pragma pagurus 'a 'a -> 'a
char *func1(char *a, char *b);Only the first param constrains the return (lifetime 'a):
#pragma pagurus 'a 'b -> 'a
int *get_x(int *x, int *y);Comma-grouped syntax 'b,'a indicates a struct parameter instantiated with lifetimes 'b (first) and 'a (second) from the struct's declaration:
#pragma pagurus 'b,'a -> 'b
char *get_data(struct Buf buf);The checker resolves which field is returned by matching lifetime 'b to the struct's field annotations (see section 4).
Backward compatible with earlier versions:
#pragma pagurus lifetime(get_ptr, 0)This annotation indicates that the return value's lifetime is tied to parameter 0.
Declare the struct's lifetime parameters and each field's lifetime:
#pragma pagurus 'a 'b
struct Buf {
#pragma pagurus 'a
const char *data; /* lifetime 'a */
#pragma pagurus 'b
char *scratch; /* lifetime 'b */
};Validation rules:
- Field with undeclared lifetime → error: "unknown lifetime 'e' in field ..."
- Declared lifetime parameter with no field → error: "declared but not bound 'c' ..."
All declared lifetimes must be used, and all field lifetimes must be declared.
Designates the next function declaration as the required destructor for a C struct or typedef type:
#pragma pagurus drop(TypeName)
void destructor_fn(TypeName value);Requirements:
TypeNamemay be a struct tag name OR a typedef name- The drop handler must:
- Return
void - Take exactly one parameter of type
T
- Return
- Invalid signatures are reported as errors and not registered
Named struct (tag name):
#pragma pagurus drop(StrStruct)
void str_free(struct StrStruct s);Using a typedef name:
typedef struct StrStruct { ... } StrType;
#pragma pagurus drop(StrType)
void str_type_free(StrType s);Any local variable of a drop-annotated type that goes out of scope without the drop function being called triggers E020[missing-drop]:
| Plugin flags | E020 severity | Effect |
|---|---|---|
-fplugin= only |
error | No automatic injection; the drop call must be written explicitly in source |
-fplugin= -fpass-plugin= |
warning | IR pass (PagurusDropPass) auto-injects the drop call into the binary |
Drop-annotated types have move semantics — assignment transfers ownership:
#pragma pagurus drop(StrStruct)
void str_free(struct StrStruct s);
void example(void) {
struct StrStruct a = str_with_cap(64);
struct StrStruct b = a; // ownership moves to b — a is now Moved
str_free(a); // error: E019[use-after-move]
str_free(b); // OK
}Structs without drop annotations are copy-able and can be freely assigned without transferring ownership.
For function declarations with exactly one "significant" parameter and a pointer return type, the checker automatically infers the return constraint without requiring an explicit annotation.
A parameter is "significant" when it is:
- A pointer parameter (
T *), or - A struct parameter passed by value where the struct has exactly one declared lifetime parameter
Automatically inferred (no annotation needed):
char *first_char(char *s);Redundant annotation (emits warning: "can be elided"):
#pragma pagurus 'a -> 'a
char *dup(char *s);Single-lifetime struct (annotation can be elided):
#pragma pagurus 'b
struct Buf { #pragma pagurus 'b char *scratch; };
#pragma pagurus 'a -> 'a // Warning: can be elided
char *get_data(struct Buf buf);The single-lifetime struct annotation itself also warns: "explicit lifetime declaration for struct 'Buf' can be elided".
For detailed information about specific error codes (E001–E021), see the main README.md.