1
Fork 0

Auto merge of #139473 - Kobzol:rollup-ycksn9b, r=Kobzol

Rollup of 5 pull requests

Successful merges:

 - #138314 (fix usage of `autodiff` macro with inner functions)
 - #139426 (Make the UnifyKey and UnifyValue imports non-nightly)
 - #139431 (Remove LLVM 18 inline ASM span fallback)
 - #139456 (style guide: add let-chain rules)
 - #139467 (More trivial tweaks)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-04-07 06:27:35 +00:00
commit 8fb32ab8e5
12 changed files with 193 additions and 78 deletions

View file

@ -4589,6 +4589,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"derive-where", "derive-where",
"ena",
"indexmap", "indexmap",
"rustc-hash 1.1.0", "rustc-hash 1.1.0",
"rustc_ast_ir", "rustc_ast_ir",

View file

@ -17,7 +17,7 @@ mod llvm_enzyme {
use rustc_ast::visit::AssocCtxt::*; use rustc_ast::visit::AssocCtxt::*;
use rustc_ast::{ use rustc_ast::{
self as ast, AssocItemKind, BindingMode, ExprKind, FnRetTy, FnSig, Generics, ItemKind, self as ast, AssocItemKind, BindingMode, ExprKind, FnRetTy, FnSig, Generics, ItemKind,
MetaItemInner, PatKind, QSelf, TyKind, MetaItemInner, PatKind, QSelf, TyKind, Visibility,
}; };
use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::{Ident, Span, Symbol, kw, sym}; use rustc_span::{Ident, Span, Symbol, kw, sym};
@ -72,6 +72,16 @@ mod llvm_enzyme {
} }
} }
// Get information about the function the macro is applied to
fn extract_item_info(iitem: &P<ast::Item>) -> Option<(Visibility, FnSig, Ident)> {
match &iitem.kind {
ItemKind::Fn(box ast::Fn { sig, ident, .. }) => {
Some((iitem.vis.clone(), sig.clone(), ident.clone()))
}
_ => None,
}
}
pub(crate) fn from_ast( pub(crate) fn from_ast(
ecx: &mut ExtCtxt<'_>, ecx: &mut ExtCtxt<'_>,
meta_item: &ThinVec<MetaItemInner>, meta_item: &ThinVec<MetaItemInner>,
@ -199,32 +209,26 @@ mod llvm_enzyme {
return vec![item]; return vec![item];
} }
let dcx = ecx.sess.dcx(); let dcx = ecx.sess.dcx();
// first get the annotable item:
let (primal, sig, is_impl): (Ident, FnSig, bool) = match &item { // first get information about the annotable item:
Annotatable::Item(iitem) => { let Some((vis, sig, primal)) = (match &item {
let (ident, sig) = match &iitem.kind { Annotatable::Item(iitem) => extract_item_info(iitem),
ItemKind::Fn(box ast::Fn { ident, sig, .. }) => (ident, sig), Annotatable::Stmt(stmt) => match &stmt.kind {
_ => { ast::StmtKind::Item(iitem) => extract_item_info(iitem),
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); _ => None,
return vec![item]; },
}
};
(*ident, sig.clone(), false)
}
Annotatable::AssocItem(assoc_item, Impl { of_trait: false }) => { Annotatable::AssocItem(assoc_item, Impl { of_trait: false }) => {
let (ident, sig) = match &assoc_item.kind { match &assoc_item.kind {
ast::AssocItemKind::Fn(box ast::Fn { ident, sig, .. }) => (ident, sig), ast::AssocItemKind::Fn(box ast::Fn { sig, ident, .. }) => {
_ => { Some((assoc_item.vis.clone(), sig.clone(), ident.clone()))
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
return vec![item];
} }
}; _ => None,
(*ident, sig.clone(), true) }
}
_ => {
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
return vec![item];
} }
_ => None,
}) else {
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
return vec![item];
}; };
let meta_item_vec: ThinVec<MetaItemInner> = match meta_item.kind { let meta_item_vec: ThinVec<MetaItemInner> = match meta_item.kind {
@ -238,15 +242,6 @@ mod llvm_enzyme {
let has_ret = has_ret(&sig.decl.output); let has_ret = has_ret(&sig.decl.output);
let sig_span = ecx.with_call_site_ctxt(sig.span); let sig_span = ecx.with_call_site_ctxt(sig.span);
let vis = match &item {
Annotatable::Item(iitem) => iitem.vis.clone(),
Annotatable::AssocItem(assoc_item, _) => assoc_item.vis.clone(),
_ => {
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
return vec![item];
}
};
// create TokenStream from vec elemtents: // create TokenStream from vec elemtents:
// meta_item doesn't have a .tokens field // meta_item doesn't have a .tokens field
let mut ts: Vec<TokenTree> = vec![]; let mut ts: Vec<TokenTree> = vec![];
@ -379,6 +374,22 @@ mod llvm_enzyme {
} }
Annotatable::AssocItem(assoc_item.clone(), i) Annotatable::AssocItem(assoc_item.clone(), i)
} }
Annotatable::Stmt(ref mut stmt) => {
match stmt.kind {
ast::StmtKind::Item(ref mut iitem) => {
if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
iitem.attrs.push(attr);
}
if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind))
{
iitem.attrs.push(inline_never.clone());
}
}
_ => unreachable!("stmt kind checked previously"),
};
Annotatable::Stmt(stmt.clone())
}
_ => { _ => {
unreachable!("annotatable kind checked previously") unreachable!("annotatable kind checked previously")
} }
@ -389,22 +400,40 @@ mod llvm_enzyme {
delim: rustc_ast::token::Delimiter::Parenthesis, delim: rustc_ast::token::Delimiter::Parenthesis,
tokens: ts, tokens: ts,
}); });
let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span); let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
let d_annotatable = if is_impl { let d_annotatable = match &item {
let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); Annotatable::AssocItem(_, _) => {
let d_fn = P(ast::AssocItem { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf);
attrs: thin_vec![d_attr, inline_never], let d_fn = P(ast::AssocItem {
id: ast::DUMMY_NODE_ID, attrs: thin_vec![d_attr, inline_never],
span, id: ast::DUMMY_NODE_ID,
vis, span,
kind: assoc_item, vis,
tokens: None, kind: assoc_item,
}); tokens: None,
Annotatable::AssocItem(d_fn, Impl { of_trait: false }) });
} else { Annotatable::AssocItem(d_fn, Impl { of_trait: false })
let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); }
d_fn.vis = vis; Annotatable::Item(_) => {
Annotatable::Item(d_fn) let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf));
d_fn.vis = vis;
Annotatable::Item(d_fn)
}
Annotatable::Stmt(_) => {
let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf));
d_fn.vis = vis;
Annotatable::Stmt(P(ast::Stmt {
id: ast::DUMMY_NODE_ID,
kind: ast::StmtKind::Item(d_fn),
span,
}))
}
_ => {
unreachable!("item kind checked previously")
}
}; };
return vec![orig_annotatable, d_annotatable]; return vec![orig_annotatable, d_annotatable];

