Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,14 +340,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}

fn br_with_attrs(&mut self, dest: &'ll BasicBlock, attributes: &[AttributeKind]) {
fn br_with_attrs(&mut self, dest: &'ll BasicBlock, loop_hint_attrs: &[AttributeKind]) {

@JonathanBrouwer JonathanBrouwer Sep 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling it loop_hint_attributes everywhere is going to be painful when inevitably we add a non-loop-hint attribute in the future.
Can we call it filtered_attributes or sth like that?

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be renamed again if the meaning changes 🤷

I'm not sure naming it "filtered_attributes" would be clearer, that name doesn't say by what metric it is filtered.

unsafe {
let val = llvm::LLVMBuildBr(self.llbuilder, dest);

let mut nodes = Vec::new();

for attribute in attributes {
let AttributeKind::Unroll(unroll) = attribute else {
for loop_hint_attr in loop_hint_attrs {
let AttributeKind::Unroll(unroll) = loop_hint_attr else {
continue;
};
// UnrollAttr::Count needs a second operand, the provided count, but the other
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
bx: &mut Bx,
target: mir::BasicBlock,
mergeable_succ: bool,
attributes: &[AttributeKind],
loop_hint_attrs: &[AttributeKind],
) -> MergingSucc {
let (needs_landing_pad, is_cleanupret) = self.llbb_characteristics(fx, target);
if mergeable_succ && !needs_landing_pad && !is_cleanupret {
Expand All @@ -156,7 +156,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
// to a trampoline.
bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget));
} else {
bx.br_with_attrs(lltarget, attributes);
bx.br_with_attrs(lltarget, loop_hint_attrs);
}
MergingSucc::False
}
Expand Down Expand Up @@ -1677,7 +1677,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}

mir::TerminatorKind::Goto { target } => {
helper.funclet_br(self, bx, target, mergeable_succ(), &terminator.attributes)
helper.funclet_br(self, bx, target, mergeable_succ(), &terminator.loop_hint_attrs)
}

mir::TerminatorKind::SwitchInt { ref discr, ref targets } => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/traits/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub trait BuilderMethods<'a, 'tcx>:
fn ret_void(&mut self);
fn ret(&mut self, v: Self::Value);
fn br(&mut self, dest: Self::BasicBlock);
fn br_with_attrs(&mut self, dest: Self::BasicBlock, _attributes: &[AttributeKind]) {
fn br_with_attrs(&mut self, dest: Self::BasicBlock, _loop_hint_attrs: &[AttributeKind]) {
self.br(dest)
}
fn cond_br(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ impl<O: fmt::Debug> fmt::Display for AssertKind<O> {
pub struct Terminator<'tcx> {
pub source_info: SourceInfo,
pub kind: TerminatorKind<'tcx>,
pub attributes: ThinVec<AttributeKind>,
pub loop_hint_attrs: ThinVec<AttributeKind>,
}

impl<'tcx> Terminator<'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ macro_rules! make_mir_visitor {
terminator: &$($mutability)? Terminator<'tcx>,
location: Location
) {
let Terminator { source_info, kind, attributes: _ } = terminator;
let Terminator { source_info, kind, loop_hint_attrs: _ } = terminator;

self.visit_source_info(source_info);
match kind {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ macro_rules! thir_with_elements {
#[derive(Debug, StableHash, Clone)]
pub struct Thir<'tcx> {
pub body_type: BodyTy<'tcx>,
pub attributes: FxIndexMap<ExprId, ThinVec<AttributeKind>>,
pub loop_hint_attrs: FxIndexMap<ExprId, ThinVec<AttributeKind>>,
$(
pub $name: IndexVec<$id, $value>,
)*
Expand All @@ -72,7 +72,7 @@ macro_rules! thir_with_elements {
pub fn new(body_type: BodyTy<'tcx>) -> Thir<'tcx> {
Thir {
body_type,
attributes: FxIndexMap::default(),
loop_hint_attrs: FxIndexMap::default(),
$(
$name: IndexVec::new(),
)*
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/builder/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl<'tcx> CFG<'tcx> {
self.block_data(block)
);
self.block_data_mut(block).terminator =
Some(Terminator { source_info, kind, attributes: ThinVec::new() });
Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() });
self.block_data_mut(block).terminator.as_mut().unwrap()
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/builder/custom/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
data.terminator = Some(Terminator {
source_info: SourceInfo { span, scope: self.source_scope },
kind: terminator,
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});

Ok(data)
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/builder/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let body_block_end = this.expr_into_dest(tmp, body_block, body).into_block();

let goto = this.cfg.goto(body_block_end, source_info, loop_block);
if let Some(attrs) = this.thir.attributes.get(&expr_id) {
goto.attributes = attrs.clone();
if let Some(attrs) = this.thir.loop_hint_attrs.get(&expr_id) {
goto.loop_hint_attrs = attrs.clone();
}

// Loops are only exited by `break` expressions.
Expand Down
18 changes: 10 additions & 8 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ impl<'tcx> SplattedFunc<'tcx> {
}
}

fn parsed_attrs(id: HirId, tcx: TyCtxt<'_>) -> ThinVec<AttributeKind> {
fn filter_loop_hint_attrs(id: HirId, tcx: TyCtxt<'_>) -> ThinVec<AttributeKind> {
HasAttrs::get_attrs(id, &tcx)
.into_iter()
.filter_map(|attr| match attr {
rustc_attr_ir::Attribute::Parsed(attrkind) => Some(attrkind.clone()),
rustc_attr_ir::Attribute::Unparsed(_) => None,
rustc_attr_ir::Attribute::Parsed(attrkind @ AttributeKind::Unroll(_)) => {
Some(attrkind.clone())
}
_ => None,
})
Comment thread
mejrs marked this conversation as resolved.
.collect()
}
Expand Down Expand Up @@ -91,7 +93,7 @@ impl<'tcx> ThirBuildCx<'tcx> {

trace!(?expr.ty);

let mut attrs = ThinVec::new();
let mut loop_hint_attrs = ThinVec::new();

if let hir::ExprKind::Loop(_, _, _, span) = hir_expr.kind {
match span.desugaring_kind() {
Expand All @@ -103,12 +105,12 @@ impl<'tcx> ThirBuildCx<'tcx> {
// ignore async for loops
if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(expr.hir_id) {
std::assert_matches!(expr.kind, hir::ExprKind::DropTemps(..));
attrs = parsed_attrs(expr.hir_id, self.tcx)
loop_hint_attrs = filter_loop_hint_attrs(expr.hir_id, self.tcx)

@JonathanBrouwer JonathanBrouwer Sep 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it a problem to store these attributes in the thir, but it is not a problem to store these attributes in the hir?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution this PR proposes is fine, but it feels like "this should work" to me

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, I think we just never have them being en/de/coded in queries otherwise?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the hir is also stored in a query, so that's not any different.
I'd really like to understand the problem, so we can be sure we're implementing a fix and not a workaround

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah the HIR is never encoded to disk, so this is not a problem in the HIR.
The THIR is encoded to disk so this is a problem there.

@Zalathar Zalathar Sep 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth, I'm fairly sure THIR is not stored to disk.

}
}
// For loops defined with `loop` and `while`, the expr already has the attrs
Some(DesugaringKind::WhileLoop) | None => {
attrs = parsed_attrs(hir_expr.hir_id, self.tcx);
loop_hint_attrs = filter_loop_hint_attrs(hir_expr.hir_id, self.tcx);
}
_ => (),
}
Expand All @@ -128,8 +130,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
let ty = expr.ty;
let value = self.thir.exprs.push(expr);

if !attrs.is_empty() {
self.thir.attributes.insert(value, attrs);
if !loop_hint_attrs.is_empty() {
self.thir.loop_hint_attrs.insert(value, loop_hint_attrs);
}

// Finally, wrap this up in the expr's scope.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/framework/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {

blocks.push(mir::BasicBlockData::new_stmts(
std::iter::repeat(&nop).cloned().take(n).collect(),
Some(mir::Terminator { source_info, kind, attributes: ThinVec::new() }),
Some(mir::Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }),
false,
))
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/add_call_guards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
Some(Terminator {
source_info,
kind: TerminatorKind::Goto { target },
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
}),
is_cleanup,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fn add_move_for_packed_drop<'tcx>(
Some(Terminator {
source_info,
kind: TerminatorKind::Goto { target },
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
}),
is_cleanup,
));
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_mir_transform/src/check_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'tcx> crate::MirPass<'tcx> for CheckEnums {
basic_blocks[block].terminator = Some(Terminator {
source_info,
kind: TerminatorKind::Goto { target: new_block },
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});
}
EnumCheckType::Direct { source_op, discr, op_size, valid_discrs } => {
Expand Down Expand Up @@ -395,7 +395,7 @@ fn insert_direct_enum_check<'tcx>(
invalid_discr_block,
),
},
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});

// Abort in case of an invalid enum discriminant.
Expand All @@ -415,7 +415,7 @@ fn insert_direct_enum_check<'tcx>(
// make a failing UB check turn into much worse UB when we start unwinding.
unwind: UnwindAction::Unreachable,
},
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});
}

Expand Down Expand Up @@ -461,7 +461,7 @@ fn insert_uninhabited_enum_check<'tcx>(
// make a failing UB check turn into much worse UB when we start unwinding.
unwind: UnwindAction::Unreachable,
},
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});
}

