about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManuel Drehwald <git@manuel.drehwald.info>2024-10-11 20:38:43 +0200
committerManuel Drehwald <git@manuel.drehwald.info>2024-10-11 20:38:43 +0200
commit7c37d2db98ec28b633ddc69ca0cf0ca651ae00b3 (patch)
treefb9bfaea990741da2b53eb20d4c2cef826e804dd
parent624c071b997f3bab0ef086af24f59ebc95f37c59 (diff)
downloadrust-7c37d2db98ec28b633ddc69ca0cf0ca651ae00b3.tar.gz
rust-7c37d2db98ec28b633ddc69ca0cf0ca651ae00b3.zip
Add pretty, ui, and feature-gate tests for the enzyme/autodiff frontend
-rw-r--r--tests/pretty/autodiff_forward.pp107
-rw-r--r--tests/pretty/autodiff_forward.rs39
-rw-r--r--tests/pretty/autodiff_reverse.pp86
-rw-r--r--tests/pretty/autodiff_reverse.rs40
-rw-r--r--tests/ui/autodiff/autodiff_illegal.rs160
-rw-r--r--tests/ui/autodiff/autodiff_illegal.stderr152
-rw-r--r--tests/ui/autodiff/auxiliary/my_macro.rs12
-rw-r--r--tests/ui/autodiff/visibility.rs17
-rw-r--r--tests/ui/autodiff/visibility.std_autodiff.stderr24
-rw-r--r--tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr23
-rw-r--r--tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr29
-rw-r--r--tests/ui/feature-gates/feature-gate-autodiff-use.rs17
-rw-r--r--tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-autodiff.rs12
15 files changed, 744 insertions, 0 deletions
diff --git a/tests/pretty/autodiff_forward.pp b/tests/pretty/autodiff_forward.pp
new file mode 100644
index 00000000000..23c3b5b34a8
--- /dev/null
+++ b/tests/pretty/autodiff_forward.pp
@@ -0,0 +1,107 @@
+#![feature(prelude_import)]
+#![no_std]
+//@ needs-enzyme
+
+#![feature(autodiff)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+//@ pretty-mode:expanded
+//@ pretty-compare-only
+//@ pp-exact:autodiff_forward.pp
+
+// Test that forward mode ad macros are expanded correctly.
+
+use std::autodiff::autodiff;
+
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f1(x: &[f64], y: f64) -> f64 {
+
+
+
+    // Not the most interesting derivative, but who are we to judge
+
+    // We want to be sure that the same function can be differentiated in different ways
+
+    ::core::panicking::panic("not implemented")
+}
+#[rustc_autodiff(Forward, Dual, Const, Dual,)]
+#[inline(never)]
+pub fn df1(x: &[f64], bx: &[f64], y: f64) -> (f64, f64) {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f1(x, y));
+    ::core::hint::black_box((bx,));
+    ::core::hint::black_box((f1(x, y), f64::default()))
+}
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f2(x: &[f64], y: f64) -> f64 {
+    ::core::panicking::panic("not implemented")
+}
+#[rustc_autodiff(Forward, Dual, Const, Const,)]
+#[inline(never)]
+pub fn df2(x: &[f64], bx: &[f64], y: f64) -> f64 {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f2(x, y));
+    ::core::hint::black_box((bx,));
+    ::core::hint::black_box(f2(x, y))
+}
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f3(x: &[f64], y: f64) -> f64 {
+    ::core::panicking::panic("not implemented")
+}
+#[rustc_autodiff(ForwardFirst, Dual, Const, Const,)]
+#[inline(never)]
+pub fn df3(x: &[f64], bx: &[f64], y: f64) -> f64 {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f3(x, y));
+    ::core::hint::black_box((bx,));
+    ::core::hint::black_box(f3(x, y))
+}
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f4() {}
+#[rustc_autodiff(Forward, None)]
+#[inline(never)]
+pub fn df4() {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f4());
+    ::core::hint::black_box(());
+}
+#[rustc_autodiff]
+#[inline(never)]
+#[rustc_autodiff]
+#[inline(never)]
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f5(x: &[f64], y: f64) -> f64 {
+    ::core::panicking::panic("not implemented")
+}
+#[rustc_autodiff(Forward, Const, Dual, Const,)]
+#[inline(never)]
+pub fn df5_y(x: &[f64], y: f64, by: f64) -> f64 {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f5(x, y));
+    ::core::hint::black_box((by,));
+    ::core::hint::black_box(f5(x, y))
+}
+#[rustc_autodiff(Forward, Dual, Const, Const,)]
+#[inline(never)]
+pub fn df5_x(x: &[f64], bx: &[f64], y: f64) -> f64 {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f5(x, y));
+    ::core::hint::black_box((bx,));
+    ::core::hint::black_box(f5(x, y))
+}
+#[rustc_autodiff(Reverse, Duplicated, Const, Active,)]
+#[inline(never)]
+pub fn df5_rev(x: &[f64], dx: &mut [f64], y: f64, dret: f64) -> f64 {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f5(x, y));
+    ::core::hint::black_box((dx, dret));
+    ::core::hint::black_box(f5(x, y))
+}
+fn main() {}
diff --git a/tests/pretty/autodiff_forward.rs b/tests/pretty/autodiff_forward.rs
new file mode 100644
index 00000000000..35108d0d6f1
--- /dev/null
+++ b/tests/pretty/autodiff_forward.rs
@@ -0,0 +1,39 @@
+//@ needs-enzyme
+
+#![feature(autodiff)]
+//@ pretty-mode:expanded
+//@ pretty-compare-only
+//@ pp-exact:autodiff_forward.pp
+
+// Test that forward mode ad macros are expanded correctly.
+
+use std::autodiff::autodiff;
+
+#[autodiff(df1, Forward, Dual, Const, Dual)]
+pub fn f1(x: &[f64], y: f64) -> f64 {
+    unimplemented!()
+}
+
+#[autodiff(df2, Forward, Dual, Const, Const)]
+pub fn f2(x: &[f64], y: f64) -> f64 {
+    unimplemented!()
+}
+
+#[autodiff(df3, ForwardFirst, Dual, Const, Const)]
+pub fn f3(x: &[f64], y: f64) -> f64 {
+    unimplemented!()
+}
+
+// Not the most interesting derivative, but who are we to judge
+#[autodiff(df4, Forward)]
+pub fn f4() {}
+
+// We want to be sure that the same function can be differentiated in different ways
+#[autodiff(df5_rev, Reverse, Duplicated, Const, Active)]
+#[autodiff(df5_x, Forward, Dual, Const, Const)]
+#[autodiff(df5_y, Forward, Const, Dual, Const)]
+pub fn f5(x: &[f64], y: f64) -> f64 {
+    unimplemented!()
+}
+
+fn main() {}
diff --git a/tests/pretty/autodiff_reverse.pp b/tests/pretty/autodiff_reverse.pp
new file mode 100644
index 00000000000..a98d3782c70
--- /dev/null
+++ b/tests/pretty/autodiff_reverse.pp
@@ -0,0 +1,86 @@
+#![feature(prelude_import)]
+#![no_std]
+//@ needs-enzyme
+
+#![feature(autodiff)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+//@ pretty-mode:expanded
+//@ pretty-compare-only
+//@ pp-exact:autodiff_reverse.pp
+
+// Test that reverse mode ad macros are expanded correctly.
+
+use std::autodiff::autodiff;
+
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f1(x: &[f64], y: f64) -> f64 {
+
+    // Not the most interesting derivative, but who are we to judge
+
+
+    // What happens if we already have Reverse in type (enum variant decl) and value (enum variant
+    // constructor) namespace? > It's expected to work normally.
+
+
+    ::core::panicking::panic("not implemented")
+}
+#[rustc_autodiff(Reverse, Duplicated, Const, Active,)]
+#[inline(never)]
+pub fn df1(x: &[f64], dx: &mut [f64], y: f64, dret: f64) -> f64 {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f1(x, y));
+    ::core::hint::black_box((dx, dret));
+    ::core::hint::black_box(f1(x, y))
+}
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f2() {}
+#[rustc_autodiff(Reverse, None)]
+#[inline(never)]
+pub fn df2() {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f2());
+    ::core::hint::black_box(());
+}
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f3(x: &[f64], y: f64) -> f64 {
+    ::core::panicking::panic("not implemented")
+}
+#[rustc_autodiff(ReverseFirst, Duplicated, Const, Active,)]
+#[inline(never)]
+pub fn df3(x: &[f64], dx: &mut [f64], y: f64, dret: f64) -> f64 {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f3(x, y));
+    ::core::hint::black_box((dx, dret));
+    ::core::hint::black_box(f3(x, y))
+}
+enum Foo { Reverse, }
+use Foo::Reverse;
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f4(x: f32) { ::core::panicking::panic("not implemented") }
+#[rustc_autodiff(Reverse, Const, None)]
+#[inline(never)]
+pub fn df4(x: f32) {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f4(x));
+    ::core::hint::black_box(());
+}
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f5(x: *const f32, y: &f32) {
+    ::core::panicking::panic("not implemented")
+}
+#[rustc_autodiff(Reverse, DuplicatedOnly, Duplicated, None)]
+#[inline(never)]
+pub unsafe fn df5(x: *const f32, dx: *mut f32, y: &f32, dy: &mut f32) {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f5(x, y));
+    ::core::hint::black_box((dx, dy));
+}
+fn main() {}
diff --git a/tests/pretty/autodiff_reverse.rs b/tests/pretty/autodiff_reverse.rs
new file mode 100644
index 00000000000..657201caa94
--- /dev/null
+++ b/tests/pretty/autodiff_reverse.rs
@@ -0,0 +1,40 @@
+//@ needs-enzyme
+
+#![feature(autodiff)]
+//@ pretty-mode:expanded
+//@ pretty-compare-only
+//@ pp-exact:autodiff_reverse.pp
+
+// Test that reverse mode ad macros are expanded correctly.
+
+use std::autodiff::autodiff;
+
+#[autodiff(df1, Reverse, Duplicated, Const, Active)]
+pub fn f1(x: &[f64], y: f64) -> f64 {
+    unimplemented!()
+}
+
+// Not the most interesting derivative, but who are we to judge
+#[autodiff(df2, Reverse)]
+pub fn f2() {}
+
+#[autodiff(df3, ReverseFirst, Duplicated, Const, Active)]
+pub fn f3(x: &[f64], y: f64) -> f64 {
+    unimplemented!()
+}
+
+enum Foo { Reverse }
+use Foo::Reverse;
+// What happens if we already have Reverse in type (enum variant decl) and value (enum variant
+// constructor) namespace? > It's expected to work normally.
+#[autodiff(df4, Reverse, Const)]
+pub fn f4(x: f32) {
+    unimplemented!()
+}
+
+#[autodiff(df5, Reverse, DuplicatedOnly, Duplicated)]
+pub fn f5(x: *const f32, y: &f32) {
+    unimplemented!()
+}
+
+fn main() {}
diff --git a/tests/ui/autodiff/autodiff_illegal.rs b/tests/ui/autodiff/autodiff_illegal.rs
new file mode 100644
index 00000000000..c0548d2bbb8
--- /dev/null
+++ b/tests/ui/autodiff/autodiff_illegal.rs
@@ -0,0 +1,160 @@
+//@ needs-enzyme
+
+#![feature(autodiff)]
+//@ pretty-mode:expanded
+//@ pretty-compare-only
+//@ pp-exact:autodiff_illegal.pp
+
+// Test that invalid ad macros give nice errors and don't ICE.
+
+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
+    unimplemented!()
+}
+
+// Too many activities
+#[autodiff(df3, Reverse, Duplicated, Const)]
+pub fn f3(x: f64) {
+//~^^ 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
+    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
+    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
+    unimplemented!()
+}
+
+fn dummy() {
+
+    #[autodiff(df7, Forward, Dual)]
+    let mut x = 5;
+    //~^ ERROR autodiff must be applied to function
+
+    #[autodiff(df7, Forward, Dual)]
+    x = x + 3;
+    //~^^ ERROR attributes on expressions are experimental [E0658]
+    //~^^ ERROR autodiff must be applied to function
+
+    #[autodiff(df7, Forward, Dual)]
+    let add_one_v2 = |x: u32| -> u32 { x + 1 };
+    //~^ ERROR autodiff must be applied to function
+}
+
+// Malformed, where args?
+#[autodiff]
+pub fn f7(x: f64) {
+//~^ 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
+    unimplemented!()
+}
+
+// Invalid attribute syntax
+#[autodiff = ""]
+pub fn f9(x: f64) {
+//~^ ERROR autodiff must be applied to function
+    unimplemented!()
+}
+
+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]
+    unimplemented!()
+}
+
+// Malformed, missing a mode
+#[autodiff(df11)]
+pub fn f11() {
+//~^ 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`
+    unimplemented!()
+}
+
+// Invalid, please pick one Mode
+// or use two autodiff macros.
+#[autodiff(df13, Forward, Reverse)]
+pub fn f13() {
+//~^^ ERROR did not recognize Activity: `Reverse`
+    unimplemented!()
+}
+
+struct Foo {}
+
+// We can't handle Active structs, because that would mean (in the general case), that we would
+// need to allocate and initialize arbitrary user types. We have Duplicated/Dual input args for
+// that. FIXME: Give a nicer error and suggest to the user to have a `&mut Foo` input instead.
+#[autodiff(df14, Reverse, Active, Active)]
+fn f14(x: f32) -> Foo {
+    unimplemented!()
+}
+
+type MyFloat = f32;
+
+// We would like to support type alias to f32/f64 in argument type in the future,
+// but that requires us to implement our checks at a later stage
+// 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]
+    unimplemented!()
+}
+
+// We would like to support type alias to f32/f64 in return type in the future
+#[autodiff(df16, Reverse, Active, Active)]
+fn f16(x: f32) -> MyFloat {
+    unimplemented!()
+}
+
+#[repr(transparent)]
+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)]
+fn f17(x: f64) -> F64Trans {
+    unimplemented!()
+}
+
+// We would like to support `#[repr(transparent)]` f32/f64 wrapper in argument type in the future
+#[autodiff(df18, Reverse, Active, Active)]
+fn f18(x: F64Trans) -> f64 {
+    //~^^ ERROR failed to resolve: use of undeclared type `F64Trans` [E0433]
+    unimplemented!()
+}
+
+
+fn main() {}
diff --git a/tests/ui/autodiff/autodiff_illegal.stderr b/tests/ui/autodiff/autodiff_illegal.stderr
new file mode 100644
index 00000000000..3a7242b2f5d
--- /dev/null
+++ b/tests/ui/autodiff/autodiff_illegal.stderr
@@ -0,0 +1,152 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/autodiff_illegal.rs:54:5
+   |
+LL |     #[autodiff(df7, Forward, Dual)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: Duplicated can not be used for this type
+  --> $DIR/autodiff_illegal.rs:14:14
+   |
+LL | pub fn f1(x: f64) {
+   |              ^^^
+
+error: expected 1 activities, but found 2
+  --> $DIR/autodiff_illegal.rs:20:1
+   |
+LL | #[autodiff(df3, Reverse, Duplicated, Const)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected 1 activities, but found 0
+  --> $DIR/autodiff_illegal.rs:27:1
+   |
+LL | #[autodiff(df4, Reverse)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: Dual can not be used in Reverse Mode
+  --> $DIR/autodiff_illegal.rs:34:1
+   |
+LL | #[autodiff(df5, Reverse, Dual)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: Duplicated can not be used in Forward Mode
+  --> $DIR/autodiff_illegal.rs:41:1
+   |
+LL | #[autodiff(df6, Forward, Duplicated)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the attribute macro `autodiff` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: Duplicated can not be used for this type
+  --> $DIR/autodiff_illegal.rs:42:14
+   |
+LL | pub fn f6(x: f64) {
+   |              ^^^
+
+error: autodiff must be applied to function
+  --> $DIR/autodiff_illegal.rs:51:5
+   |
+LL |     let mut x = 5;
+   |     ^^^^^^^^^^^^^^
+
+error: autodiff must be applied to function
+  --> $DIR/autodiff_illegal.rs:55:5
+   |
+LL |     x = x + 3;
+   |     ^
+
+error: autodiff must be applied to function
+  --> $DIR/autodiff_illegal.rs:60:5
+   |
+LL |     let add_one_v2 = |x: u32| -> u32 { x + 1 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: autodiff must be applied to function
+  --> $DIR/autodiff_illegal.rs:66:1
+   |
+LL | / pub fn f7(x: f64) {
+LL | |
+LL | |     unimplemented!()
+LL | | }
+   | |_^
+
+error: autodiff requires at least a name and mode
+  --> $DIR/autodiff_illegal.rs:73:1
+   |
+LL | / pub fn f8(x: f64) {
+LL | |
+LL | |     unimplemented!()
+LL | | }
+   | |_^
+
+error: autodiff must be applied to function
+  --> $DIR/autodiff_illegal.rs:80:1
+   |
+LL | / pub fn f9(x: f64) {
+LL | |
+LL | |     unimplemented!()
+LL | | }
+   | |_^
+
+error[E0428]: the name `fn_exists` is defined multiple times
+  --> $DIR/autodiff_illegal.rs:88:1
+   |
+LL | fn fn_exists() {}
+   | -------------- previous definition of the value `fn_exists` here
+...
+LL | #[autodiff(fn_exists, Reverse, Active)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn_exists` redefined here
+   |
+   = note: `fn_exists` must be defined only once in the value namespace of this module
+   = 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
+   |
+LL | / pub fn f11() {
+LL | |
+LL | |     unimplemented!()
+LL | | }
+   | |_^
+
+error: unknown Mode: `Debug`. Use `Forward` or `Reverse`
+  --> $DIR/autodiff_illegal.rs:102:18
+   |
+LL | #[autodiff(df12, Debug)]
+   |                  ^^^^^
+
+error: did not recognize Activity: `Reverse`
+  --> $DIR/autodiff_illegal.rs:110:27
+   |
+LL | #[autodiff(df13, Forward, Reverse)]
+   |                           ^^^^^^^
+
+error[E0433]: failed to resolve: use of undeclared type `MyFloat`
+  --> $DIR/autodiff_illegal.rs:131:1
+   |
+LL | #[autodiff(df15, Reverse, Active, Active)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat`
+   |
+   = 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
+   |
+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
+
+Some errors have detailed explanations: E0428, E0433, E0658.
+For more information about an error, try `rustc --explain E0428`.
diff --git a/tests/ui/autodiff/auxiliary/my_macro.rs b/tests/ui/autodiff/auxiliary/my_macro.rs
new file mode 100644
index 00000000000..417199611cc
--- /dev/null
+++ b/tests/ui/autodiff/auxiliary/my_macro.rs
@@ -0,0 +1,12 @@
+//@ force-host
+//@ no-prefer-dynamic
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+#[macro_use]
+pub fn autodiff(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    item // identity proc-macro
+}
diff --git a/tests/ui/autodiff/visibility.rs b/tests/ui/autodiff/visibility.rs
new file mode 100644
index 00000000000..6a4851de2dc
--- /dev/null
+++ b/tests/ui/autodiff/visibility.rs
@@ -0,0 +1,17 @@
+//@ ignore-enzyme
+//@ revisions: std_autodiff no_std_autodiff
+//@[no_std_autodiff] check-pass
+//@ aux-build: my_macro.rs
+#![crate_type = "lib"]
+#![feature(autodiff)]
+
+#[cfg(std_autodiff)]
+use std::autodiff::autodiff;
+
+extern crate my_macro;
+use my_macro::autodiff; // bring `autodiff` in scope
+
+#[autodiff]
+//[std_autodiff]~^^^ ERROR the name `autodiff` is defined multiple times
+//[std_autodiff]~^^ ERROR this rustc version does not support autodiff
+fn foo() {}
diff --git a/tests/ui/autodiff/visibility.std_autodiff.stderr b/tests/ui/autodiff/visibility.std_autodiff.stderr
new file mode 100644
index 00000000000..720c9a00170
--- /dev/null
+++ b/tests/ui/autodiff/visibility.std_autodiff.stderr
@@ -0,0 +1,24 @@
+error[E0252]: the name `autodiff` is defined multiple times
+  --> $DIR/visibility.rs:12:5
+   |
+LL | use std::autodiff::autodiff;
+   |     ----------------------- previous import of the macro `autodiff` here
+...
+LL | use my_macro::autodiff; // bring `autodiff` in scope
+   |     ^^^^^^^^^^^^^^^^^^ `autodiff` reimported here
+   |
+   = note: `autodiff` must be defined only once in the macro namespace of this module
+help: you can use `as` to change the binding name of the import
+   |
+LL | use my_macro::autodiff as other_autodiff; // bring `autodiff` in scope
+   |                        +++++++++++++++++
+
+error: this rustc version does not support autodiff
+  --> $DIR/visibility.rs:14:1
+   |
+LL | #[autodiff]
+   | ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0252`.
diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr
new file mode 100644
index 00000000000..36a017dd53c
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr
@@ -0,0 +1,23 @@
+error[E0658]: use of unstable library feature 'autodiff'
+  --> $DIR/feature-gate-autodiff-use.rs:13:3
+   |
+LL | #[autodiff(dfoo, Reverse)]
+   |   ^^^^^^^^
+   |
+   = note: see issue #124509 <https://github.com/rust-lang/rust/issues/124509> for more information
+   = help: add `#![feature(autodiff)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'autodiff'
+  --> $DIR/feature-gate-autodiff-use.rs:9:5
+   |
+LL | use std::autodiff::autodiff;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #124509 <https://github.com/rust-lang/rust/issues/124509> for more information
+   = help: add `#![feature(autodiff)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr
new file mode 100644
index 00000000000..4b767f824c8
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr
@@ -0,0 +1,29 @@
+error[E0658]: use of unstable library feature 'autodiff'
+  --> $DIR/feature-gate-autodiff-use.rs:13:3
+   |
+LL | #[autodiff(dfoo, Reverse)]
+   |   ^^^^^^^^
+   |
+   = note: see issue #124509 <https://github.com/rust-lang/rust/issues/124509> for more information
+   = help: add `#![feature(autodiff)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: this rustc version does not support autodiff
+  --> $DIR/feature-gate-autodiff-use.rs:13:1
+   |
+LL | #[autodiff(dfoo, Reverse)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: use of unstable library feature 'autodiff'
+  --> $DIR/feature-gate-autodiff-use.rs:9:5
+   |
+LL | use std::autodiff::autodiff;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #124509 <https://github.com/rust-lang/rust/issues/124509> for more information
+   = help: add `#![feature(autodiff)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.rs b/tests/ui/feature-gates/feature-gate-autodiff-use.rs
new file mode 100644
index 00000000000..2276a79d6e2
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-autodiff-use.rs
@@ -0,0 +1,17 @@
+//@ revisions: has_support no_support
+//@[no_support] ignore-enzyme
+//@[has_support] needs-enzyme
+
+// This checks that without enabling the autodiff feature, we can't import std::autodiff::autodiff;
+
+#![crate_type = "lib"]
+
+use std::autodiff::autodiff;
+//[has_support]~^ ERROR use of unstable library feature 'autodiff'
+//[no_support]~^^ ERROR use of unstable library feature 'autodiff'
+
+#[autodiff(dfoo, Reverse)]
+//[has_support]~^ ERROR use of unstable library feature 'autodiff' [E0658]
+//[no_support]~^^ ERROR use of unstable library feature 'autodiff' [E0658]
+//[no_support]~| ERROR this rustc version does not support autodiff
+fn foo() {}
diff --git a/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr
new file mode 100644
index 00000000000..c25cf7d3373
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr
@@ -0,0 +1,13 @@
+error: cannot find attribute `autodiff` in this scope
+  --> $DIR/feature-gate-autodiff.rs:9:3
+   |
+LL | #[autodiff(dfoo, Reverse)]
+   |   ^^^^^^^^
+   |
+help: consider importing this attribute macro
+   |
+LL + use std::autodiff::autodiff;
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr
new file mode 100644
index 00000000000..c25cf7d3373
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr
@@ -0,0 +1,13 @@
+error: cannot find attribute `autodiff` in this scope
+  --> $DIR/feature-gate-autodiff.rs:9:3
+   |
+LL | #[autodiff(dfoo, Reverse)]
+   |   ^^^^^^^^
+   |
+help: consider importing this attribute macro
+   |
+LL + use std::autodiff::autodiff;
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/feature-gates/feature-gate-autodiff.rs b/tests/ui/feature-gates/feature-gate-autodiff.rs
new file mode 100644
index 00000000000..4249b229a69
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-autodiff.rs
@@ -0,0 +1,12 @@
+//@ revisions: has_support no_support
+//@[no_support] ignore-enzyme
+//@[has_support] needs-enzyme
+
+#![crate_type = "lib"]
+
+// This checks that without the autodiff feature enabled, we can't use it.
+
+#[autodiff(dfoo, Reverse)]
+//[has_support]~^ ERROR cannot find attribute `autodiff` in this scope
+//[no_support]~^^ ERROR cannot find attribute `autodiff` in this scope
+fn foo() {}