Skip to content

Commit ad2aaa8

Browse files
committed
Auto merge of rust-lang#140350 - jhpratt:rollup-fudxv6m, r=jhpratt
Rollup of 4 pull requests Successful merges: - rust-lang#139308 (add autodiff inline) - rust-lang#140291 (Correctly display stdout and stderr in case a doctest is failing) - rust-lang#140297 (Update example to use CStr::to_string_lossy) - rust-lang#140339 (session: Cleanup `CanonicalizedPath::new`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 10fa3c4 + 60316bf commit ad2aaa8

File tree

17 files changed

+244
-13
lines changed

17 files changed

+244
-13
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+16
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
2828
}
2929
}
3030

31+
pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: AttributeKind) -> bool {
32+
llvm::HasAttributeAtIndex(llfn, idx, attr)
33+
}
34+
35+
pub(crate) fn has_string_attr(llfn: &Value, name: *const i8) -> bool {
36+
llvm::HasStringAttribute(llfn, name)
37+
}
38+
39+
pub(crate) fn remove_from_llfn(llfn: &Value, place: AttributePlace, kind: AttributeKind) {
40+
llvm::RemoveRustEnumAttributeAtIndex(llfn, place, kind);
41+
}
42+
43+
pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: *const i8) {
44+
llvm::RemoveStringAttrFromFn(llfn, name);
45+
}
46+
3147
/// Get LLVM attribute for the provided inline heuristic.
3248
#[inline]
3349
fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {

compiler/rustc_codegen_llvm/src/back/lto.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ use crate::back::write::{
2828
use crate::errors::{
2929
DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
3030
};
31+
use crate::llvm::AttributePlace::Function;
3132
use crate::llvm::{self, build_string};
32-
use crate::{LlvmCodegenBackend, ModuleLlvm};
33+
use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx, attributes};
3334

3435
/// We keep track of the computed LTO cache keys from the previous
3536
/// session to determine which CGUs we can reuse.
@@ -666,6 +667,33 @@ pub(crate) fn run_pass_manager(
666667
}
667668

668669
if cfg!(llvm_enzyme) && enable_ad && !thin {
670+
let cx =
671+
SimpleCx::new(module.module_llvm.llmod(), &module.module_llvm.llcx, cgcx.pointer_size);
672+
673+
for function in cx.get_functions() {
674+
let enzyme_marker = CString::new("enzyme_marker").unwrap();
675+
let marker_ptr = enzyme_marker.as_ptr();
676+
677+
if attributes::has_string_attr(function, marker_ptr) {
678+
// Sanity check: Ensure 'noinline' is present before replacing it.
679+
assert!(
680+
!attributes::has_attr(function, Function, llvm::AttributeKind::NoInline),
681+
"Expected __enzyme function to have 'noinline' before adding 'alwaysinline'"
682+
);
683+
684+
attributes::remove_from_llfn(function, Function, llvm::AttributeKind::NoInline);
685+
attributes::remove_string_attr_from_llfn(function, marker_ptr);
686+
687+
assert!(
688+
!attributes::has_string_attr(function, marker_ptr),
689+
"Expected function to not have 'enzyme_marker'"
690+
);
691+
692+
let always_inline = llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx);
693+
attributes::apply_to_llfn(function, Function, &[always_inline]);
694+
}
695+
}
696+
669697
let opt_stage = llvm::OptStage::FatLTO;
670698
let stage = write::AutodiffStage::PostAD;
671699
if !config.autodiff.contains(&config::AutoDiff::NoPostopt) {

compiler/rustc_codegen_llvm/src/builder/autodiff.rs

+5
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,11 @@ fn generate_enzyme_call<'ll>(
361361
let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx);
362362
attributes::apply_to_llfn(ad_fn, Function, &[attr]);
363363

364+
// We add a made-up attribute just such that we can recognize it after AD to update
365+
// (no)-inline attributes. We'll then also remove this attribute.
366+
let enzyme_marker_attr = llvm::CreateAttrString(cx.llcx, "enzyme_marker");
367+
attributes::apply_to_llfn(outer_fn, Function, &[enzyme_marker_attr]);
368+
364369
// first, remove all calls from fnc
365370
let entry = llvm::LLVMGetFirstBasicBlock(outer_fn);
366371
let br = llvm::LLVMRustGetTerminator(entry);

compiler/rustc_codegen_llvm/src/context.rs

+10
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,16 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
698698
llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
699699
})
700700
}
701+
702+
pub(crate) fn get_functions(&self) -> Vec<&'ll Value> {
703+
let mut functions = vec![];
704+
let mut func = unsafe { llvm::LLVMGetFirstFunction(self.llmod()) };
705+
while let Some(f) = func {
706+
functions.push(f);
707+
func = unsafe { llvm::LLVMGetNextFunction(f) }
708+
}
709+
functions
710+
}
701711
}
702712