Expand Down Expand Up @@ -539,6 +539,6 @@ fn insert_niche_check<'tcx>(
// make a failing UB check turn into much worse UB when we start unwinding.
unwind: UnwindAction::Unreachable,
},
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});
}
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/check_pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub(crate) fn check_pointers<'tcx, F>(
// worse UB when we start unwinding.
unwind: UnwindAction::Unreachable,
},
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/coroutine/drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>(
drop: None,
};
body.basic_blocks_mut()[call_bb].terminator =
Some(Terminator { source_info, kind, attributes: ThinVec::new() });
Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() });

// Run derefer to fix Derefs that are not in the first place
deref_finder(tcx, &mut body, false);
Expand Down
18 changes: 11 additions & 7 deletions compiler/rustc_mir_transform/src/coroutine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl<'tcx> TransformVisitor<'tcx> {
Some(Terminator {
source_info,
kind: TerminatorKind::Return,
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
}),
false,
));
Expand Down Expand Up @@ -744,14 +744,14 @@ fn insert_switch<'tcx>(
body.basic_blocks_mut()[START_BLOCK].terminator = Some(Terminator {
source_info: SourceInfo::outermost(body.span),
kind: switch,
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});
}

fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock {
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().push(BasicBlockData::new(
Some(Terminator { source_info, kind, attributes: ThinVec::new() }),
Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }),
false,
))
}
Expand All @@ -776,7 +776,11 @@ fn insert_poll_ready_block<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ba
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().push(BasicBlockData::new_stmts(
[return_poll_ready_assign(tcx, source_info)].to_vec(),
Some(Terminator { source_info, kind: TerminatorKind::Return, attributes: ThinVec::new() }),
Some(Terminator {
source_info,
kind: TerminatorKind::Return,
loop_hint_attrs: ThinVec::new(),
}),
false,
))
}
Expand Down Expand Up @@ -835,7 +839,7 @@ fn generate_poison_block_and_redirect_unwinds_there<'tcx>(
source_info,
kind: TerminatorKind::UnwindResume,

attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
}),
true,
));
Expand All @@ -851,7 +855,7 @@ fn generate_poison_block_and_redirect_unwinds_there<'tcx>(
source_info,
kind: TerminatorKind::Goto { target: poison_block },

attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
};
}
} else if !block.is_cleanup
Expand Down Expand Up @@ -1019,7 +1023,7 @@ fn create_cases<'tcx>(
source_info,
kind: TerminatorKind::Goto { target },

attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
}),
false,
));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/coverage/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<'tcx> MockBlocks<'tcx> {
Some(Terminator {
source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)),
kind,
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
}),
false,
))
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_transform/src/early_otherwise_branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
discr: parent_op,
targets: eq_targets,
},
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
}),
bbs[parent].is_cleanup,
);
Expand Down Expand Up @@ -230,7 +230,7 @@ fn evaluate_candidate<'tcx>(
let Terminator {
kind: TerminatorKind::SwitchInt { targets: child_targets, discr: child_discr },
source_info,
attributes: _,
loop_hint_attrs: _,
} = bbs[child].terminator()
else {
return None;
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_mir_transform/src/elaborate_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1641,7 +1641,11 @@ where
#[instrument(level = "trace", skip(self), ret)]
fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock {
self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator { source_info: self.source_info, kind: k, attributes: ThinVec::new() }),
Some(Terminator {
source_info: self.source_info,
kind: k,
loop_hint_attrs: ThinVec::new(),
}),
unwind.is_cleanup(),
))
}
Expand All @@ -1655,7 +1659,11 @@ where
) -> BasicBlock {
self.elaborator.patch().new_block(BasicBlockData::new_stmts(
statements,
Some(Terminator { source_info: self.source_info, kind: k, attributes: ThinVec::new() }),
Some(Terminator {
source_info: self.source_info,
kind: k,
loop_hint_attrs: ThinVec::new(),
}),
unwind.is_cleanup(),
))
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
Some(Terminator {
source_info: terminator.source_info,
kind: TerminatorKind::Goto { target: block },
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
}),
caller_body[block].is_cleanup,
);
Expand Down Expand Up @@ -1000,7 +1000,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
caller_body[callsite.block].terminator = Some(Terminator {
source_info: callsite.source_info,
kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
attributes: ThinVec::new(),
loop_hint_attrs: ThinVec::new(),
});

// Copy required constants from the callee_body into the caller_body. Although we are only
Expand Down
Loading
Loading