View file

@ -439,12 +439,9 @@ fn report_inline_asm(
let span = if cookie == 0 || matches!(cgcx.lto, Lto::Fat | Lto::Thin) { let span = if cookie == 0 || matches!(cgcx.lto, Lto::Fat | Lto::Thin) {
SpanData::default() SpanData::default()
} else { } else {
let lo = BytePos::from_u32(cookie as u32);
let hi = BytePos::from_u32((cookie >> 32) as u32);
SpanData { SpanData {
lo, lo: BytePos::from_u32(cookie as u32),
// LLVM version < 19 silently truncates the cookie to 32 bits in some situations. hi: BytePos::from_u32((cookie >> 32) as u32),
hi: if hi.to_u32() != 0 { hi } else { lo },
ctxt: SyntaxContext::root(), ctxt: SyntaxContext::root(),
parent: None, parent: None,
} }

View file

@ -446,14 +446,11 @@ fn resolve_expr<'tcx>(
// Mark this expr's scope and all parent scopes as containing `yield`. // Mark this expr's scope and all parent scopes as containing `yield`.
let mut scope = Scope { local_id: expr.hir_id.local_id, data: ScopeData::Node }; let mut scope = Scope { local_id: expr.hir_id.local_id, data: ScopeData::Node };
loop { loop {
let span = match expr.kind { let data = YieldData {
hir::ExprKind::Yield(expr, hir::YieldSource::Await { .. }) => { span: expr.span,
expr.span.shrink_to_hi().to(expr.span) expr_and_pat_count: visitor.expr_and_pat_count,
} source: *source,
_ => expr.span,
}; };
let data =
YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source };
match visitor.scope_tree.yield_in_scope.get_mut(&scope) { match visitor.scope_tree.yield_in_scope.get_mut(&scope) {
Some(yields) => yields.push(data), Some(yields) => yields.push(data),
None => { None => {

View file

@ -865,10 +865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty` // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
vec![( vec![(
ty_ref.1.ty.span.shrink_to_lo(), ty_ref.1.ty.span.shrink_to_lo(),
format!( format!("{}mut ", if ty_ref.0.ident.span.is_empty() { "" } else { " " },),
"{}mut ",
if ty_ref.0.ident.span.lo() == ty_ref.0.ident.span.hi() { "" } else { " " },
),
)] )]
}; };
sugg.extend([ sugg.extend([

View file

@ -1655,7 +1655,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty` // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
Some(mut_ty.ty.span.shrink_to_lo()) Some(mut_ty.ty.span.shrink_to_lo())
}; };
let pre = if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " }; let pre = if lt.ident.span.is_empty() { "" } else { " " };
Some(errors::UnusedAssignSuggestion { Some(errors::UnusedAssignSuggestion {
ty_span, ty_span,
pre, pre,

View file

@ -7,6 +7,7 @@ edition = "2024"
# tidy-alphabetical-start # tidy-alphabetical-start
bitflags = "2.4.1" bitflags = "2.4.1"
derive-where = "1.2.7" derive-where = "1.2.7"
ena = "0.14.3"
indexmap = "2.0.0" indexmap = "2.0.0"
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }

View file

@ -1,5 +1,6 @@
use std::hash::BuildHasherDefault; use std::hash::BuildHasherDefault;
pub use ena::unify::{NoError, UnifyKey, UnifyValue};
use rustc_hash::FxHasher; use rustc_hash::FxHasher;
pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};

View file

@ -6,9 +6,8 @@ use rustc_ast_ir::Mutability;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir::data_structures::{NoError, UnifyKey, UnifyValue};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use self::TyKind::*; use self::TyKind::*;
@ -796,7 +795,6 @@ pub enum InferTy {
/// Raw `TyVid` are used as the unification key for `sub_relations`; /// Raw `TyVid` are used as the unification key for `sub_relations`;
/// they carry no values. /// they carry no values.
#[cfg(feature = "nightly")]
impl UnifyKey for TyVid { impl UnifyKey for TyVid {
type Value = (); type Value = ();
#[inline] #[inline]
@ -812,7 +810,6 @@ impl UnifyKey for TyVid {
} }
} }
#[cfg(feature = "nightly")]
impl UnifyValue for IntVarValue { impl UnifyValue for IntVarValue {
type Error = NoError; type Error = NoError;
@ -832,7 +829,6 @@ impl UnifyValue for IntVarValue {
} }
} }
#[cfg(feature = "nightly")]
impl UnifyKey for IntVid { impl UnifyKey for IntVid {
type Value = IntVarValue; type Value = IntVarValue;
#[inline] // make this function eligible for inlining - it is quite hot. #[inline] // make this function eligible for inlining - it is quite hot.
@ -848,7 +844,6 @@ impl UnifyKey for IntVid {
} }
} }
#[cfg(feature = "nightly")]
impl UnifyValue for FloatVarValue { impl UnifyValue for FloatVarValue {
type Error = NoError; type Error = NoError;
@ -866,7 +861,6 @@ impl UnifyValue for FloatVarValue {
} }
} }
#[cfg(feature = "nightly")]
impl UnifyKey for FloatVid { impl UnifyKey for FloatVid {
type Value = FloatVarValue; type Value = FloatVarValue;
#[inline] #[inline]

View file

@ -521,8 +521,11 @@ self.pre_comment.as_ref().map_or(
## Control flow expressions ## Control flow expressions
This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for` This section covers `for` and `loop` expressions, as well as `if` and `while`
expressions. expressions with their sub-expression variants. This includes those with a
single `let` sub-expression (i.e. `if let` and `while let`)
as well as "let-chains": those with one or more `let` sub-expressions and
one or more bool-type conditions (i.e. `if a && let Some(b) = c`).
Put the keyword, any initial clauses, and the opening brace of the block all on Put the keyword, any initial clauses, and the opening brace of the block all on
a single line, if they fit. Apply the usual rules for [block a single line, if they fit. Apply the usual rules for [block
@ -548,10 +551,11 @@ if let ... {
} }
``` ```
If the control line needs to be broken, prefer to break before the `=` in `* If the control line needs to be broken, then prefer breaking after the `=` for any
let` expressions and before `in` in a `for` expression; block-indent the `let` sub-expression in an `if` or `while` expression that does not fit,
following line. If the control line is broken for any reason, put the opening and before `in` in a `for` expression; the following line should be block indented.
brace on its own line, not indented. Examples: If the control line is broken for any reason, then the opening brace should be on its
own line and not indented. Examples:
```rust ```rust
while let Some(foo) while let Some(foo)
@ -572,6 +576,68 @@ if a_long_expression
{ {
... ...
} }
if let Some(a) = b
&& another_long_expression
&& a_third_long_expression
{
// ...
}
if let Some(relatively_long_thing)
= a_long_expression
&& another_long_expression
&& a_third_long_expression
{
// ...
}
if some_expr
&& another_long_expression
&& let Some(relatively_long_thing) =
a_long_long_long_long_long_long_really_reallllllllllyyyyyyy_long_expression
&& a_third_long_expression
{
// ...
}
```
A let-chain control line is allowed to be formatted on a single line provided
it only consists of two clauses, with the first, left-hand side operand being a literal or an
`ident` (which can optionally be preceded by any number of unary prefix operators),
and the second, right-hand side operand being a single-line `let` clause. Otherwise,
the control line must be broken and formatted according to the above rules. For example:
```rust
if a && let Some(b) = foo() {
// ...
}
if true && let Some(b) = foo() {
// ...
}
let operator = if !from_hir_call && let Some(p) = parent {
// ...
};
if let Some(b) = foo()
&& a
{
// ..
}
if foo()
&& let Some(b) = bar
{
// ...
}
if gen_pos != GenericArgPosition::Type
&& let Some(b) = gen_args.bindings.first()
{
// ..
}
``` ```
Where the initial clause spans multiple lines and ends with one or more closing Where the initial clause spans multiple lines and ends with one or more closing

View file

@ -29,6 +29,8 @@ pub fn f1(x: &[f64], y: f64) -> f64 {
// Make sure, that we add the None for the default return. // Make sure, that we add the None for the default return.
// We want to make sure that we can use the macro for functions defined inside of functions
::core::panicking::panic("not implemented") ::core::panicking::panic("not implemented")
} }
#[rustc_autodiff(Forward, 1, Dual, Const, Dual)] #[rustc_autodiff(Forward, 1, Dual, Const, Dual)]
@ -158,4 +160,25 @@ fn f8_1(x: &f32, bx_0: &f32) -> f32 {
::core::hint::black_box((bx_0,)); ::core::hint::black_box((bx_0,));
::core::hint::black_box(<f32>::default()) ::core::hint::black_box(<f32>::default())
} }
pub fn f9() {
#[rustc_autodiff]
#[inline(never)]
fn inner(x: f32) -> f32 { x * x }
#[rustc_autodiff(Forward, 1, Dual, Dual)]
#[inline(never)]
fn d_inner_2(x: f32, bx_0: f32) -> (f32, f32) {
unsafe { asm!("NOP", options(pure, nomem)); };
::core::hint::black_box(inner(x));
::core::hint::black_box((bx_0,));
::core::hint::black_box(<(f32, f32)>::default())
}
#[rustc_autodiff(Forward, 1, Dual, DualOnly)]
#[inline(never)]
fn d_inner_1(x: f32, bx_0: f32) -> f32 {
unsafe { asm!("NOP", options(pure, nomem)); };
::core::hint::black_box(inner(x));
::core::hint::black_box((bx_0,));
::core::hint::black_box(<f32>::default())
}
}
fn main() {} fn main() {}

View file

@ -54,4 +54,13 @@ fn f8(x: &f32) -> f32 {
unimplemented!() unimplemented!()
} }
// We want to make sure that we can use the macro for functions defined inside of functions
pub fn f9() {
#[autodiff(d_inner_1, Forward, Dual, DualOnly)]
#[autodiff(d_inner_2, Forward, Dual, Dual)]
fn inner(x: f32) -> f32 {
x * x
}
}
fn main() {} fn main() {}