1
Fork 0

Auto merge of #137914 - matthiaskrgr:rollup-phaxe6f, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #137103 ({json|html}docck: catch and error on deprecated syntax)
 - #137632 (rustdoc: when merging target features, keep the highest stability)
 - #137684 (Add rustdoc support for `--emit=dep-info[=path]`)
 - #137794 (make qnx pass a test)
 - #137801 (tests: Unignore target modifier tests on all platforms)
 - #137826 (test(codegen): add looping_over_ne_bytes test for #133528)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-03-03 19:34:25 +00:00
commit e16a049adb
26 changed files with 267 additions and 152 deletions

View file

@ -10,7 +10,7 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
use rustc_target::target_features;
use rustc_target::target_features::{self, Stability};
use crate::errors;
@ -87,6 +87,10 @@ pub(crate) fn from_target_feature_attr(
// But ensure the ABI does not forbid enabling this.
// Here we do assume that LLVM doesn't add even more implied features
// we don't know about, at least no features that would have ABI effects!
// We skip this logic in rustdoc, where we want to allow all target features of
// all targets, so we can't check their ABI compatibility and anyway we are not
// generating code so "it's fine".
if !tcx.sess.opts.actually_rustdoc {
if abi_feature_constraints.incompatible.contains(&name.as_str()) {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
@ -94,6 +98,7 @@ pub(crate) fn from_target_feature_attr(
reason: "this feature is incompatible with the target ABI",
});
}
}
target_features.push(TargetFeature { name, implied: name != feature_sym })
}
}
@ -142,11 +147,38 @@ pub(crate) fn provide(providers: &mut Providers) {
rust_target_features: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
if tcx.sess.opts.actually_rustdoc {
// rustdoc needs to be able to document functions that use all the features, so
// whitelist them all
rustc_target::target_features::all_rust_features()
.map(|(a, b)| (a.to_string(), b))
.collect()
// HACK: rustdoc would like to pretend that we have all the target features, so we
// have to merge all the lists into one. To ensure an unstable target never prevents
// a stable one from working, we merge the stability info of all instances of the
// same target feature name, with the "most stable" taking precedence. And then we
// hope that this doesn't cause issues anywhere else in the compiler...
let mut result: UnordMap<String, Stability> = Default::default();
for (name, stability) in rustc_target::target_features::all_rust_features() {
use std::collections::hash_map::Entry;
match result.entry(name.to_owned()) {
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(stability);
}
Entry::Occupied(mut occupied_entry) => {
// Merge the two stabilities, "more stable" taking precedence.
match (occupied_entry.get(), stability) {
(Stability::Stable, _)
| (
Stability::Unstable { .. },
Stability::Unstable { .. } | Stability::Forbidden { .. },
)
| (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => {
// The stability in the entry is at least as good as the new one, just keep it.
}
_ => {
// Overwrite stabilite.
occupied_entry.insert(stability);
}
}
}
}
}
result
} else {
tcx.sess
.target

View file

@ -297,10 +297,24 @@ LINE_PATTERN = re.compile(
re.X | re.UNICODE,
)
DEPRECATED_LINE_PATTERN = re.compile(
r"""
//\s+@
""",
re.X | re.UNICODE,
)
def get_commands(template):
with io.open(template, encoding="utf-8") as f:
for lineno, line in concat_multi_lines(f):
if DEPRECATED_LINE_PATTERN.search(line):
print_err(
lineno,
line,
"Deprecated command syntax, replace `// @` with `//@ `",
)
continue
m = LINE_PATTERN.search(line)
if not m:
continue

View file

@ -315,23 +315,30 @@ pub(crate) enum ModuleSorting {
Alphabetical,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum EmitType {
Unversioned,
Toolchain,
InvocationSpecific,
DepInfo(Option<PathBuf>),
}
impl FromStr for EmitType {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
use EmitType::*;
match s {
"unversioned-shared-resources" => Ok(Unversioned),
"toolchain-shared-resources" => Ok(Toolchain),
"invocation-specific" => Ok(InvocationSpecific),
_ => Err(()),
"unversioned-shared-resources" => Ok(Self::Unversioned),
"toolchain-shared-resources" => Ok(Self::Toolchain),
"invocation-specific" => Ok(Self::InvocationSpecific),
"dep-info" => Ok(Self::DepInfo(None)),
option => {
if let Some(file) = option.strip_prefix("dep-info=") {
Ok(Self::DepInfo(Some(Path::new(file).into())))
} else {
Err(())
}
}
}
}
}
@ -340,6 +347,15 @@ impl RenderOptions {
pub(crate) fn should_emit_crate(&self) -> bool {
self.emit.is_empty() || self.emit.contains(&EmitType::InvocationSpecific)
}
pub(crate) fn dep_info(&self) -> Option<Option<&Path>> {
for emit in &self.emit {
if let EmitType::DepInfo(file) = emit {
return Some(file.as_deref());
}
}
None
}
}
/// Create the input (string or file path)

View file

@ -15,11 +15,12 @@ use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{HirId, Path};
use rustc_interface::interface;
use rustc_lint::{MissingDoc, late_lint_mod};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
use rustc_session::config::{self, CrateType, ErrorOutputType, Input, ResolveDocLinks};
use rustc_session::config::{
self, CrateType, ErrorOutputType, Input, OutFileName, OutputType, OutputTypes, ResolveDocLinks,
};
pub(crate) use rustc_session::config::{Options, UnstableOptions};
use rustc_session::{Session, lint};
use rustc_span::source_map;
@ -219,7 +220,7 @@ pub(crate) fn create_config(
remap_path_prefix,
..
}: RustdocOptions,
RenderOptions { document_private, .. }: &RenderOptions,
render_options: &RenderOptions,
) -> rustc_interface::Config {
// Add the doc cfg into the doc build.
cfgs.push("doc".to_string());
@ -245,8 +246,11 @@ pub(crate) fn create_config(
let crate_types =
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
let resolve_doc_links =
if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported };
let resolve_doc_links = if render_options.document_private {
ResolveDocLinks::All
} else {
ResolveDocLinks::Exported
};
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
// plays with error output here!
let sessopts = config::Options {
@ -269,10 +273,18 @@ pub(crate) fn create_config(
crate_name,
test,
remap_path_prefix,
output_types: if let Some(file) = render_options.dep_info() {
OutputTypes::new(&[(
OutputType::DepInfo,
file.map(|f| OutFileName::Real(f.to_path_buf())),
)])
} else {
OutputTypes::new(&[])
},
..Options::default()
};
interface::Config {
rustc_interface::Config {
opts: sessopts,
crate_cfg: cfgs,
crate_check_cfg: check_cfgs,

View file

@ -153,7 +153,7 @@ fn write_rendered_cross_crate_info(
include_sources: bool,
) -> Result<(), Error> {
let m = &opt.should_merge;
if opt.emit.is_empty() || opt.emit.contains(&EmitType::InvocationSpecific) {
if opt.should_emit_crate() {
if include_sources {
write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, crates, m)?;
}

View file

@ -561,7 +561,7 @@ fn opts() -> Vec<RustcOptGroup> {
"",
"emit",
"Comma separated list of types of output for rustdoc to emit",
"[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
"[unversioned-shared-resources,toolchain-shared-resources,invocation-specific,dep-info]",
),
opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
opt(
@ -890,7 +890,13 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
// if we ran coverage, bail early, we don't need to also generate docs at this point
// (also we didn't load in any of the useful passes)
return;
} else if run_check {
}
if render_opts.dep_info().is_some() {
rustc_interface::passes::write_dep_info(tcx);
}
if run_check {
// Since we're in "check" mode, no need to generate anything beyond this point.
return;
}

View file

@ -1,6 +1,6 @@
use std::borrow::Cow;
use std::process::ExitCode;
use std::sync::OnceLock;
use std::sync::LazyLock;
use std::{env, fs};
use regex::{Regex, RegexBuilder};
@ -151,8 +151,7 @@ impl CommandKind {
}
}
static LINE_PATTERN: OnceLock<Regex> = OnceLock::new();
fn line_pattern() -> Regex {
static LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
RegexBuilder::new(
r#"
//@\s+
@ -165,7 +164,19 @@ fn line_pattern() -> Regex {
.unicode(true)
.build()
.unwrap()
}
});
static DEPRECATED_LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
RegexBuilder::new(
r#"
//\s+@
"#,
)
.ignore_whitespace(true)
.unicode(true)
.build()
.unwrap()
});
fn print_err(msg: &str, lineno: usize) {
eprintln!("Invalid command: {} on line {}", msg, lineno)
@ -184,21 +195,23 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
for (lineno, line) in file.split('\n').enumerate() {
let lineno = lineno + 1;
let cap = match LINE_PATTERN.get_or_init(line_pattern).captures(line) {
Some(c) => c,
None => continue,
};
let negated = cap.name("negated").unwrap().as_str() == "!";
let args_str = &cap["args"];
let args = match shlex::split(args_str) {
Some(args) => args,
None => {
print_err(&format!("Invalid arguments to shlex::split: `{args_str}`",), lineno);
if DEPRECATED_LINE_PATTERN.is_match(line) {
print_err("Deprecated command syntax, replace `// @` with `//@ `", lineno);
errors = true;
continue;
}
let Some(cap) = LINE_PATTERN.captures(line) else {
continue;
};
let negated = &cap["negated"] == "!";
let args_str = &cap["args"];
let Some(args) = shlex::split(args_str) else {
print_err(&format!("Invalid arguments to shlex::split: `{args_str}`",), lineno);
errors = true;
continue;
};
if let Some((kind, path)) = CommandKind::parse(&cap["cmd"], negated, &args) {

View file

@ -132,4 +132,11 @@ impl Rustdoc {
self.cmd.arg(format);
self
}
/// Specify type(s) of output files to generate.
pub fn emit<S: AsRef<str>>(&mut self, kinds: S) -> &mut Self {
let kinds = kinds.as_ref();
self.cmd.arg(format!("--emit={kinds}"));
self
}
}

View file

@ -0,0 +1,17 @@
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 20
#![crate_type = "lib"]
/// Ensure the function is properly optimized
/// In the issue #133528, the function was not getting optimized
/// whereas, a version with `bytes` wrapped into a `black_box` was optimized
/// It was probably a LLVM bug that was fixed in LLVM 20
// CHECK-LABEL: @looping_over_ne_bytes
// CHECK: icmp eq i64 %input, -1
// CHECK-NEXT: ret i1
#[no_mangle]
fn looping_over_ne_bytes(input: u64) -> bool {
let bytes = input.to_ne_bytes();
bytes.iter().all(|x| *x == !0)
}

View file

@ -153,7 +153,7 @@ Options:
--generate-redirect-map
Generate JSON file at the top level instead of
generating HTML redirection files
--emit [unversioned-shared-resources,toolchain-shared-resources,invocation-specific]
--emit [unversioned-shared-resources,toolchain-shared-resources,invocation-specific,dep-info]
Comma separated list of types of output for rustdoc to
emit
--no-run Compile doctests without running them

View file

@ -0,0 +1 @@
include!("foo.rs");

View file

@ -0,0 +1 @@
blablabla

View file

@ -0,0 +1 @@
pub fn foo() {}

View file

@ -0,0 +1,6 @@
#![crate_name = "foo"]
#[cfg_attr(doc, doc = include_str!("doc.md"))]
pub struct Bar;
mod bar;

View file

@ -0,0 +1,21 @@
// This is a simple smoke test for rustdoc's `--emit dep-info` feature. It prints out
// information about dependencies in a Makefile-compatible format, as a `.d` file.
use run_make_support::assertion_helpers::assert_contains;
use run_make_support::{path, rfs, rustdoc};
fn main() {
// We're only emitting dep info, so we shouldn't be running static analysis to
// figure out that this program is erroneous.
rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info").run();
let content = rfs::read_to_string("foo.d");
assert_contains(&content, "lib.rs:");
assert_contains(&content, "foo.rs:");
assert_contains(&content, "bar.rs:");
assert_contains(&content, "doc.md:");
// Now we check that we can provide a file name to the `dep-info` argument.
rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info=bla.d").run();
assert!(path("bla.d").exists());
}

View file

@ -0,0 +1,28 @@
//! This is a regression test for <https://github.com/rust-lang/rust/issues/137366>, ensuring
//! that we can use the `neon` target feature on ARM32 targets in rustdoc despite there
//! being a "forbidden" feature of the same name for aarch64, and rustdoc merging the
//! target features of all targets.
//@ check-pass
//@ revisions: arm aarch64
//@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf
//@[arm] needs-llvm-components: arm
//@[aarch64] compile-flags: --target aarch64-unknown-none-softfloat
//@[aarch64] needs-llvm-components: aarch64
#![crate_type = "lib"]
#![feature(no_core, lang_items)]
#![feature(arm_target_feature)]
#![no_core]
#[lang = "sized"]
pub trait Sized {}
// `fp-armv8` is "forbidden" on aarch64 as we tie it to `neon`.
#[target_feature(enable = "fp-armv8")]
pub fn fun1() {}
// This would usually be rejected as it changes the ABI.
// But we disable that check in rustdoc since we are building "for all targets" and the
// check can't really handle that.
#[target_feature(enable = "soft-float")]
pub fn fun2() {}

View file

@ -10,14 +10,15 @@
#[cfg_attr(
any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "haiku",
target_os = "illumos",
target_os = "haiku"
target_os = "linux",
target_os = "netbsd",
target_os = "nto",
target_os = "openbsd",
),
link_section = ".init_array"
)]

View file

@ -1,20 +1,7 @@
//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
// Auxiliary build problems with aarch64-apple:
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
// Auxiliary build problems with i686-mingw: linker `cc` not found
//@ only-x86
//@ ignore-windows
//@ ignore-apple
//@ no-prefer-dynamic
//@ compile-flags: --target i686-unknown-linux-gnu
//@ needs-llvm-components: x86
#![feature(no_core)]
#![crate_type = "rlib"]
#![no_core]
#![feature(no_core, lang_items, repr_simd)]
#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}
pub fn somefun() {}
pub struct S;

View file

@ -1,20 +1,7 @@
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Cpanic=abort
// Auxiliary build problems with aarch64-apple:
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
// Auxiliary build problems with i686-mingw: linker `cc` not found
//@ only-x86
//@ ignore-windows
//@ ignore-apple
//@ no-prefer-dynamic
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2
//@ needs-llvm-components: x86
#![feature(no_core)]
#![crate_type = "rlib"]
#![no_core]
#![feature(no_core, lang_items, repr_simd)]
#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}
pub fn somefun() {}
pub struct S;

View file

@ -1,20 +1,7 @@
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Zreg-struct-return=true -Cpanic=abort
// Auxiliary build problems with aarch64-apple:
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
// Auxiliary build problems with i686-mingw: linker `cc` not found
//@ only-x86
//@ ignore-windows
//@ ignore-apple
//@ no-prefer-dynamic
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Zreg-struct-return=true
//@ needs-llvm-components: x86
#![feature(no_core)]
#![crate_type = "rlib"]
#![no_core]
#![feature(no_core, lang_items, repr_simd)]
#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}
pub fn somefun() {}
pub struct S;

View file

@ -1,7 +1,7 @@
error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `defaults_check`
--> $DIR/defaults_check.rs:20:1
--> $DIR/defaults_check.rs:15:1
|
LL | #![crate_type = "rlib"]
LL | #![feature(no_core)]
| ^
|
= help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely

View file

@ -1,27 +1,20 @@
// Tests that default unspecified target modifier value in dependency crate is ok linked
// with the same value, explicitly specified
//@ aux-crate:default_reg_struct_return=default_reg_struct_return.rs
//@ aux-build:default_reg_struct_return.rs
//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
//@ revisions:error ok ok_explicit
//@ needs-llvm-components: x86
//@ revisions: ok ok_explicit error
//@[ok] compile-flags:
//@[ok_explicit] compile-flags: -Zreg-struct-return=false
//@[error] compile-flags: -Zreg-struct-return=true
//@[ok] check-pass
//@[ok_explicit] check-pass
// Auxiliary build problems with aarch64-apple:
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
// Auxiliary build problems with i686-mingw: linker `cc` not found
//@ only-x86
//@ ignore-windows
//@ ignore-apple
//@ needs-llvm-components: x86
//@[ok] build-pass
//@[ok_explicit] build-pass
#![crate_type = "rlib"]
#![feature(no_core)]
//[error]~^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `defaults_check`
#![crate_type = "rlib"]
#![no_core]
#![feature(no_core, lang_items, repr_simd)]
fn foo() {
default_reg_struct_return::somefun();
}
extern crate default_reg_struct_return;

View file

@ -1,7 +1,7 @@
error: mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm`
--> $DIR/incompatible_regparm.rs:16:1
--> $DIR/incompatible_regparm.rs:11:1
|
LL | #![crate_type = "rlib"]
LL | #![feature(no_core)]
| ^
|
= help: the `-Zregparm` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely

View file

@ -1,23 +1,16 @@
//@ aux-crate:wrong_regparm=wrong_regparm.rs
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=1 -Cpanic=abort
// Auxiliary build problems with aarch64-apple:
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
// Auxiliary build problems with i686-mingw: linker `cc` not found
//@ only-x86
//@ ignore-windows
//@ ignore-apple
//@ aux-build:wrong_regparm.rs
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=1
//@ needs-llvm-components: x86
//@ revisions:error_generated allow_regparm_mismatch allow_no_value
//@ revisions:allow_regparm_mismatch allow_no_value error_generated
//@[allow_regparm_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=regparm
//@[allow_regparm_mismatch] build-pass
//@[allow_no_value] compile-flags: -Cunsafe-allow-abi-mismatch
//@[error_generated] compile-flags:
//@[allow_regparm_mismatch] check-pass
#![crate_type = "rlib"]
#![feature(no_core)]
//[error_generated]~^ ERROR mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm`
#![crate_type = "rlib"]
#![no_core]
#![feature(no_core, lang_items, repr_simd)]
fn foo() {
wrong_regparm::somefun();
}
extern crate wrong_regparm;

View file

@ -1,23 +1,15 @@
//@ aux-crate:wrong_regparm_and_ret=wrong_regparm_and_ret.rs
//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
// Auxiliary build problems with aarch64-apple:
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
// Auxiliary build problems with i686-mingw: linker `cc` not found
//@ only-x86
//@ ignore-windows
//@ ignore-apple
//@ aux-build:wrong_regparm_and_ret.rs
//@ compile-flags: --target i686-unknown-linux-gnu
//@ needs-llvm-components: x86
//@ revisions:two_allowed unknown_allowed
//@[two_allowed] compile-flags: -Cunsafe-allow-abi-mismatch=regparm,reg-struct-return
//@[two_allowed] build-pass
//@[unknown_allowed] compile-flags: -Cunsafe-allow-abi-mismatch=unknown_flag -Zregparm=2 -Zreg-struct-return=true
//@[two_allowed] check-pass
#![crate_type = "rlib"]
#![feature(no_core)]
//[unknown_allowed]~^ ERROR unknown target modifier `unknown_flag`, requested by `-Cunsafe-allow-abi-mismatch=unknown_flag`
#![crate_type = "rlib"]
#![no_core]
#![feature(no_core, lang_items, repr_simd)]
fn foo() {
wrong_regparm_and_ret::somefun();
}
extern crate wrong_regparm_and_ret;

View file

@ -1,7 +1,7 @@
error: unknown target modifier `unknown_flag`, requested by `-Cunsafe-allow-abi-mismatch=unknown_flag`
--> $DIR/two_flags.rs:16:1
--> $DIR/two_flags.rs:10:1
|
LL | #![crate_type = "rlib"]
LL | #![feature(no_core)]
| ^
error: aborting due to 1 previous error