From 64c128756d4e61f2660fd8f81ce73cae22fe3236 Mon Sep 17 00:00:00 2001
From: Vincent Lafeychine <vincent.lafeychine@proton.me>
Date: Thu, 2 May 2024 20:22:35 +0200
Subject: [PATCH] clippy: Fix must_use_candidate

---
 rr_frontend/.cargo/config.toml                |  1 -
 rr_frontend/attribute_parse/src/parse.rs      | 12 +++
 rr_frontend/radium/src/code.rs                | 12 +++
 rr_frontend/radium/src/coq.rs                 |  5 ++
 rr_frontend/radium/src/specs.rs               | 86 +++++++++++++++++++
 rr_frontend/rrconfig/src/launch.rs            |  1 +
 rr_frontend/rrconfig/src/lib.rs               | 25 ++++++
 .../src/environment/borrowck/facts.rs         |  4 +
 .../src/environment/borrowck/regions.rs       |  1 +
 .../translation/src/environment/loops.rs      | 12 +++
 .../mir_analyses/initialization.rs            |  3 +
 .../src/environment/mir_sets/local_set.rs     |  2 +
 .../src/environment/mir_sets/place_set.rs     |  5 ++
 .../src/environment/mir_utils/real_edges.rs   |  2 +
 .../translation/src/environment/mod.rs        |  1 +
 .../src/environment/polonius_info.rs          | 30 +++++++
 .../translation/src/environment/procedure.rs  | 15 ++++
 17 files changed, 216 insertions(+), 1 deletion(-)

