From 6b29bb6680e0df3bbcd8e9defdf0ad142e80cdf0 Mon Sep 17 00:00:00 2001 From: Sa4dUs Date: Sun, 2 Mar 2025 23:38:55 +0100 Subject: [PATCH 1/4] Prevent ICE in autodiff validation by emitting user-friendly errors --- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 673740b4aab9f..c8f13dc0bae61 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -930,13 +930,19 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { } } + // Validate input and return activities + let mut msg = "".to_string(); for &input in &arg_activities { if !valid_input_activity(mode, input) { - span_bug!(attr.span(), "Invalid input activity {} for {} mode", input, mode); + msg = format!("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); + msg = format!("Invalid return activity {} for {} mode", ret_activity, mode); + } + if msg != "".to_string() { + tcx.dcx().struct_span_err(attr.span(), msg).with_note("invalid activity").emit(); + return Some(AutoDiffAttrs::error()); } Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities }) From cf8e1f5e0faed0a8f50ccfecedb1e4fad8d79191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= <69964857+Sa4dUs@users.noreply.github.com> Date: Fri, 7 Mar 2025 17:37:50 +0100 Subject: [PATCH 2/4] Fix ICE for invalid return activity and proper error handling --- compiler/rustc_builtin_macros/messages.ftl | 2 + compiler/rustc_builtin_macros/src/autodiff.rs | 15 +++++- compiler/rustc_builtin_macros/src/errors.rs | 9 ++++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 19 +------ tests/ui/autodiff/autodiff_illegal.rs | 52 +++++++++++++------ tests/ui/autodiff/autodiff_illegal.stderr | 52 ++++++++++++++----- 6 files changed, 100 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 4cac7cb93f581..9dac7a8aaf428 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -75,8 +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_not_build = this rustc version does not support autodiff 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_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 .label = not applicable here diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 6d9c35756574e..6707ab8edde9f 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -8,7 +8,8 @@ mod llvm_enzyme { use std::string::String; 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::token::{Token, TokenKind}; @@ -632,10 +633,22 @@ mod llvm_enzyme { 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 { // This is not the right signature, but we can continue parsing. return (sig.clone(), new_inputs, idents, true); } + let unsafe_activities = x .input_activity .iter() diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index ab1e0d8ee896b..30597944124cb 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -185,6 +185,15 @@ mod autodiff { 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)] #[diag(builtin_macros_autodiff_mode)] pub(crate) struct AutoDiffInvalidMode { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index c8f13dc0bae61..a01f5d372a2da 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,9 +1,7 @@ use std::str::FromStr; use rustc_abi::ExternAbi; -use rustc_ast::expand::autodiff_attrs::{ - AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, -}; +use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{MetaItem, MetaItemInner, attr}; use rustc_attr_parsing::ReprAttr::ReprAlign; use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; @@ -930,21 +928,6 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { } } - // Validate input and return activities - let mut msg = "".to_string(); - for &input in &arg_activities { - if !valid_input_activity(mode, input) { - msg = format!("Invalid input activity {} for {} mode", input, mode); - } - } - if !valid_ret_activity(mode, ret_activity) { - msg = format!("Invalid return activity {} for {} mode", ret_activity, mode); - } - if msg != "".to_string() { - tcx.dcx().struct_span_err(attr.span(), msg).with_note("invalid activity").emit(); - return Some(AutoDiffAttrs::error()); - } - Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities }) } diff --git a/tests/ui/autodiff/autodiff_illegal.rs b/tests/ui/autodiff/autodiff_illegal.rs index c0548d2bbb8ff..e810b9ba565ba 100644 --- a/tests/ui/autodiff/autodiff_illegal.rs +++ b/tests/ui/autodiff/autodiff_illegal.rs @@ -12,41 +12,40 @@ use std::autodiff::autodiff; // We can't use Duplicated on scalars #[autodiff(df1, Reverse, Duplicated)] pub fn f1(x: f64) { -//~^ ERROR Duplicated can not be used for this type + //~^ ERROR Duplicated can not be used for this type unimplemented!() } // Too many activities #[autodiff(df3, Reverse, Duplicated, Const)] pub fn f3(x: f64) { -//~^^ ERROR expected 1 activities, but found 2 + //~^^ ERROR expected 1 activities, but found 2 unimplemented!() } // To few activities #[autodiff(df4, Reverse)] pub fn f4(x: f64) { -//~^^ ERROR expected 1 activities, but found 0 + //~^^ ERROR expected 1 activities, but found 0 unimplemented!() } // We can't use Dual in Reverse mode #[autodiff(df5, Reverse, Dual)] pub fn f5(x: f64) { -//~^^ ERROR Dual can not be used in Reverse Mode + //~^^ ERROR Dual can not be used in Reverse Mode unimplemented!() } // We can't use Duplicated in Forward mode #[autodiff(df6, Forward, Duplicated)] pub fn f6(x: f64) { -//~^^ ERROR Duplicated can not be used in Forward Mode -//~^^ ERROR Duplicated can not be used for this type + //~^^ ERROR Duplicated can not be used in Forward Mode + //~^^ ERROR Duplicated can not be used for this type unimplemented!() } fn dummy() { - #[autodiff(df7, Forward, Dual)] let mut x = 5; //~^ ERROR autodiff must be applied to function @@ -64,21 +63,21 @@ fn dummy() { // Malformed, where args? #[autodiff] pub fn f7(x: f64) { -//~^ ERROR autodiff must be applied to function + //~^ ERROR autodiff must be applied to function unimplemented!() } // Malformed, where args? #[autodiff()] pub fn f8(x: f64) { -//~^ ERROR autodiff requires at least a name and mode + //~^ ERROR autodiff requires at least a name and mode unimplemented!() } // Invalid attribute syntax #[autodiff = ""] pub fn f9(x: f64) { -//~^ ERROR autodiff must be applied to function + //~^ ERROR autodiff must be applied to function unimplemented!() } @@ -87,21 +86,21 @@ fn fn_exists() {} // We colide with an already existing function #[autodiff(fn_exists, Reverse, Active)] 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!() } // Malformed, missing a mode #[autodiff(df11)] pub fn f11() { -//~^ ERROR autodiff requires at least a name and mode + //~^ ERROR autodiff requires at least a name and mode unimplemented!() } // Invalid Mode #[autodiff(df12, Debug)] pub fn f12() { -//~^^ ERROR unknown Mode: `Debug`. Use `Forward` or `Reverse` + //~^^ ERROR unknown Mode: `Debug`. Use `Forward` or `Reverse` unimplemented!() } @@ -109,7 +108,7 @@ pub fn f12() { // or use two autodiff macros. #[autodiff(df13, Forward, Reverse)] pub fn f13() { -//~^^ ERROR did not recognize Activity: `Reverse` + //~^^ ERROR did not recognize Activity: `Reverse` unimplemented!() } @@ -130,7 +129,7 @@ type MyFloat = f32; // like THIR which has type information available. #[autodiff(df15, Reverse, Active, Active)] 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!() } @@ -141,7 +140,9 @@ fn f16(x: f32) -> MyFloat { } #[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 #[autodiff(df17, Reverse, Active, Active)] @@ -156,5 +157,24 @@ fn f18(x: F64Trans) -> f64 { 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() {} diff --git a/tests/ui/autodiff/autodiff_illegal.stderr b/tests/ui/autodiff/autodiff_illegal.stderr index 3a7242b2f5d95..47d53492700ba 100644 --- a/tests/ui/autodiff/autodiff_illegal.stderr +++ b/tests/ui/autodiff/autodiff_illegal.stderr @@ -1,5 +1,5 @@ error[E0658]: attributes on expressions are experimental - --> $DIR/autodiff_illegal.rs:54:5 + --> $DIR/autodiff_illegal.rs:53:5 | LL | #[autodiff(df7, Forward, Dual)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,25 +53,25 @@ LL | pub fn f6(x: f64) { | ^^^ error: autodiff must be applied to function - --> $DIR/autodiff_illegal.rs:51:5 + --> $DIR/autodiff_illegal.rs:50:5 | LL | let mut x = 5; | ^^^^^^^^^^^^^^ error: autodiff must be applied to function - --> $DIR/autodiff_illegal.rs:55:5 + --> $DIR/autodiff_illegal.rs:54:5 | LL | x = x + 3; | ^ 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 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 | | @@ -80,7 +80,7 @@ LL | | } | |_^ 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 | | @@ -89,7 +89,7 @@ LL | | } | |_^ 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 | | @@ -98,7 +98,7 @@ LL | | } | |_^ 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() {} | -------------- 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) 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 | | @@ -119,19 +119,43 @@ LL | | } | |_^ error: unknown Mode: `Debug`. Use `Forward` or `Reverse` - --> $DIR/autodiff_illegal.rs:102:18 + --> $DIR/autodiff_illegal.rs:101:18 | LL | #[autodiff(df12, Debug)] | ^^^^^ error: did not recognize Activity: `Reverse` - --> $DIR/autodiff_illegal.rs:110:27 + --> $DIR/autodiff_illegal.rs:109:27 | 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` - --> $DIR/autodiff_illegal.rs:131:1 + --> $DIR/autodiff_illegal.rs:130:1 | LL | #[autodiff(df15, Reverse, Active, Active)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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) 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)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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) -error: aborting due to 19 previous errors +error: aborting due to 22 previous errors Some errors have detailed explanations: E0428, E0433, E0658. For more information about an error, try `rustc --explain E0428`. From 33f9a491eb97af0cc72df70fd10724eda2453d45 Mon Sep 17 00:00:00 2001 From: Sa4dUs Date: Mon, 10 Mar 2025 13:58:10 +0100 Subject: [PATCH 3/4] Combine autodiff errors together --- compiler/rustc_builtin_macros/messages.ftl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 9dac7a8aaf428..3f03834f8d781 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -77,9 +77,8 @@ 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_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_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 .label = not applicable here .label2 = not a `struct`, `enum` or `union` From 8546e015b4a04e9c397478ae1e27a5370d2c638b Mon Sep 17 00:00:00 2001 From: Sa4dUs Date: Mon, 10 Mar 2025 16:05:27 +0100 Subject: [PATCH 4/4] Add individual activity span availability FIXME --- compiler/rustc_builtin_macros/src/autodiff.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 6707ab8edde9f..cae806c6da776 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -586,6 +586,8 @@ mod llvm_enzyme { // // 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. + // FIXME(Sa4dUs): make individual activities' span available so errors + // can point to only the activity instead of the entire attribute fn gen_enzyme_decl( ecx: &ExtCtxt<'_>, sig: &ast::FnSig,