Rollup merge of #138231 - Sa4dUs:autodiff-ice, r=ZuseZ4

Prevent ICE in autodiff validation by emitting user-friendly errors

This PR moves `valid_ret_activity` and `valid_input_activity` checks to the macro expansion phase in compiler/rustc_builtin_macros/src/autodiff.rs, replacing the following internal compiler error (ICE):
```
error: internal compiler error:
compiler/rustc_codegen_ssa/src/codegen_attrs.rs:935:13:
Invalid input activity Dual for Reverse mode
```
with a more user-friendly message.

The issue specifically affected the test file `tests/ui/autodiff/autodiff_illegal.rs`, impacting the functions `f5` and `f6`.

The ICE can be reproduced by following [Enzyme's Rustbook](https://enzymead.github.io/rustbook/installation.html) installation guide.

Additionally, this PR adds tests for invalid return activity in `autodiff_illegal.rs`, which previously triggered an unnoticed ICE before these fixes.

r? ``@oli-obk``
This commit is contained in:
Matthias Krüger 2025-03-11 19:35:29 +01:00 committed by GitHub
commit caa2d008f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 102 additions and 44 deletions

View file

@ -75,9 +75,10 @@ builtin_macros_autodiff_mode = unknown Mode: `{$mode}`. Use `Forward` or `Revers
builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode
builtin_macros_autodiff_not_build = this rustc version does not support autodiff builtin_macros_autodiff_not_build = this rustc version does not support autodiff
builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found} builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found}
builtin_macros_autodiff_ret_activity = invalid return activity {$act} in {$mode} Mode
builtin_macros_autodiff_ty_activity = {$act} can not be used for this type builtin_macros_autodiff_ty_activity = {$act} can not be used for this type
builtin_macros_autodiff_unknown_activity = did not recognize Activity: `{$act}` builtin_macros_autodiff_unknown_activity = did not recognize Activity: `{$act}`
builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
.label = not applicable here .label = not applicable here
.label2 = not a `struct`, `enum` or `union` .label2 = not a `struct`, `enum` or `union`

View file

@ -8,7 +8,8 @@ mod llvm_enzyme {
use std::string::String; use std::string::String;
use rustc_ast::expand::autodiff_attrs::{ use rustc_ast::expand::autodiff_attrs::{
AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ty_for_activity, AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
valid_ty_for_activity,
}; };
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{Token, TokenKind}; use rustc_ast::token::{Token, TokenKind};
@ -576,6 +577,8 @@ mod llvm_enzyme {
// //
// Error handling: If the user provides an invalid configuration (incorrect numbers, types, or // Error handling: If the user provides an invalid configuration (incorrect numbers, types, or
// both), we emit an error and return the original signature. This allows us to continue parsing. // both), we emit an error and return the original signature. This allows us to continue parsing.
// FIXME(Sa4dUs): make individual activities' span available so errors
// can point to only the activity instead of the entire attribute
fn gen_enzyme_decl( fn gen_enzyme_decl(
ecx: &ExtCtxt<'_>, ecx: &ExtCtxt<'_>,
sig: &ast::FnSig, sig: &ast::FnSig,
@ -623,10 +626,22 @@ mod llvm_enzyme {
errors = true; errors = true;
} }
} }
if has_ret && !valid_ret_activity(x.mode, x.ret_activity) {
dcx.emit_err(errors::AutoDiffInvalidRetAct {
span,
mode: x.mode.to_string(),
act: x.ret_activity.to_string(),
});
// We don't set `errors = true` to avoid annoying type errors relative
// to the expanded macro type signature
}
if errors { if errors {
// This is not the right signature, but we can continue parsing. // This is not the right signature, but we can continue parsing.
return (sig.clone(), new_inputs, idents, true); return (sig.clone(), new_inputs, idents, true);
} }
let unsafe_activities = x let unsafe_activities = x
.input_activity .input_activity
.iter() .iter()

View file

@ -185,6 +185,15 @@ mod autodiff {
pub(crate) act: String, pub(crate) act: String,
} }
#[derive(Diagnostic)]
#[diag(builtin_macros_autodiff_ret_activity)]
pub(crate) struct AutoDiffInvalidRetAct {
#[primary_span]
pub(crate) span: Span,
pub(crate) mode: String,
pub(crate) act: String,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(builtin_macros_autodiff_mode)] #[diag(builtin_macros_autodiff_mode)]
pub(crate) struct AutoDiffInvalidMode { pub(crate) struct AutoDiffInvalidMode {

View file

@ -1,9 +1,7 @@
use std::str::FromStr; use std::str::FromStr;
use rustc_abi::ExternAbi; use rustc_abi::ExternAbi;
use rustc_ast::expand::autodiff_attrs::{ use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
};
use rustc_ast::{MetaItem, MetaItemInner, attr}; use rustc_ast::{MetaItem, MetaItemInner, attr};
use rustc_attr_parsing::ReprAttr::ReprAlign; use rustc_attr_parsing::ReprAttr::ReprAlign;
use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr};
@ -874,15 +872,6 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
} }
} }
for &input in &arg_activities {
if !valid_input_activity(mode, input) {
span_bug!(attr.span(), "Invalid input activity {} for {} mode", input, mode);
}
}
if !valid_ret_activity(mode, ret_activity) {
span_bug!(attr.span(), "Invalid return activity {} for {} mode", ret_activity, mode);
}
Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities }) Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities })
} }

View file

@ -12,41 +12,40 @@ use std::autodiff::autodiff;
// We can't use Duplicated on scalars // We can't use Duplicated on scalars
#[autodiff(df1, Reverse, Duplicated)] #[autodiff(df1, Reverse, Duplicated)]
pub fn f1(x: f64) { pub fn f1(x: f64) {
//~^ ERROR Duplicated can not be used for this type //~^ ERROR Duplicated can not be used for this type
unimplemented!() unimplemented!()
} }
// Too many activities // Too many activities
#[autodiff(df3, Reverse, Duplicated, Const)] #[autodiff(df3, Reverse, Duplicated, Const)]
pub fn f3(x: f64) { pub fn f3(x: f64) {
//~^^ ERROR expected 1 activities, but found 2 //~^^ ERROR expected 1 activities, but found 2
unimplemented!() unimplemented!()
} }
// To few activities // To few activities
#[autodiff(df4, Reverse)] #[autodiff(df4, Reverse)]
pub fn f4(x: f64) { pub fn f4(x: f64) {
//~^^ ERROR expected 1 activities, but found 0 //~^^ ERROR expected 1 activities, but found 0
unimplemented!() unimplemented!()
} }
// We can't use Dual in Reverse mode // We can't use Dual in Reverse mode
#[autodiff(df5, Reverse, Dual)] #[autodiff(df5, Reverse, Dual)]
pub fn f5(x: f64) { pub fn f5(x: f64) {
//~^^ ERROR Dual can not be used in Reverse Mode //~^^ ERROR Dual can not be used in Reverse Mode
unimplemented!() unimplemented!()
} }
// We can't use Duplicated in Forward mode // We can't use Duplicated in Forward mode
#[autodiff(df6, Forward, Duplicated)] #[autodiff(df6, Forward, Duplicated)]
pub fn f6(x: f64) { pub fn f6(x: f64) {
//~^^ ERROR Duplicated can not be used in Forward Mode //~^^ ERROR Duplicated can not be used in Forward Mode
//~^^ ERROR Duplicated can not be used for this type //~^^ ERROR Duplicated can not be used for this type
unimplemented!() unimplemented!()
} }
fn dummy() { fn dummy() {
#[autodiff(df7, Forward, Dual)] #[autodiff(df7, Forward, Dual)]
let mut x = 5; let mut x = 5;
//~^ ERROR autodiff must be applied to function //~^ ERROR autodiff must be applied to function
@ -64,21 +63,21 @@ fn dummy() {
// Malformed, where args? // Malformed, where args?
#[autodiff] #[autodiff]
pub fn f7(x: f64) { pub fn f7(x: f64) {
//~^ ERROR autodiff must be applied to function //~^ ERROR autodiff must be applied to function
unimplemented!() unimplemented!()
} }
// Malformed, where args? // Malformed, where args?
#[autodiff()] #[autodiff()]
pub fn f8(x: f64) { pub fn f8(x: f64) {
//~^ ERROR autodiff requires at least a name and mode //~^ ERROR autodiff requires at least a name and mode
unimplemented!() unimplemented!()
} }
// Invalid attribute syntax // Invalid attribute syntax
#[autodiff = ""] #[autodiff = ""]
pub fn f9(x: f64) { pub fn f9(x: f64) {
//~^ ERROR autodiff must be applied to function //~^ ERROR autodiff must be applied to function
unimplemented!() unimplemented!()
} }
@ -87,21 +86,21 @@ fn fn_exists() {}
// We colide with an already existing function // We colide with an already existing function
#[autodiff(fn_exists, Reverse, Active)] #[autodiff(fn_exists, Reverse, Active)]
pub fn f10(x: f64) { pub fn f10(x: f64) {
//~^^ ERROR the name `fn_exists` is defined multiple times [E0428] //~^^ ERROR the name `fn_exists` is defined multiple times [E0428]
unimplemented!() unimplemented!()
} }
// Malformed, missing a mode // Malformed, missing a mode
#[autodiff(df11)] #[autodiff(df11)]
pub fn f11() { pub fn f11() {
//~^ ERROR autodiff requires at least a name and mode //~^ ERROR autodiff requires at least a name and mode
unimplemented!() unimplemented!()
} }
// Invalid Mode // Invalid Mode
#[autodiff(df12, Debug)] #[autodiff(df12, Debug)]
pub fn f12() { pub fn f12() {
//~^^ ERROR unknown Mode: `Debug`. Use `Forward` or `Reverse` //~^^ ERROR unknown Mode: `Debug`. Use `Forward` or `Reverse`
unimplemented!() unimplemented!()
} }
@ -109,7 +108,7 @@ pub fn f12() {
// or use two autodiff macros. // or use two autodiff macros.
#[autodiff(df13, Forward, Reverse)] #[autodiff(df13, Forward, Reverse)]
pub fn f13() { pub fn f13() {
//~^^ ERROR did not recognize Activity: `Reverse` //~^^ ERROR did not recognize Activity: `Reverse`
unimplemented!() unimplemented!()
} }
@ -130,7 +129,7 @@ type MyFloat = f32;
// like THIR which has type information available. // like THIR which has type information available.
#[autodiff(df15, Reverse, Active, Active)] #[autodiff(df15, Reverse, Active, Active)]
fn f15(x: MyFloat) -> f32 { fn f15(x: MyFloat) -> f32 {
//~^^ ERROR failed to resolve: use of undeclared type `MyFloat` [E0433] //~^^ ERROR failed to resolve: use of undeclared type `MyFloat` [E0433]
unimplemented!() unimplemented!()
} }
@ -141,7 +140,9 @@ fn f16(x: f32) -> MyFloat {
} }
#[repr(transparent)] #[repr(transparent)]
struct F64Trans { inner: f64 } struct F64Trans {
inner: f64,
}
// We would like to support `#[repr(transparent)]` f32/f64 wrapper in return type in the future // We would like to support `#[repr(transparent)]` f32/f64 wrapper in return type in the future
#[autodiff(df17, Reverse, Active, Active)] #[autodiff(df17, Reverse, Active, Active)]
@ -156,5 +157,24 @@ fn f18(x: F64Trans) -> f64 {
unimplemented!() unimplemented!()
} }
// Invalid return activity
#[autodiff(df19, Forward, Dual, Active)]
fn f19(x: f32) -> f32 {
//~^^ ERROR invalid return activity Active in Forward Mode
unimplemented!()
}
#[autodiff(df20, Reverse, Active, Dual)]
fn f20(x: f32) -> f32 {
//~^^ ERROR invalid return activity Dual in Reverse Mode
unimplemented!()
}
// Duplicated cannot be used as return activity
#[autodiff(df21, Reverse, Active, Duplicated)]
fn f21(x: f32) -> f32 {
//~^^ ERROR invalid return activity Duplicated in Reverse Mode
unimplemented!()
}
fn main() {} fn main() {}