703713
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {

compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs

+9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ unsafe extern "C" {
1919
pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
2020
pub(crate) fn LLVMRustHasAttributeAtIndex(V: &Value, i: c_uint, Kind: AttributeKind) -> bool;
2121
pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64;
22+
pub(crate) fn LLVMRustHasFnAttribute(F: &Value, Name: *const c_char) -> bool;
23+
pub(crate) fn LLVMRustRemoveFnAttribute(F: &Value, Name: *const c_char);
24+
pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;
25+
pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>;
26+
pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex(
27+
Fn: &Value,
28+
index: c_uint,
29+
kind: AttributeKind,
30+
);
2231
}
2332

2433
unsafe extern "C" {

compiler/rustc_codegen_llvm/src/llvm/mod.rs

+26
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,32 @@ pub(crate) fn AddFunctionAttributes<'ll>(
4141
}
4242
}
4343

44+
pub(crate) fn HasAttributeAtIndex<'ll>(
45+
llfn: &'ll Value,
46+
idx: AttributePlace,
47+
kind: AttributeKind,
48+
) -> bool {
49+
unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), kind) }
50+
}
51+
52+
pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: *const i8) -> bool {
53+
unsafe { LLVMRustHasFnAttribute(llfn, name) }
54+
}
55+
56+
pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: *const i8) {
57+
unsafe { LLVMRustRemoveFnAttribute(llfn, name) }
58+
}
59+
60+
pub(crate) fn RemoveRustEnumAttributeAtIndex(
61+
llfn: &Value,
62+
place: AttributePlace,
63+
kind: AttributeKind,
64+
) {
65+
unsafe {
66+
LLVMRustRemoveEnumAttributeAtIndex(llfn, place.as_uint(), kind);
67+
}
68+
}
69+
4470
pub(crate) fn AddCallSiteAttributes<'ll>(
4571
callsite: &'ll Value,
4672
idx: AttributePlace,

compiler/rustc_codegen_llvm/src/type_.rs

+4
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
128128
(**self).borrow().llcx
129129
}
130130

131+
pub(crate) fn llmod(&self) -> &'ll llvm::Module {
132+
(**self).borrow().llmod
133+
}
134+
131135
pub(crate) fn isize_ty(&self) -> &'ll Type {
132136
(**self).borrow().isize_ty
133137
}

compiler/rustc_interface/src/tests.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![allow(rustc::bad_opt_access)]
2-
use std::collections::{BTreeMap, BTreeSet};
2+
use std::collections::BTreeMap;
33
use std::num::NonZero;
4-
use std::path::{Path, PathBuf};
4+
use std::path::PathBuf;
55
use std::sync::atomic::AtomicBool;
66