diff --git a/rr_frontend/.cargo/config.toml b/rr_frontend/.cargo/config.toml
index d8cc38de..60f51a34 100644
--- a/rr_frontend/.cargo/config.toml
+++ b/rr_frontend/.cargo/config.toml
@@ -32,7 +32,6 @@ rustflags = [
     "-Aclippy::string_lit_as_bytes",
 
     # clippy::pedantic
-    "-Aclippy::must_use_candidate",
     "-Aclippy::needless_continue",
     "-Aclippy::needless_pass_by_value",
     "-Aclippy::redundant_closure_for_method_calls",
diff --git a/rr_frontend/attribute_parse/src/parse.rs b/rr_frontend/attribute_parse/src/parse.rs
index aee9f8a1..056ae9b3 100644
--- a/rr_frontend/attribute_parse/src/parse.rs
+++ b/rr_frontend/attribute_parse/src/parse.rs
@@ -119,6 +119,7 @@ pub struct ParseBuffer {
 }
 
 impl ParseBuffer {
+    #[must_use]
     pub fn new(stream: &rustc_ast::tokenstream::TokenStream) -> Self {
         // TODO; maybe avoid the cloning
         let trees: Vec<TokenTree> = stream.trees().cloned().collect();
@@ -441,6 +442,7 @@ pub struct LitStr {
 }
 
 impl LitStr {
+    #[must_use]
     pub fn value(&self) -> String {
         self.sym.to_string()
     }
@@ -478,6 +480,7 @@ where
 }
 
 impl Ident {
+    #[must_use]
     pub fn value(&self) -> String {
         self.sym.to_string()
     }
@@ -625,6 +628,7 @@ mod value {
     }
 }
 
+#[must_use]
 pub fn xid_ok(symbol: &str) -> bool {
     let mut chars = symbol.chars();
     let first = chars.next().unwrap();
@@ -647,6 +651,7 @@ pub struct BigInt {
 }
 
 impl BigInt {
+    #[must_use]
     pub const fn new() -> Self {
         Self { digits: Vec::new() }
     }
@@ -716,6 +721,7 @@ pub struct Punctuated<T, P> {
 
 impl<T, P> Punctuated<T, P> {
     /// Creates an empty punctuated sequence.
+    #[must_use]
     pub const fn new() -> Self {
         Self {
             inner: Vec::new(),
@@ -725,6 +731,7 @@ impl<T, P> Punctuated<T, P> {
 
     /// Determines whether this punctuated sequence is empty, meaning it
     /// contains no syntax tree nodes or punctuation.
+    #[must_use]
     pub fn is_empty(&self) -> bool {
         self.inner.len() == 0 && self.last.is_none()
     }
@@ -733,11 +740,13 @@ impl<T, P> Punctuated<T, P> {
     ///
     /// This is the number of nodes of type `T`, not counting the punctuation of
     /// type `P`.
+    #[must_use]
     pub fn len(&self) -> usize {
         self.inner.len() + usize::from(self.last.is_some())
     }
 
     /// Borrows the first element in this sequence.
+    #[must_use]
     pub fn first(&self) -> Option<&T> {
         self.iter().next()
     }
@@ -748,6 +757,7 @@ impl<T, P> Punctuated<T, P> {
     //}
 
     /// Borrows the last element in this sequence.
+    #[must_use]
     pub fn last(&self) -> Option<&T> {
         self.iter().next_back()
     }
@@ -850,6 +860,7 @@ impl<T, P> Punctuated<T, P> {
 
     /// Determines whether this punctuated sequence ends with a trailing
     /// punctuation.
+    #[must_use]
     pub fn trailing_punct(&self) -> bool {
         self.last.is_none() && !self.is_empty()
     }
@@ -858,6 +869,7 @@ impl<T, P> Punctuated<T, P> {
     /// punctuation.
     ///
     /// Equivalent to `punctuated.is_empty() || punctuated.trailing_punct()`.
+    #[must_use]
     pub const fn empty_or_trailing(&self) -> bool {
         self.last.is_none()
     }
diff --git a/rr_frontend/radium/src/code.rs b/rr_frontend/radium/src/code.rs
index cc007ab5..bfb132f7 100644
--- a/rr_frontend/radium/src/code.rs
+++ b/rr_frontend/radium/src/code.rs
@@ -95,6 +95,7 @@ impl Display for RustType {
 }
 
 impl RustType {
+    #[must_use]
     pub fn of_type(ty: &Type<'_>, env: &[Option<LiteralTyParam>]) -> Self {
         info!("Translating rustType: {:?}", ty);
         match ty {
@@ -297,6 +298,7 @@ pub enum Expr {
 }
 
 impl Expr {
+    #[must_use]
     pub fn with_optional_annotation(e: Self, a: Option<Annotation>, why: Option<String>) -> Self {
         match a {
             Some(a) => Self::Annot {
@@ -624,6 +626,7 @@ impl Stmt {
     }
 
     /// Annotate a statement with a list of annotations
+    #[must_use]
     pub fn with_annotations(mut s: Self, a: Vec<Annotation>, why: Option<String>) -> Self {
         for annot in a {
             s = Self::Annot {
@@ -753,6 +756,7 @@ fn make_lft_map_string(els: Vec<(String, String)>) -> String {
 impl FunctionCode {
     const INITIAL_BB: usize = 0;
 
+    #[must_use]
     pub fn caesium_fmt(&self) -> String {
         // format args
         let format_stack_layout = |layout: std::slice::Iter<'_, (String, SynType)>| {
@@ -825,6 +829,7 @@ impl FunctionCode {
     }
 
     /// Get the number of arguments of the function.
+    #[must_use]
     pub fn get_argument_count(&self) -> usize {
         self.stack_layout.iter_args().len()
     }
@@ -840,6 +845,7 @@ pub struct StackMap {
 }
 
 impl StackMap {
+    #[must_use]
     pub fn new() -> Self {
         Self {
             arg_map: Vec::new(),
@@ -866,6 +872,7 @@ impl StackMap {
         true
     }
 
+    #[must_use]
     pub fn lookup_binding(&self, name: &str) -> Option<&SynType> {
         if !self.used_names.contains(name) {
             return None;
@@ -899,6 +906,7 @@ pub struct FunctionCodeBuilder {
 }
 
 impl FunctionCodeBuilder {
+    #[must_use]
     pub fn new() -> Self {
         Self {
             stack_layout: StackMap::new(),
@@ -956,6 +964,7 @@ pub struct Function<'def> {
 
 impl<'def> Function<'def> {
     /// Get the name of the function.
+    #[must_use]
     pub fn name(&self) -> &str {
         &self.code.name
     }
@@ -1283,6 +1292,7 @@ pub struct FunctionBuilder<'def> {
 }
 
 impl<'def> FunctionBuilder<'def> {
+    #[must_use]
     pub fn new(name: &str, spec_name: &str) -> Self {
         let code_builder = FunctionCodeBuilder::new();
         let spec_builder = FunctionSpecBuilder::new();
@@ -1344,11 +1354,13 @@ impl<'def> FunctionBuilder<'def> {
     }
 
     /// Get the type parameters.
+    #[must_use]
     pub fn get_ty_params(&self) -> &[LiteralTyParam] {
         &self.generic_types
     }
 
     /// Get the universal lifetimes.
+    #[must_use]
     pub fn get_lfts(&self) -> Vec<(Option<String>, Lft)> {
         self.generic_lifetimes.clone()
     }
diff --git a/rr_frontend/radium/src/coq.rs b/rr_frontend/radium/src/coq.rs
index 00e123c8..3a16d26d 100644
--- a/rr_frontend/radium/src/coq.rs
+++ b/rr_frontend/radium/src/coq.rs
@@ -171,6 +171,7 @@ impl Display for CoqType {
 
 impl CoqType {
     /// Check if the `CoqType` contains a free variable `Var(i)`.
+    #[must_use]
     pub fn is_closed(&self) -> bool {
         match self {
             Self::Bool
@@ -251,6 +252,7 @@ impl CoqType {
 pub struct CoqParamList(pub Vec<(CoqName, CoqType)>);
 
 impl CoqParamList {
+    #[must_use]
     pub const fn empty() -> Self {
         Self(vec![])
     }
@@ -397,10 +399,12 @@ pub struct CoqAttributes {
     attrs: Vec<CoqAttribute>,
 }
 impl CoqAttributes {
+    #[must_use]
     pub const fn empty() -> Self {
         Self { attrs: vec![] }
     }
 
+    #[must_use]
     pub fn new(attrs: Vec<CoqAttribute>) -> Self {
         Self { attrs }
     }
@@ -463,6 +467,7 @@ impl Display for CoqTopLevelAssertion {
 pub struct CoqTopLevelAssertions(pub Vec<CoqTopLevelAssertion>);
 
 impl CoqTopLevelAssertions {
+    #[must_use]
     pub const fn empty() -> Self {
         Self(vec![])
     }
diff --git a/rr_frontend/radium/src/specs.rs b/rr_frontend/radium/src/specs.rs
index 2f45ca1f..3479a36b 100644
--- a/rr_frontend/radium/src/specs.rs
+++ b/rr_frontend/radium/src/specs.rs
@@ -26,18 +26,22 @@ impl<'def> Display for TypeWithRef<'def> {
 }
 
 impl<'def> TypeWithRef<'def> {
+    #[must_use]
     pub const fn new(ty: Type<'def>, rfn: String) -> Self {
         TypeWithRef(ty, rfn)
     }
 
+    #[must_use]
     pub fn make_unit() -> Self {
         TypeWithRef(Type::Unit, "()".to_string())
     }
 
+    #[must_use]
     pub const fn ty(&self) -> &Type<'def> {
         &self.0
     }
 
+    #[must_use]
     pub fn rfn(&self) -> &str {
         self.1.as_str()
     }
@@ -106,6 +110,7 @@ impl Display for IntType {
 
 impl IntType {
     /// Get the size in bytes of the Caesium representation.
+    #[must_use]
     pub const fn size(&self) -> u32 {
         match self {
             Self::I8 | Self::U8 => 1,
@@ -117,6 +122,7 @@ impl IntType {
     }
 
     /// Get the alignment in bytes of the Caesium representation.
+    #[must_use]
     pub const fn alignment(&self) -> u32 {
         match self {
             Self::I8 | Self::U8 => 1,
@@ -245,11 +251,13 @@ impl SynType {
 
     /// Get a Coq term for the layout of this syntactic type.
     /// This may call the Coq-level layout algorithm that we assume.
+    #[must_use]
     pub fn layout_term_typaram(&self, env: &[Option<LiteralTyParam>]) -> Layout {
         self.layout_term_core(env, |x| Self::Literal(x.syn_type.clone()))
     }
 
     /// See `layout_term_typaram`.
+    #[must_use]
     pub fn layout_term(&self, env: &[Option<Self>]) -> Layout {
         self.layout_term_core(env, |x| x.clone())
     }
@@ -284,16 +292,19 @@ impl SynType {
     /// Determine the optype used to access a value of this syntactic type.
     /// Note that we may also always use `UntypedOp`, but this here computes the more specific
     /// `op_type` that triggers more UB on invalid values.
+    #[must_use]
     pub fn optype_typaram(&self, env: &[Option<LiteralTyParam>]) -> OpType {
         self.optype_core(env, |x| Self::Literal(x.syn_type.clone()))
     }
 
     /// See `optype_typaram`.
+    #[must_use]
     pub fn optype(&self, env: &[Option<Self>]) -> OpType {
         self.optype_core(env, |x| x.clone())
     }
 
     /// Check if the `SynType` contains a free variable `Var(i)`.
+    #[must_use]
     pub const fn is_closed(&self) -> bool {
         !matches!(self, Self::Var(_))
     }
@@ -328,10 +339,12 @@ pub struct TypeAnnotMeta {
 }
 
 impl TypeAnnotMeta {
+    #[must_use]
     pub fn is_empty(&self) -> bool {
         self.escaped_lfts.is_empty() && self.escaped_tyvars.is_empty()
     }
 
+    #[must_use]
     pub fn empty() -> Self {
         Self {
             escaped_lfts: HashSet::new(),
@@ -339,6 +352,7 @@ impl TypeAnnotMeta {
         }
     }
 
+    #[must_use]
     pub const fn new(tyvars: HashSet<LiteralTyParam>, lfts: HashSet<Lft>) -> Self {
         Self {
             escaped_lfts: lfts,
@@ -381,6 +395,7 @@ pub struct LiteralTypeUse<'def> {
 
 impl<'def> LiteralTypeUse<'def> {
     /// `params` should not contain `Var`
+    #[must_use]
     pub fn new(s: LiteralTypeRef<'def>, params: Vec<Type<'def>>) -> Self {
         LiteralTypeUse {
             def: s,
@@ -390,6 +405,7 @@ impl<'def> LiteralTypeUse<'def> {
     }
 
     /// `params` should not contain `Var`
+    #[must_use]
     pub fn new_with_annot(s: LiteralTypeRef<'def>, params: Vec<Type<'def>>, annot: TypeAnnotMeta) -> Self {
         LiteralTypeUse {
             def: s,
@@ -412,6 +428,7 @@ impl<'def> LiteralTypeUse<'def> {
 
     /// Get the refinement type of a struct usage.
     /// This requires that all type parameters of the struct have been instantiated.
+    #[must_use]
     pub fn get_rfn_type(&self) -> String {
         let rfn_instantiations: Vec<String> =
             self.params.iter().map(|ty| ty.get_rfn_type(&[]).to_string()).collect();
@@ -422,6 +439,7 @@ impl<'def> LiteralTypeUse<'def> {
     }
 
     /// Get the `syn_type` term for this struct use.
+    #[must_use]
     pub fn generate_raw_syn_type_term(&self) -> SynType {
         // first get the syntys for the type params
         let mut param_sts = Vec::new();
@@ -433,6 +451,7 @@ impl<'def> LiteralTypeUse<'def> {
         SynType::Literal(specialized_spec.to_string())
     }
 
+    #[must_use]
     pub fn generate_syn_type_term(&self) -> SynType {
         // first get the syntys for the type params
         let mut param_sts = Vec::new();
@@ -445,6 +464,7 @@ impl<'def> LiteralTypeUse<'def> {
     }
 
     /// Generate a string representation of this struct use.
+    #[must_use]
     pub fn generate_type_term(&self) -> String {
         let mut param_tys = Vec::new();
         for p in &self.params {
@@ -469,6 +489,7 @@ pub struct LiteralTyParam {
 
 impl LiteralTyParam {
     /// Make a literal type for this type parameter and a given `st_name`.
+    #[must_use]
     pub fn make_literal_type(&self) -> LiteralType {
         LiteralType {
             rust_name: Some(self.rust_name.clone()),
@@ -549,6 +570,7 @@ impl<'def> Type<'def> {
 
     /// Determines the type this type is refined by.
     /// `env` gives the environment for `Var(i)` constructors.
+    #[must_use]
     pub fn get_rfn_type(&self, env: &[Option<CoqType>]) -> CoqType {
         match self {
             Self::Bool => CoqType::Bool,
@@ -595,6 +617,7 @@ impl<'def> Type<'def> {
     }
 
     /// Get the layout of a type.
+    #[must_use]
     pub fn get_syn_type(&self) -> SynType {
         match self {
             Self::Bool => SynType::Bool,
@@ -680,6 +703,7 @@ impl<'def> Type<'def> {
     }
 
     /// Check if the Type contains a free variable `Var(i)`.
+    #[must_use]
     pub fn is_closed(&self) -> bool {
         match self {
             Self::Var(_) => false,
@@ -742,6 +766,7 @@ pub struct TyOwnSpec {
 }
 
 impl TyOwnSpec {
+    #[must_use]
     pub const fn new(
         loc: String,
         rfn: String,
@@ -758,10 +783,12 @@ impl TyOwnSpec {
         }
     }
 
+    #[must_use]
     pub fn fmt_owned(&self, tid: &str) -> String {
         format!("{} ◁ₗ[{}, Owned {}] #({}) @ (◁ {})", self.loc, tid, self.with_later, self.rfn, self.ty)
     }
 
+    #[must_use]
     pub fn fmt_shared(&self, tid: &str, lft: &str) -> String {
         format!("{} ◁ₗ[{}, Shared {}] #({}) @ (◁ {})", self.loc, tid, lft, self.rfn, self.ty)
     }
@@ -814,6 +841,7 @@ pub struct InvariantSpec {
 }
 
 impl InvariantSpec {
+    #[must_use]
     pub fn new(
         type_name: String,
         flags: InvariantSpecFlags,
@@ -1143,6 +1171,7 @@ impl InvariantSpec {
         out
     }
 
+    #[must_use]
     pub fn rt_def_name(&self) -> String {
         format!("{}_rt", self.type_name)
     }
@@ -1202,6 +1231,7 @@ impl Display for UnionRepr {
 }
 
 /// Lookup a Rust-level type parameter identifier `name` in the given type parameter environment.
+#[must_use]
 pub fn lookup_ty_param<'a>(name: &'_ str, env: &'a [LiteralTyParam]) -> Option<&'a LiteralTyParam> {
     env.iter().find(|&names| names.rust_name == name)
 }
@@ -1234,11 +1264,13 @@ pub struct AbstractVariant<'def> {
 
 impl<'def> AbstractVariant<'def> {
     /// Get the name of this variant
+    #[must_use]
     pub fn name(&self) -> &str {
         &self.name
     }
 
     /// The core of generating the sls definition, without the section + context intro.
+    #[must_use]
     pub fn generate_coq_sls_def_core(&self, typarams: &[String], typarams_use: &[String]) -> String {
         let mut out = String::with_capacity(200);
         let indent = "  ";
@@ -1272,6 +1304,7 @@ impl<'def> AbstractVariant<'def> {
     }
 
     /// Generate a Coq definition for the struct layout spec.
+    #[must_use]
     pub fn generate_coq_sls_def(&self, ty_params: &[LiteralTyParam]) -> String {
         let mut out = String::with_capacity(200);
 
@@ -1295,6 +1328,7 @@ impl<'def> AbstractVariant<'def> {
         out
     }
 
+    #[must_use]
     pub fn generate_coq_type_term(&self, sls_app: Vec<String>) -> String {
         let mut out = String::with_capacity(200);
 
@@ -1305,6 +1339,7 @@ impl<'def> AbstractVariant<'def> {
         out
     }
 
+    #[must_use]
     pub fn generate_coq_type_def_core(
         &self,
         ty_params: &[LiteralTyParam],
@@ -1354,6 +1389,7 @@ impl<'def> AbstractVariant<'def> {
     /// Generate a Coq definition for the struct type alias.
     /// TODO: maybe we should also generate a separate alias def for the refinement type to make
     /// things more readable?
+    #[must_use]
     pub fn generate_coq_type_def(&self, ty_params: &[LiteralTyParam], extra_context: &[CoqParam]) -> String {
         let mut out = String::with_capacity(200);
         let indent = "  ";
@@ -1449,6 +1485,7 @@ pub struct AbstractStruct<'def> {
 }
 
 impl<'def> AbstractStruct<'def> {
+    #[must_use]
     pub fn new(variant_def: AbstractVariant<'def>, ty_params: Vec<LiteralTyParam>) -> Self {
         AbstractStruct {
             invariant: None,
@@ -1458,28 +1495,34 @@ impl<'def> AbstractStruct<'def> {
     }
 
     /// Check if the struct has type parameters.
+    #[must_use]
     pub fn has_type_params(&self) -> bool {
         !self.ty_params.is_empty()
     }
 
     /// Get the name of this struct
+    #[must_use]
     pub fn name(&self) -> &str {
         self.variant_def.name()
     }
 
+    #[must_use]
     pub fn sls_def_name(&self) -> &str {
         &self.variant_def.sls_def_name
     }
 
+    #[must_use]
     pub fn st_def_name(&self) -> &str {
         &self.variant_def.st_def_name
     }
 
+    #[must_use]
     pub fn plain_ty_name(&self) -> &str {
         &self.variant_def.plain_ty_name
     }
 
     /// Get the name of the struct, or an ADT defined on it, if available.
+    #[must_use]
     pub fn public_type_name(&self) -> &str {
         match self.invariant {
             Some(ref inv) => &inv.type_name,
@@ -1487,10 +1530,12 @@ impl<'def> AbstractStruct<'def> {
         }
     }
 
+    #[must_use]
     pub fn plain_rt_def_name(&self) -> &str {
         &self.variant_def.plain_rt_def_name
     }
 
+    #[must_use]
     pub fn public_rt_def_name(&self) -> String {
         match self.invariant {
             Some(ref inv) => inv.rt_def_name(),
@@ -1507,11 +1552,13 @@ impl<'def> AbstractStruct<'def> {
     }
 
     /// Generate a Coq definition for the struct layout spec.
+    #[must_use]
     pub fn generate_coq_sls_def(&self) -> String {
         self.variant_def.generate_coq_sls_def(&self.ty_params)
     }
 
     /// Generate a Coq definition for the struct type alias.
+    #[must_use]
     pub fn generate_coq_type_def(&self) -> String {
         let extra_context = if let Some(ref inv) = self.invariant { inv.coq_params.as_slice() } else { &[] };
 
@@ -1519,6 +1566,7 @@ impl<'def> AbstractStruct<'def> {
     }
 
     /// Generate an optional definition for the invariant of this type, if one has been specified.
+    #[must_use]
     pub fn generate_optional_invariant_def(&self) -> Option<String> {
         self.invariant.as_ref().map(|spec| {
             spec.generate_coq_type_def(self.plain_ty_name(), self.plain_rt_def_name(), &self.ty_params)
@@ -1526,6 +1574,7 @@ impl<'def> AbstractStruct<'def> {
     }
 
     /// Make a literal type.
+    #[must_use]
     pub fn make_literal_type(&self) -> LiteralType {
         LiteralType {
             rust_name: Some(self.name().to_string()),
@@ -1547,6 +1596,7 @@ pub struct VariantBuilder<'def> {
 }
 
 impl<'def> VariantBuilder<'def> {
+    #[must_use]
     pub fn finish(self, ty_params: &[LiteralTyParam]) -> AbstractVariant<'def> {
         let sls_def_name: String = format!("{}_sls", &self.name);
         let st_def_name: String = format!("{}_st", &self.name);
@@ -1586,6 +1636,7 @@ impl<'def> VariantBuilder<'def> {
     }
 
     /// Finish building the struct type and generate an abstract struct definition.
+    #[must_use]
     pub fn finish_as_struct(self, ty_params: Vec<LiteralTyParam>) -> AbstractStruct<'def> {
         let variant = self.finish(&ty_params);
         AbstractStruct {
@@ -1597,6 +1648,7 @@ impl<'def> VariantBuilder<'def> {
 
     /// Initialize a struct builder.
     /// `ty_params` are the user-facing type parameter names in the Rust code.
+    #[must_use]
     pub fn new(name: String, repr: StructRepr) -> VariantBuilder<'def> {
         VariantBuilder {
             fields: Vec::new(),
@@ -1612,6 +1664,7 @@ impl<'def> VariantBuilder<'def> {
 }
 
 /// Create a struct representation of a tuple with `num_fields`, all of which are generic.
+#[must_use]
 pub fn make_tuple_struct_repr<'def>(num_fields: usize) -> AbstractStruct<'def> {
     let name = format!("tuple{}", num_fields);
 
@@ -1661,6 +1714,7 @@ impl<'def> AbstractStructUse<'def> {
     }
 
     /// Creates a new use of unit.
+    #[must_use]
     pub const fn new_unit() -> Self {
         AbstractStructUse {
             def: None,
@@ -1670,10 +1724,12 @@ impl<'def> AbstractStructUse<'def> {
     }
 
     /// Returns true iff this is a use of unit.
+    #[must_use]
     pub const fn is_unit(&self) -> bool {
         self.def.is_none()
     }
 
+    #[must_use]
     pub fn is_raw(&self) -> bool {
         self.raw == TypeIsRaw::Yes
     }
@@ -1694,6 +1750,7 @@ impl<'def> AbstractStructUse<'def> {
 
     /// Get the refinement type of a struct usage.
     /// This requires that all type parameters of the struct have been instantiated.
+    #[must_use]
     pub fn get_rfn_type(&self) -> String {
         let Some(def) = self.def.as_ref() else {
             return CoqType::Unit.to_string();
@@ -1719,6 +1776,7 @@ impl<'def> AbstractStructUse<'def> {
     }
 
     /// Generate a term for the `struct_layout` (of type `struct_layout`)
+    #[must_use]
     pub fn generate_struct_layout_term(&self) -> String {
         let Some(def) = self.def.as_ref() else {
             return Layout::UnitLayout.to_string();
@@ -1737,6 +1795,7 @@ impl<'def> AbstractStructUse<'def> {
         CoqAppTerm::new("use_struct_layout_alg'".to_string(), vec![specialized_spec]).to_string()
     }
 
+    #[must_use]
     pub fn generate_struct_layout_spec_term(&self) -> String {
         let Some(def) = self.def.as_ref() else {
             panic!("unit has no sls");
@@ -1755,6 +1814,7 @@ impl<'def> AbstractStructUse<'def> {
     }
 
     /// Get the `syn_type` term for this struct use.
+    #[must_use]
     pub fn generate_syn_type_term(&self) -> SynType {
         let Some(def) = self.def.as_ref() else {
             return SynType::Unit;
@@ -1774,6 +1834,7 @@ impl<'def> AbstractStructUse<'def> {
     }
 
     /// Generate a string representation of this struct use.
+    #[must_use]
     pub fn generate_type_term(&self) -> String {
         let Some(def) = self.def.as_ref() else {
             return Type::Unit.to_string();
@@ -1844,37 +1905,45 @@ pub struct AbstractEnum<'def> {
 
 impl<'def> AbstractEnum<'def> {
     /// Check whether this enum has any type parameters.
+    #[must_use]
     pub fn has_type_params(&self) -> bool {
         !self.ty_params.is_empty()
     }
 
     /// Get the name of this enum.
+    #[must_use]
     pub fn name(&self) -> &str {
         &self.name
     }
 
+    #[must_use]
     pub fn public_type_name(&self) -> &str {
         &self.plain_ty_name
     }
 
+    #[must_use]
     pub fn public_rt_def_name(&self) -> &str {
         &self.plain_rt_name
     }
 
+    #[must_use]
     pub fn els_def_name(&self) -> &str {
         &self.els_def_name
     }
 
+    #[must_use]
     pub fn st_def_name(&self) -> &str {
         &self.st_def_name
     }
 
+    #[must_use]
     pub fn get_variant(&self, i: usize) -> Option<&(String, AbstractStructRef<'def>, i128)> {
         self.variants.get(i)
     }
 
     /// Generate a Coq definition for the enum layout spec, and all the `struct_layout_specs` for the
     /// variants.
+    #[must_use]
     pub fn generate_coq_els_def(&self) -> String {
         let indent = "  ";
 
@@ -2057,6 +2126,7 @@ impl<'def> AbstractEnum<'def> {
         out
     }
 
+    #[must_use]
     pub fn generate_coq_type_def(&self) -> String {
         let mut out = String::with_capacity(200);
 
@@ -2192,6 +2262,7 @@ impl<'def> AbstractEnum<'def> {
     }
 
     /// Make a literal type.
+    #[must_use]
     pub fn make_literal_type(&self) -> LiteralType {
         LiteralType {
             rust_name: Some(self.name().to_string()),
@@ -2220,6 +2291,7 @@ pub struct EnumBuilder<'def> {
 
 impl<'def> EnumBuilder<'def> {
     /// Finish building the enum type and generate an abstract enum definition.
+    #[must_use]
     pub fn finish(self, optional_inductive_def: Option<CoqInductive>, spec: EnumSpec) -> AbstractEnum<'def> {
         let els_def_name: String = format!("{}_els", &self.name);
         let st_def_name: String = format!("{}_st", &self.name);
@@ -2245,6 +2317,7 @@ impl<'def> EnumBuilder<'def> {
 
     /// Initialize an enum builder.
     /// `ty_params` are the user-facing type parameter names in the Rust code.
+    #[must_use]
     pub fn new(
         name: String,
         ty_param_defs: Vec<LiteralTyParam>,
@@ -2298,6 +2371,7 @@ impl<'def> AbstractEnumUse<'def> {
 
     /// Get the refinement type of an enum usage.
     /// This requires that all type parameters of the enum have been instantiated.
+    #[must_use]
     pub fn get_rfn_type(&self) -> CoqType {
         let env = Vec::new(); // we use the empty environment per our assumption
         let rfn_instantiations: Vec<CoqType> =
@@ -2311,6 +2385,7 @@ impl<'def> AbstractEnumUse<'def> {
     }
 
     /// Generate a term for the enum layout (of type `struct_layout`)
+    #[must_use]
     pub fn generate_enum_layout_term(&self) -> String {
         // first get the syntys for the type params
         let mut param_sts = Vec::new();
@@ -2328,6 +2403,7 @@ impl<'def> AbstractEnumUse<'def> {
     }
 
     /// Generate a term for the enum layout spec (of type `enum_layout_spec`).
+    #[must_use]
     pub fn generate_enum_layout_spec_term(&self) -> String {
         // first get the syntys for the type params
         let mut param_sts = Vec::new();
@@ -2341,6 +2417,7 @@ impl<'def> AbstractEnumUse<'def> {
     }
 
     /// Get the `syn_type` term for this enum use.
+    #[must_use]
     pub fn generate_syn_type_term(&self) -> SynType {
         // first get the syntys for the type params
         let mut param_sts = Vec::new();
@@ -2356,6 +2433,7 @@ impl<'def> AbstractEnumUse<'def> {
     }
 
     /// Generate a string representation of this enum use.
+    #[must_use]
     pub fn generate_type_term(&self) -> String {
         let mut param_tys = Vec::new();
         for p in &self.ty_params {
@@ -2405,6 +2483,7 @@ impl Display for Layout {
 }
 
 impl Layout {
+    #[must_use]
     pub fn size(&self, env: &LayoutEnv) -> Option<u32> {
         match self {
             Self::UnitLayout => Some(0),
@@ -2423,6 +2502,7 @@ impl Layout {
         }
     }
 
+    #[must_use]
     pub fn alignment(&self, env: &LayoutEnv) -> Option<u32> {
         match self {
             Self::BoolLayout | Self::UnitLayout | Self::PadLayout(_) => Some(1),
@@ -2448,6 +2528,7 @@ impl Layout {
 #[derive(Clone, Eq, PartialEq, Debug)]
 pub struct CoqBinder(CoqName, CoqType);
 impl CoqBinder {
+    #[must_use]
     pub const fn new(n: CoqName, t: CoqType) -> Self {
         Self(n, t)
     }
@@ -2526,6 +2607,7 @@ pub struct IPropPredicate {
 }
 
 impl IPropPredicate {
+    #[must_use]
     pub fn new(binders: Vec<CoqBinder>, prop: IProp) -> Self {
         Self { binders, prop }
     }
@@ -2558,6 +2640,7 @@ pub struct CoqParam {
 }
 
 impl CoqParam {
+    #[must_use]
     pub fn new(name: CoqName, ty: CoqType, implicit: bool) -> Self {
         let depends_on_sigma = if let CoqType::Literal(ref lit) = ty { lit.contains('Σ') } else { false };
         Self {
@@ -2568,6 +2651,7 @@ impl CoqParam {
         }
     }
 
+    #[must_use]
     pub fn with_name(&self, name: String) -> Self {
         Self::new(CoqName::Named(name), self.ty.clone(), self.implicit)
     }
@@ -2662,6 +2746,7 @@ impl<'def> FunctionSpec<'def> {
         out
     }
 
+    #[must_use]
     pub const fn has_spec(&self) -> bool {
         self.has_spec
     }
@@ -2774,6 +2859,7 @@ pub struct FunctionSpecBuilder<'def> {
 }
 
 impl<'def> FunctionSpecBuilder<'def> {
+    #[must_use]
     pub fn new() -> Self {
         Self {
             coq_params: Vec::new(),
diff --git a/rr_frontend/rrconfig/src/launch.rs b/rr_frontend/rrconfig/src/launch.rs
index 44762aab..990cf478 100644
--- a/rr_frontend/rrconfig/src/launch.rs
+++ b/rr_frontend/rrconfig/src/launch.rs
@@ -9,6 +9,7 @@ use std::env;
 use std::path::PathBuf;
 use std::process::Command;
 
+#[must_use]
 pub fn get_current_executable_dir() -> PathBuf {
     env::current_exe()
         .expect("current executable path invalid")
diff --git a/rr_frontend/rrconfig/src/lib.rs b/rr_frontend/rrconfig/src/lib.rs
index c8b78355..f59a9fa7 100644
--- a/rr_frontend/rrconfig/src/lib.rs
+++ b/rr_frontend/rrconfig/src/lib.rs
@@ -77,6 +77,7 @@ lazy_static! {
 }
 
 /// Generate a dump of the settings
+#[must_use]
 pub fn dump() -> String {
     format!("{:#?}", SETTINGS.read().unwrap())
 }
@@ -121,31 +122,37 @@ fn write_setting<T: Into<config::Value>>(key: &'static str, value: T) {
         .unwrap_or_else(|e| panic!("Failed to write setting {key} due to {e}"));
 }
 
+#[must_use]
 pub fn work_dir() -> String {
     read_setting("work_dir")
 }
 
+#[must_use]
 pub fn absolute_work_dir() -> PathBuf {
     let s = work_dir();
     make_path_absolute(&s)
 }
 
 /// Should we dump debug files?
+#[must_use]
 pub fn dump_debug_info() -> bool {
     read_setting("dump_debug_info")
 }
 
 /// Should we dump borrowck info?
+#[must_use]
 pub fn dump_borrowck_info() -> bool {
     read_setting("dump_borrowck_info")
 }
 
 /// In which folder should we store log/dumps?
+#[must_use]
 pub fn log_dir() -> PathBuf {
     make_path_absolute(&read_setting::<String>("log_dir"))
 }
 
 /// Get the paths in which to search for `RefinedRust` library declarations.
+#[must_use]
 pub fn lib_load_paths() -> Vec<PathBuf> {
     let mut paths = Vec::new();
     let s = read_setting::<Vec<String>>("lib_load_paths");
@@ -156,89 +163,107 @@ pub fn lib_load_paths() -> Vec<PathBuf> {
 }
 
 /// The hotword with which specification attributes should begin.
+#[must_use]
 pub fn spec_hotword() -> String {
     read_setting("spec_hotword")
 }
 
 /// Should we hide user messages?
+#[must_use]
 pub fn quiet() -> bool {
     read_setting("quiet")
 }
 
 /// Skip features that are unsupported or partially supported
+#[must_use]
 pub fn skip_unsupported_features() -> bool {
     read_setting("skip_unsupported_features")
 }
 
 /// Whether to generate a dune-project file for this project
+#[must_use]
 pub fn generate_dune_project() -> bool {
     read_setting("generate_dune_project")
 }
 
 /// Which attribute parser to use? Currently, only the "verbose" parser is supported.
+#[must_use]
 pub fn attribute_parser() -> String {
     read_setting("attribute_parser")
 }
 
 /// Which directory to write the generated Coq files to?
+#[must_use]
 pub fn output_dir() -> Option<PathBuf> {
     read_optional_setting("output_dir").map(|s: String| make_path_absolute(&s))
 }
 
 /// Whether to admit proofs of functions instead of running Qed.
+#[must_use]
 pub fn admit_proofs() -> bool {
     read_setting("admit_proofs")
 }
 
 /// Post-generation hook
+#[must_use]
 pub fn post_generation_hook() -> Option<String> {
     read_optional_setting("post_generation_hook")
 }
 
 /// Which file to read shims from?
+#[must_use]
 pub fn shim_file() -> Option<PathBuf> {
     read_optional_setting("shims").map(|s: String| make_path_absolute(&s))
 }
 
 /// Which file should we read extra specs from?
+#[must_use]
 pub fn extra_specs_file() -> Option<PathBuf> {
     read_optional_setting("extra_specs").map(|s: String| make_path_absolute(&s))
 }
 
 /// Run the proof checker after generating the Coq code?
+#[must_use]
 pub fn check_proofs() -> bool {
     read_setting("run_check")
 }
 
 /// Which cargo to use?
+#[must_use]
 pub fn cargo_path() -> String {
     read_setting("cargo_path")
 }
 
 /// Which cargo command should cargo-refinedrust hook into?
+#[must_use]
 pub fn cargo_command() -> String {
     read_setting("cargo_command")
 }
 
 /// Should refinedrust-rustc behave like rustc?
+#[must_use]
 pub fn be_rustc() -> bool {
     read_setting("be_rustc")
 }
 
 /// Should also dependencies be verified?
+#[must_use]
 pub fn verify_deps() -> bool {
     read_setting("verify_deps")
 }
 
 /// Should verification be skipped?
+#[must_use]
 pub fn no_verify() -> bool {
     read_setting("no_verify")
 }
+
 pub fn set_no_verify(value: bool) {
     write_setting("no_verify", value);
 }
 
 /// Should we check for overflows?
+#[must_use]
 pub fn check_overflows() -> bool {
     read_setting("check_overflows")
 }
diff --git a/rr_frontend/translation/src/environment/borrowck/facts.rs b/rr_frontend/translation/src/environment/borrowck/facts.rs
index 3d4e5f48..5c3592d5 100644
--- a/rr_frontend/translation/src/environment/borrowck/facts.rs
+++ b/rr_frontend/translation/src/environment/borrowck/facts.rs
@@ -86,10 +86,12 @@ pub struct Interner {
 }
 
 impl Interner {
+    #[must_use]
     pub const fn new(location_table: LocationTable) -> Self {
         Self { location_table }
     }
 
+    #[must_use]
     pub fn get_point_index(&self, point: &Point) -> PointIndex {
         // self.points.get_index(point)
         match point.typ {
@@ -98,6 +100,7 @@ impl Interner {
         }
     }
 
+    #[must_use]
     pub fn get_point(&self, index: PointIndex) -> Point {
         // self.points.get_element(index)
         match self.location_table.to_location(index) {
@@ -112,6 +115,7 @@ impl Interner {
         }
     }
 
+    #[must_use]
     pub fn get_location(&self, index: PointIndex) -> mir::Location {
         // self.points.get_element(index)
         match self.location_table.to_location(index) {
diff --git a/rr_frontend/translation/src/environment/borrowck/regions.rs b/rr_frontend/translation/src/environment/borrowck/regions.rs
index 02dda04a..a6ddc213 100644
--- a/rr_frontend/translation/src/environment/borrowck/regions.rs
+++ b/rr_frontend/translation/src/environment/borrowck/regions.rs
@@ -36,6 +36,7 @@ impl PlaceRegions {
         self.0.insert((local, projections), rvid);
     }
 
+    #[must_use]
     pub fn for_local(&self, local: mir::Local) -> Option<facts::Region> {
         self.for_place(local.into()).unwrap()
     }
diff --git a/rr_frontend/translation/src/environment/loops.rs b/rr_frontend/translation/src/environment/loops.rs
index 1b15a25f..712b0fb1 100644
--- a/rr_frontend/translation/src/environment/loops.rs
+++ b/rr_frontend/translation/src/environment/loops.rs
@@ -359,56 +359,67 @@ impl ProcedureLoops {
         }
     }
 
+    #[must_use]
     pub fn count_loop_heads(&self) -> usize {
         self.loop_heads.len()
     }
 
+    #[must_use]
     pub fn max_loop_nesting(&self) -> usize {
         self.loop_head_depths.values().max().copied().unwrap_or(0)
     }
 
+    #[must_use]
     pub fn is_loop_head(&self, bbi: BasicBlockIndex) -> bool {
         self.loop_heads.contains(&bbi)
     }
 
+    #[must_use]
     pub fn get_loop_exit_blocks(&self, bbi: BasicBlockIndex) -> &[BasicBlockIndex] {
         debug_assert!(self.is_loop_head(bbi));
         &self.loop_exit_blocks[&bbi]
     }
 
+    #[must_use]
     pub fn is_conditional_branch(&self, loop_head: BasicBlockIndex, bbi: BasicBlockIndex) -> bool {
         debug_assert!(self.is_loop_head(loop_head));
         !self.nonconditional_loop_blocks[&loop_head].contains(&bbi)
     }
 
+    #[must_use]
     pub fn get_enclosing_loop_heads(&self, bbi: BasicBlockIndex) -> &[BasicBlockIndex] {
         if let Some(heads) = self.enclosing_loop_heads.get(&bbi) { heads } else { &[] }
     }
 
     /// Get the loop head, if any
     /// Note: a loop head **is** loop head of itself
+    #[must_use]
     pub fn get_loop_head(&self, bbi: BasicBlockIndex) -> Option<BasicBlockIndex> {
         self.enclosing_loop_heads.get(&bbi).and_then(|heads| heads.last()).copied()
     }
 
     /// Get the depth of a loop head, starting from one for a simple loop
+    #[must_use]
     pub fn get_loop_head_depth(&self, bbi: BasicBlockIndex) -> usize {
         debug_assert!(self.is_loop_head(bbi));
         self.loop_head_depths[&bbi]
     }
 
     /// Get the loop-depth of a block (zero if it's not in a loop).
+    #[must_use]
     pub fn get_loop_depth(&self, bbi: BasicBlockIndex) -> usize {
         self.get_loop_head(bbi).map_or(0, |x| self.get_loop_head_depth(x))
     }
 
     /// Get the (topologically ordered) body of a loop, given a loop head
+    #[must_use]
     pub fn get_loop_body(&self, loop_head: BasicBlockIndex) -> &[BasicBlockIndex] {
         debug_assert!(self.is_loop_head(loop_head));
         &self.ordered_loop_bodies[&loop_head]
     }
 
     /// Does this edge exit a loop?
+    #[must_use]
     pub fn is_out_edge(&self, from: BasicBlockIndex, to: BasicBlockIndex) -> bool {
         let Some(from_loop_head) = self.get_loop_head(from) else {
             return false;
@@ -426,6 +437,7 @@ impl ProcedureLoops {
     }
 
     /// Check if ``block`` is inside a given loop.
+    #[must_use]
     pub fn is_block_in_loop(&self, loop_head: BasicBlockIndex, block: BasicBlockIndex) -> bool {
         self.dominators.dominates(loop_head, block)
     }
diff --git a/rr_frontend/translation/src/environment/mir_analyses/initialization.rs b/rr_frontend/translation/src/environment/mir_analyses/initialization.rs
index 8573576b..19ce2004 100644
--- a/rr_frontend/translation/src/environment/mir_analyses/initialization.rs
+++ b/rr_frontend/translation/src/environment/mir_analyses/initialization.rs
@@ -36,6 +36,7 @@ pub struct AnalysisResult<T> {
 
 impl<T> AnalysisResult<T> {
     #[allow(clippy::new_without_default)]
+    #[must_use]
     pub fn new() -> Self {
         Self {
             before_block: FxHashMap::default(),
@@ -45,6 +46,7 @@ impl<T> AnalysisResult<T> {
 
     /// Get the initialization set before the first statement of the
     /// basic block.
+    #[must_use]
     pub fn get_before_block(&self, bb: mir::BasicBlock) -> &T {
         self.before_block
             .get(&bb)
@@ -54,6 +56,7 @@ impl<T> AnalysisResult<T> {
     /// Get the initialization set after the statement.
     /// If `location.statement_index` is equal to the number of statements,
     /// returns the initialization set after the terminator.
+    #[must_use]
     pub fn get_after_statement(&self, location: mir::Location) -> &T {
         self.after_statement
             .get(&location)
diff --git a/rr_frontend/translation/src/environment/mir_sets/local_set.rs b/rr_frontend/translation/src/environment/mir_sets/local_set.rs
index 90c57dd0..b2c0cb57 100644
--- a/rr_frontend/translation/src/environment/mir_sets/local_set.rs
+++ b/rr_frontend/translation/src/environment/mir_sets/local_set.rs
@@ -18,10 +18,12 @@ pub struct LocalSet {
 }
 
 impl LocalSet {
+    #[must_use]
     pub fn new() -> Self {
         Self::default()
     }
 
+    #[must_use]
     pub fn contains_prefix_of(&self, place: mir::Place) -> bool {
         self.locals.contains(&place.local)
     }
diff --git a/rr_frontend/translation/src/environment/mir_sets/place_set.rs b/rr_frontend/translation/src/environment/mir_sets/place_set.rs
index 9520711f..651469b0 100644
--- a/rr_frontend/translation/src/environment/mir_sets/place_set.rs
+++ b/rr_frontend/translation/src/environment/mir_sets/place_set.rs
@@ -21,14 +21,17 @@ pub struct PlaceSet<'tcx> {
 }
 
 impl<'tcx> PlaceSet<'tcx> {
+    #[must_use]
     pub fn new() -> Self {
         Self::default()
     }
 
+    #[must_use]
     pub fn contains(&self, place: mir::Place<'tcx>) -> bool {
         self.places.contains(&place)
     }
 
+    #[must_use]
     pub fn contains_prefix_of(&self, place: mir::Place<'tcx>) -> bool {
         self.places.iter().any(|potential_prefix| is_prefix(&place, potential_prefix))
     }
@@ -133,6 +136,7 @@ impl<'tcx> PlaceSet<'tcx> {
     }
 
     /// Compute the intersection of the two place sets.
+    #[must_use]
     pub fn merge(place_set1: &PlaceSet<'tcx>, place_set2: &PlaceSet<'tcx>) -> PlaceSet<'tcx> {
         place_set1.check_invariant();
         place_set2.check_invariant();
@@ -185,6 +189,7 @@ impl<'tcx> PlaceSet<'tcx> {
     ///
     /// Note that this function may break the invariant that we never
     /// have a place and its descendants in the set.
+    #[must_use]
     pub fn union(place_set1: &PlaceSet<'tcx>, place_set2: &PlaceSet<'tcx>) -> PlaceSet<'tcx> {
         let mut places = place_set1.places.clone();
         places.extend(place_set2.iter().copied());
diff --git a/rr_frontend/translation/src/environment/mir_utils/real_edges.rs b/rr_frontend/translation/src/environment/mir_utils/real_edges.rs
index fc6b6c21..39eb9929 100644
--- a/rr_frontend/translation/src/environment/mir_utils/real_edges.rs
+++ b/rr_frontend/translation/src/environment/mir_utils/real_edges.rs
@@ -32,10 +32,12 @@ impl RealEdges {
         }
     }
 
+    #[must_use]
     pub fn successors(&self, bb: mir::BasicBlock) -> &[mir::BasicBlock] {
         &self.successors[bb]
     }
 
+    #[must_use]
     pub fn predecessors(&self, bb: mir::BasicBlock) -> &[mir::BasicBlock] {
         &self.predecessors[bb]
     }
diff --git a/rr_frontend/translation/src/environment/mod.rs b/rr_frontend/translation/src/environment/mod.rs
index 88c8618c..da670769 100644
--- a/rr_frontend/translation/src/environment/mod.rs
+++ b/rr_frontend/translation/src/environment/mod.rs
@@ -58,6 +58,7 @@ pub struct Environment<'tcx> {
 
 impl<'tcx> Environment<'tcx> {
     /// Builds an environment given a compiler state.
+    #[must_use]
     pub fn new(tcx: TyCtxt<'tcx>) -> Self {
         Environment {
             tcx,
diff --git a/rr_frontend/translation/src/environment/polonius_info.rs b/rr_frontend/translation/src/environment/polonius_info.rs
index f6e94f25..69dc3d28 100644
--- a/rr_frontend/translation/src/environment/polonius_info.rs
+++ b/rr_frontend/translation/src/environment/polonius_info.rs
@@ -55,22 +55,27 @@ pub enum AtomicRegion {
 }
 
 impl AtomicRegion {
+    #[must_use]
     pub const fn is_loan(&self) -> bool {
         matches!(*self, Self::Loan(_, _))
     }
 
+    #[must_use]
     pub const fn is_universal(&self) -> bool {
         matches!(*self, Self::Universal(_, _))
     }
 
+    #[must_use]
     pub const fn is_place(&self) -> bool {
         matches!(*self, Self::PlaceRegion(_))
     }
 
+    #[must_use]
     pub const fn is_value(&self) -> bool {
         matches!(*self, Self::Unknown(_))
     }
 
+    #[must_use]
     pub const fn get_region(&self) -> facts::Region {
         match self {
             Self::Loan(_, r) | Self::Universal(_, r) | Self::PlaceRegion(r) | Self::Unknown(r) => *r,
@@ -273,6 +278,7 @@ pub fn graphviz<'tcx>(
 }
 
 /// Compute the transitive closure of a vec of constraints between regions.
+#[must_use]
 pub fn compute_transitive_closure(
     constraints: Vec<(facts::Region, facts::Region)>,
 ) -> Vec<(facts::Region, facts::Region)> {
@@ -590,6 +596,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     */
 
     /// Gets the kind of a region: originating from a loan, a universal region, or none of these.
+    #[must_use]
     pub fn get_region_kind(&self, region: facts::Region) -> RegionKind {
         // check if this region is induced by a loan
         let v: Vec<facts::Loan> = self
@@ -639,6 +646,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
         if found_region { RegionKind::PlaceRegion } else { RegionKind::Unknown }
     }
 
+    #[must_use]
     pub fn mk_atomic_region(&self, r: facts::Region) -> AtomicRegion {
         let kind = self.get_region_kind(r);
         match kind {
@@ -650,6 +658,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Enumerate local universal regions (excluding the function lifetime).
+    #[must_use]
     pub fn enumerate_local_universal_regions(&self) -> Vec<facts::Region> {
         let mut universals = Vec::new();
         for (r, _) in &self.borrowck_in_facts.placeholder {
@@ -668,6 +677,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get new subset constraints generated at a point.
+    #[must_use]
     pub fn get_new_subset_constraints_at_point(
         &self,
         point: facts::PointIndex,
@@ -682,6 +692,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// `r` is the region induced by the loan `l`.
+    #[must_use]
     pub fn get_outliving_atomic_regions_for_loan(
         &self,
         r: facts::Region,
@@ -736,6 +747,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get regions outliving `r` at point `loc`.
+    #[must_use]
     pub fn get_outliving_atomic_regions(
         &self,
         r: facts::Region,
@@ -781,6 +793,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Flips the `subset` relation computed by Polonius for each point.
+    #[must_use]
     pub fn compute_superset(
         output: &facts::AllOutputFacts,
     ) -> HashMap<facts::PointIndex, BTreeMap<facts::Region, BTreeSet<facts::Region>>> {
@@ -803,6 +816,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
         superset
     }
 
+    #[must_use]
     pub fn get_point(&self, location: mir::Location, point_type: facts::PointType) -> facts::PointIndex {
         let point = facts::Point {
             location,
@@ -811,6 +825,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
         self.interner.get_point_index(&point)
     }
 
+    #[must_use]
     pub fn get_all_loans_kept_alive_by(
         &self,
         point: facts::PointIndex,
@@ -850,12 +865,14 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get the atomic region corresponding to a loan.
+    #[must_use]
     pub fn atomic_region_of_loan(&self, l: facts::Loan) -> AtomicRegion {
         let r = self.get_loan_issued_at_for_loan(l);
         AtomicRegion::Loan(l, r)
     }
 
     /// Get loans including the zombies ``(all_loans, zombie_loans)``.
+    #[must_use]
     pub fn get_all_active_loans(&self, location: mir::Location) -> (Vec<facts::Loan>, Vec<facts::Loan>) {
         let mut loans = self.get_active_loans(location, false);
         let zombie_loans = self.get_active_loans(location, true);
@@ -872,6 +889,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get loans that are active (including those that are about to die) at the given location.
+    #[must_use]
     pub fn get_active_loans(&self, location: mir::Location, zombie: bool) -> Vec<facts::Loan> {
         let loan_live_at = self.get_borrow_live_at(zombie);
         let start_point = self.get_point(location, facts::PointType::Start);
@@ -906,6 +924,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get loans including the zombies ``(all_loans, zombie_loans)``.
+    #[must_use]
     pub fn get_all_loans_dying_at(&self, location: mir::Location) -> (Vec<facts::Loan>, Vec<facts::Loan>) {
         let mut loans = self.get_loans_dying_at(location, false);
         let zombie_loans = self.get_loans_dying_at(location, true);
@@ -914,6 +933,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get loans including the zombies ``(all_loans, zombie_loans)``.
+    #[must_use]
     pub fn get_all_loans_dying_between(
         &self,
         initial_loc: mir::Location,
@@ -936,6 +956,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get loans that die *at* (that is, exactly after) the given location.
+    #[must_use]
     pub fn get_loans_dying_at(&self, location: mir::Location, zombie: bool) -> Vec<facts::Loan> {
         // TODO: this needs to change.
         // the problem is that we check explcitly that it is currently live, but not at the next
@@ -973,6 +994,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get loans that die between two consecutive locations.
+    #[must_use]
     pub fn get_loans_dying_between(
         &self,
         initial_loc: mir::Location,
@@ -1034,6 +1056,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     //       d.into_iter().collect()) .unwrap_or(vec![])
     //     }
 
+    #[must_use]
     pub fn get_conflicting_loans(&self, loan: facts::Loan) -> Vec<facts::Loan> {
         self.loan_conflict_sets
             .get(&loan)
@@ -1041,6 +1064,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
             .unwrap_or_default()
     }
 
+    #[must_use]
     pub fn get_alive_conflicting_loans(
         &self,
         loan: facts::Loan,
@@ -1063,18 +1087,21 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get the location at which a loan is created, if possible
+    #[must_use]
     pub fn get_loan_location(&self, loan: &facts::Loan) -> Option<mir::Location> {
         self.loan_position.get(loan).copied()
     }
 
     /// Get the loan that gets created at a location.
     /// TODO: for aggregates, this only finds one loan
+    #[must_use]
     pub fn get_loan_at_location(&self, location: mir::Location) -> facts::Loan {
         self.loan_at_position[&location]
     }
 
     /// Get the loan that gets created at a location.
     /// TODO: for aggregates, this only finds one loan
+    #[must_use]
     pub fn get_optional_loan_at_location(&self, location: mir::Location) -> Option<facts::Loan> {
         if self.loan_at_position.contains_key(&location) {
             Some(self.loan_at_position[&location])
@@ -1084,6 +1111,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Get a map from loans to locations at which they were created.
+    #[must_use]
     pub fn loan_locations(&self) -> HashMap<facts::Loan, mir::Location> {
         self.loan_position.iter().map(|(loan, location)| (*loan, *location)).collect()
     }
@@ -1215,6 +1243,7 @@ impl<'a, 'tcx: 'a> PoloniusInfo<'a, 'tcx> {
     }
 
     /// Find a variable that has the given region in its type.
+    #[must_use]
     pub const fn find_variable(&self, _region: facts::Region) -> Option<mir::Local> {
         // TODO
         None
@@ -1597,6 +1626,7 @@ impl AdditionalFacts {
     }
 
     /// Derive additional facts from the borrow checker facts.
+    #[must_use]
     pub fn new(all_facts: &facts::AllInputFacts, output: &facts::AllOutputFacts) -> Self {
         let (zombie_requires, zombie_borrow_live_at, borrow_become_zombie_at) =
             Self::derive_zombie_requires(all_facts, output);
diff --git a/rr_frontend/translation/src/environment/procedure.rs b/rr_frontend/translation/src/environment/procedure.rs
index 3ab9916a..daebdfd0 100644
--- a/rr_frontend/translation/src/environment/procedure.rs
+++ b/rr_frontend/translation/src/environment/procedure.rs
@@ -70,11 +70,13 @@ impl<'tcx> Procedure<'tcx> {
         }
     }
 
+    #[must_use]
     pub const fn loop_info(&self) -> &loops::ProcedureLoops {
         &self.loop_info
     }
 
     /// Returns all the types used in the procedure, and any types reachable from them
+    #[must_use]
     pub fn get_declared_types(&self) -> Vec<Ty<'tcx>> {
         let _types: HashSet<Ty> = HashSet::new();
         // for var in &self.mir.local_decls {
@@ -90,26 +92,31 @@ impl<'tcx> Procedure<'tcx> {
     }
 
     /// Get definition ID of the procedure.
+    #[must_use]
     pub const fn get_id(&self) -> ProcedureDefId {
         self.proc_def_id
     }
 
     /// Get the MIR of the procedure
+    #[must_use]
     pub fn get_mir(&self) -> &Mir<'tcx> {
         &self.mir
     }
 
     /// Get the typing context.
+    #[must_use]
     pub const fn get_tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
     /// Get the type parameters of this procedure.
+    #[must_use]
     pub const fn get_type_params(&self) -> ty::GenericArgsRef<'tcx> {
         self.ty_params
     }
 
     /// Get an absolute `def_path`. Note: not preserved across compilations!
+    #[must_use]
     pub fn get_def_path(&self) -> String {
         let def_path = self.tcx.def_path(self.proc_def_id);
         let mut crate_name = self.tcx.crate_name(def_path.krate).to_string();
@@ -128,21 +135,25 @@ impl<'tcx> Procedure<'tcx> {
     // }
 
     /// Get the span of the procedure
+    #[must_use]
     pub fn get_span(&self) -> Span {
         self.mir.span
     }
 
     /// Get the first CFG block
+    #[must_use]
     pub fn get_first_cfg_block(&self) -> BasicBlock {
         self.mir.basic_blocks.indices().next().unwrap()
     }
 
     /// Iterate over all CFG basic blocks
+    #[must_use]
     pub fn get_all_cfg_blocks(&self) -> Vec<BasicBlock> {
         self.loop_info.ordered_blocks.clone()
     }
 
     /// Iterate over all reachable CFG basic blocks
+    #[must_use]
     pub fn get_reachable_cfg_blocks(&self) -> Vec<BasicBlock> {
         self.get_all_cfg_blocks()
             .into_iter()
@@ -168,10 +179,12 @@ impl<'tcx> Procedure<'tcx> {
     */
 
     /// Check whether the block is reachable
+    #[must_use]
     pub fn is_reachable_block(&self, bbi: BasicBlockIndex) -> bool {
         self.reachable_basic_blocks.contains(&bbi)
     }
 
+    #[must_use]
     pub fn is_panic_block(&self, bbi: BasicBlockIndex) -> bool {
         if let TerminatorKind::Call {
             args: ref _args,
@@ -199,11 +212,13 @@ impl<'tcx> Procedure<'tcx> {
     }
 
     /// Get the successors of a basic block.
+    #[must_use]
     pub fn successors(&self, bbi: mir::BasicBlock) -> &[mir::BasicBlock] {
         self.real_edges.successors(bbi)
     }
 
     /// Get the predecessors of a basic block.
+    #[must_use]
     pub fn predecessors(&self, bbi: mir::BasicBlock) -> &[mir::BasicBlock] {
         self.real_edges.predecessors(bbi)
     }
-- 
GitLab