View file

@ -1,5 +1,5 @@
error[E0658]: attributes on expressions are experimental error[E0658]: attributes on expressions are experimental
--> $DIR/autodiff_illegal.rs:54:5 --> $DIR/autodiff_illegal.rs:53:5
| |
LL | #[autodiff(df7, Forward, Dual)] LL | #[autodiff(df7, Forward, Dual)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -53,25 +53,25 @@ LL | pub fn f6(x: f64) {
| ^^^ | ^^^
error: autodiff must be applied to function error: autodiff must be applied to function
--> $DIR/autodiff_illegal.rs:51:5 --> $DIR/autodiff_illegal.rs:50:5
| |
LL | let mut x = 5; LL | let mut x = 5;
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
error: autodiff must be applied to function error: autodiff must be applied to function
--> $DIR/autodiff_illegal.rs:55:5 --> $DIR/autodiff_illegal.rs:54:5
| |
LL | x = x + 3; LL | x = x + 3;
| ^ | ^
error: autodiff must be applied to function error: autodiff must be applied to function
--> $DIR/autodiff_illegal.rs:60:5 --> $DIR/autodiff_illegal.rs:59:5
| |
LL | let add_one_v2 = |x: u32| -> u32 { x + 1 }; LL | let add_one_v2 = |x: u32| -> u32 { x + 1 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: autodiff must be applied to function error: autodiff must be applied to function
--> $DIR/autodiff_illegal.rs:66:1 --> $DIR/autodiff_illegal.rs:65:1
| |
LL | / pub fn f7(x: f64) { LL | / pub fn f7(x: f64) {
LL | | LL | |
@ -80,7 +80,7 @@ LL | | }
| |_^ | |_^
error: autodiff requires at least a name and mode error: autodiff requires at least a name and mode
--> $DIR/autodiff_illegal.rs:73:1 --> $DIR/autodiff_illegal.rs:72:1
| |
LL | / pub fn f8(x: f64) { LL | / pub fn f8(x: f64) {
LL | | LL | |
@ -89,7 +89,7 @@ LL | | }
| |_^ | |_^
error: autodiff must be applied to function error: autodiff must be applied to function
--> $DIR/autodiff_illegal.rs:80:1 --> $DIR/autodiff_illegal.rs:79:1
| |
LL | / pub fn f9(x: f64) { LL | / pub fn f9(x: f64) {
LL | | LL | |
@ -98,7 +98,7 @@ LL | | }
| |_^ | |_^
error[E0428]: the name `fn_exists` is defined multiple times error[E0428]: the name `fn_exists` is defined multiple times
--> $DIR/autodiff_illegal.rs:88:1 --> $DIR/autodiff_illegal.rs:87:1
| |
LL | fn fn_exists() {} LL | fn fn_exists() {}
| -------------- previous definition of the value `fn_exists` here | -------------- previous definition of the value `fn_exists` here
@ -110,7 +110,7 @@ LL | #[autodiff(fn_exists, Reverse, Active)]
= note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
error: autodiff requires at least a name and mode error: autodiff requires at least a name and mode
--> $DIR/autodiff_illegal.rs:96:1 --> $DIR/autodiff_illegal.rs:95:1
| |
LL | / pub fn f11() { LL | / pub fn f11() {
LL | | LL | |
@ -119,19 +119,43 @@ LL | | }
| |_^ | |_^
error: unknown Mode: `Debug`. Use `Forward` or `Reverse` error: unknown Mode: `Debug`. Use `Forward` or `Reverse`
--> $DIR/autodiff_illegal.rs:102:18 --> $DIR/autodiff_illegal.rs:101:18
| |
LL | #[autodiff(df12, Debug)] LL | #[autodiff(df12, Debug)]
| ^^^^^ | ^^^^^
error: did not recognize Activity: `Reverse` error: did not recognize Activity: `Reverse`
--> $DIR/autodiff_illegal.rs:110:27 --> $DIR/autodiff_illegal.rs:109:27
| |
LL | #[autodiff(df13, Forward, Reverse)] LL | #[autodiff(df13, Forward, Reverse)]
| ^^^^^^^ | ^^^^^^^
error: invalid return activity Active in Forward Mode
--> $DIR/autodiff_illegal.rs:161:1
|
LL | #[autodiff(df19, Forward, Dual, Active)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid return activity Dual in Reverse Mode
--> $DIR/autodiff_illegal.rs:167:1
|
LL | #[autodiff(df20, Reverse, Active, Dual)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid return activity Duplicated in Reverse Mode
--> $DIR/autodiff_illegal.rs:174:1
|
LL | #[autodiff(df21, Reverse, Active, Duplicated)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0433]: failed to resolve: use of undeclared type `MyFloat` error[E0433]: failed to resolve: use of undeclared type `MyFloat`
--> $DIR/autodiff_illegal.rs:131:1 --> $DIR/autodiff_illegal.rs:130:1
| |
LL | #[autodiff(df15, Reverse, Active, Active)] LL | #[autodiff(df15, Reverse, Active, Active)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat`
@ -139,14 +163,14 @@ LL | #[autodiff(df15, Reverse, Active, Active)]
= note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0433]: failed to resolve: use of undeclared type `F64Trans` error[E0433]: failed to resolve: use of undeclared type `F64Trans`
--> $DIR/autodiff_illegal.rs:153:1 --> $DIR/autodiff_illegal.rs:154:1
| |
LL | #[autodiff(df18, Reverse, Active, Active)] LL | #[autodiff(df18, Reverse, Active, Active)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans`
| |
= note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 19 previous errors error: aborting due to 22 previous errors
Some errors have detailed explanations: E0428, E0433, E0658. Some errors have detailed explanations: E0428, E0433, E0658.
For more information about an error, try `rustc --explain E0428`. For more information about an error, try `rustc --explain E0428`.