77
use rustc_abi::Align;
@@ -89,8 +89,8 @@ where
8989
S: Into<String>,
9090
I: IntoIterator<Item = S>,
9191
{
92-
let locations: BTreeSet<CanonicalizedPath> =
93-
locations.into_iter().map(|s| CanonicalizedPath::new(Path::new(&s.into()))).collect();
92+
let locations =
93+
locations.into_iter().map(|s| CanonicalizedPath::new(PathBuf::from(s.into()))).collect();
9494

9595
ExternEntry {
9696
location: ExternLocation::ExactPaths(locations),

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,25 @@ extern "C" LLVMMetadataRef LLVMRustDIGetInstMetadata(LLVMValueRef x) {
973973
return nullptr;
974974
}
975975

976+
extern "C" void
977+
LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
978+
LLVMRustAttributeKind RustAttr) {
979+
LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
980+
}
981+
982+
extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name) {
983+
if (auto *Fn = dyn_cast<Function>(unwrap<Value>(F))) {
984+
return Fn->hasFnAttribute(Name);
985+
}
986+
return false;
987+
}
988+
989+
extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name) {
990+
if (auto *F = dyn_cast<Function>(unwrap<Value>(Fn))) {
991+
F->removeFnAttr(Name);
992+
}
993+
}
994+
976995
extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
977996
LLVMMetadataRef MD) {
978997
unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));

compiler/rustc_session/src/config.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2323,14 +2323,13 @@ pub fn parse_externs(
23232323
let ExternOpt { crate_name: name, path, options } =
23242324
split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
23252325

2326-
let path = path.map(|p| CanonicalizedPath::new(p.as_path()));
2327-
23282326
let entry = externs.entry(name.to_owned());
23292327

23302328
use std::collections::btree_map::Entry;
23312329

23322330
let entry = if let Some(path) = path {
23332331
// --extern prelude_name=some_file.rlib
2332+
let path = CanonicalizedPath::new(path);
23342333
match entry {
23352334
Entry::Vacant(vacant) => {
23362335
let files = BTreeSet::from_iter(iter::once(path));

compiler/rustc_session/src/utils.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::path::{Path, PathBuf};
1+
use std::path::PathBuf;
22
use std::sync::OnceLock;
33

44
use rustc_data_structures::profiling::VerboseTimingGuard;
@@ -104,8 +104,8 @@ pub struct CanonicalizedPath {
104104
}
105105

106106
impl CanonicalizedPath {
107-
pub fn new(path: &Path) -> Self {
108-
Self { original: path.to_owned(), canonicalized: try_canonicalize(path).ok() }
107+
pub fn new(path: PathBuf) -> Self {
108+
Self { canonicalized: try_canonicalize(&path).ok(), original: path }
109109
}
110110

111111
pub fn canonicalized(&self) -> &PathBuf {

library/core/src/ffi/c_str.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ use crate::{fmt, ops, slice, str};
7979
///
8080
/// fn my_string_safe() -> String {
8181
/// let cstr = unsafe { CStr::from_ptr(my_string()) };
82-
/// // Get copy-on-write Cow<'_, str>, then guarantee a freshly-owned String allocation
83-
/// String::from_utf8_lossy(cstr.to_bytes()).to_string()
82+
/// // Get a copy-on-write Cow<'_, str>, then extract the
83+
/// // allocated String (or allocate a fresh one if needed).
84+
/// cstr.to_string_lossy().into_owned()
8485
/// }
8586
///
8687
/// println!("string: {}", my_string_safe());

src/librustdoc/doctest/runner.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,22 @@ mod __doctest_mod {{
131131
.output()
132132
.expect(\"failed to run command\");
133133
if !out.status.success() {{
134-
eprint!(\"{{}}\", String::from_utf8_lossy(&out.stderr));
134+
if let Some(code) = out.status.code() {{
135+
eprintln!(\"Test executable failed (exit status: {{code}}).\");
136+
}} else {{
137+
eprintln!(\"Test executable failed (terminated by signal).\");
138+
}}
139+
if !out.stdout.is_empty() || !out.stderr.is_empty() {{
140+
eprintln!();
141+
}}
142+
if !out.stdout.is_empty() {{
143+
eprintln!(\"stdout:\");
144+
eprintln!(\"{{}}\", String::from_utf8_lossy(&out.stdout));
145+
}}
146+
if !out.stderr.is_empty() {{
147+
eprintln!(\"stderr:\");
148+
eprintln!(\"{{}}\", String::from_utf8_lossy(&out.stderr));
149+
}}
135150
ExitCode::FAILURE
136151
}} else {{
137152
ExitCode::SUCCESS

tests/codegen/autodiff/inline.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -Zautodiff=NoPostopt
2+
//@ no-prefer-dynamic
3+
//@ needs-enzyme
4+
5+
#![feature(autodiff)]
6+
7+
use std::autodiff::autodiff;
8+
9+
#[autodiff(d_square, Reverse, Duplicated, Active)]
10+
fn square(x: &f64) -> f64 {
11+
x * x
12+
}
13+
14+
// CHECK: ; inline::d_square
15+
// CHECK-NEXT: ; Function Attrs: alwaysinline
16+
// CHECK-NOT: noinline
17+
// CHECK-NEXT: define internal fastcc void @_ZN6inline8d_square17h021c74e92c259cdeE
18+
fn main() {
19+
let x = std::hint::black_box(3.0);
20+
let mut dx1 = std::hint::black_box(1.0);
21+
let _ = d_square(&x, &mut dx1, 1.0);
22+
assert_eq!(dx1, 6.0);
23+
}

tests/rustdoc-ui/doctest/edition-2024-error-output.stdout

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ test $DIR/edition-2024-error-output.rs - (line 12) ... FAILED
55
failures:
66

77
---- $DIR/edition-2024-error-output.rs - (line 12) stdout ----
8+
Test executable failed (exit status: 101).
9+
10+
stderr:
811

912
thread 'main' panicked at $TMP:6:1:
1013
assertion `left == right` failed
@@ -13,6 +16,7 @@ assertion `left == right` failed
1316
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
1417

1518

19+
1620
failures:
1721
$DIR/edition-2024-error-output.rs - (line 12)
1822

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// This test ensures that the output is correctly generated when the
2+
// doctest fails. It checks when there is stderr and stdout, no stdout
3+
// and no stderr/stdout.
4+
//
5+
// This is a regression test for <https://github.com/rust-lang/rust/issues/140289>.
6+
7+
//@ edition: 2024
8+
//@ compile-flags:--test --test-args=--test-threads=1
9+
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
10+
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
11+
//@ normalize-stdout: "panicked at .+rs:" -> "panicked at $$TMP:"
12+
//@ failure-status: 101
13+
//@ rustc-env:RUST_BACKTRACE=0
14+
15+
//! ```
16+
//! println!("######## from a DOC TEST ########");
17+
//! assert_eq!("doc", "test");
18+
//! ```
19+
//!
20+
//! ```
21+
//! assert_eq!("doc", "test");
22+
//! ```
23+
//!
24+
//! ```
25+
//! std::process::exit(1);
26+
//! ```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
running 3 tests
3+
test $DIR/stdout-and-stderr.rs - (line 15) ... FAILED
4+
test $DIR/stdout-and-stderr.rs - (line 20) ... FAILED
5+
test $DIR/stdout-and-stderr.rs - (line 24) ... FAILED
6+
7+
failures:
8+
9+
---- $DIR/stdout-and-stderr.rs - (line 15) stdout ----
10+
Test executable failed (exit status: 101).
11+
12+
stdout:
13+
######## from a DOC TEST ########
14+
15+
stderr:
16+
17+
thread 'main' panicked at $TMP:7:1:
18+
assertion `left == right` failed
19+
left: "doc"
20+
right: "test"
21+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
22+
23+
24+
---- $DIR/stdout-and-stderr.rs - (line 20) stdout ----
25+
Test executable failed (exit status: 101).
26+
27+
stderr:
28+
29+
thread 'main' panicked at $TMP:15:1:
30+
assertion `left == right` failed
31+
left: "doc"
32+
right: "test"
33+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
34+
35+
36+
---- $DIR/stdout-and-stderr.rs - (line 24) stdout ----
37+
Test executable failed (exit status: 1).
38+
39+
40+
failures:
41+
$DIR/stdout-and-stderr.rs - (line 15)
42+
$DIR/stdout-and-stderr.rs - (line 20)
43+
$DIR/stdout-and-stderr.rs - (line 24)
44+
45+
test result: FAILED. 0 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
46+

0 commit comments

Comments
 (0)