Skip to content

Rollup of 6 pull requests #137914

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b6f2240
rustdoc: disable forbidden #[target_feature] check
RalfJung Feb 25, 2025
039af88
also fix potential issues with mixed stable/unstable target features …
RalfJung Feb 25, 2025
745297e
Use helper function instead of reimplementing the logic to check if r…
GuillaumeGomez Feb 26, 2025
98eb2e3
Add rustdoc support for `--emit=dep-info[=path]`
GuillaumeGomez Feb 26, 2025
46a39f0
Add new `Rustdoc::emit` method in `run-make-support`
GuillaumeGomez Feb 26, 2025
b97310c
Add run-make test for rustdoc `--emit=dep-info` option
GuillaumeGomez Feb 26, 2025
e66bf08
sort list
tshepang Feb 28, 2025
f8091c4
qnx: avoid test failure
tshepang Feb 28, 2025
7fdd193
tests: Unignore target modifier tests on all platforms
petrochenkov Feb 28, 2025
dc04c0c
add test
RalfJung Feb 28, 2025
107d7ef
test(codegen): add looping_over_ne_bytes test for #133528
karolzwolak Feb 28, 2025
11e7aaf
jsondocck: minor cleanups
yotamofek Feb 15, 2025
94645f6
jsondocck: catch and error on deprecated syntax
yotamofek Feb 15, 2025
797ef64
htmldocck: catch and error on deprecated syntax
yotamofek Feb 15, 2025
4c939db
also skip abi_required_features check in rustdoc
RalfJung Feb 28, 2025
0447829
Rollup merge of #137103 - yotamofek:pr/jsonhtmldocck-deprecated-synta…
matthiaskrgr Mar 3, 2025
962e492
Rollup merge of #137632 - RalfJung:rustdoc-target-features, r=working…
matthiaskrgr Mar 3, 2025
f726e5c
Rollup merge of #137684 - GuillaumeGomez:rustdoc-dep-info, r=notriddle
matthiaskrgr Mar 3, 2025
65c34bb
Rollup merge of #137794 - tshepang:make-qnx-pass, r=pietroalbini
matthiaskrgr Mar 3, 2025
d818c1d
Rollup merge of #137801 - petrochenkov:tarmod, r=compiler-errors
matthiaskrgr Mar 3, 2025
15e97bd
Rollup merge of #137826 - karolzwolak:looping_over_ne_bytes_133528, r…
matthiaskrgr Mar 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 44 additions & 12 deletions compiler/rustc_codegen_ssa/src/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -87,12 +87,17 @@ 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!
if abi_feature_constraints.incompatible.contains(&name.as_str()) {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
feature: name.as_str(),
reason: "this feature is incompatible with the target ABI",
});
// 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(),
feature: name.as_str(),
reason: "this feature is incompatible with the target ABI",
});
}
}
target_features.push(TargetFeature { name, implied: name != feature_sym })
}
Expand Down Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions src/etc/htmldocck.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,24 @@ def filter_line(line):
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
Expand Down
28 changes: 22 additions & 6 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}
}
}
}
Expand All @@ -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)
Expand Down
24 changes: 18 additions & 6 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand All @@ -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 {
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/render/write_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
}
Expand Down
10 changes: 8 additions & 2 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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;
}
Expand Down
43 changes: 28 additions & 15 deletions src/tools/jsondocck/src/main.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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+
Expand All @@ -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)
Expand All @@ -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,
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.name("negated").unwrap().as_str() == "!";
let negated = &cap["negated"] == "!";

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);
errors = true;
continue;
}
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) {
Expand Down
7 changes: 7 additions & 0 deletions src/tools/run-make-support/src/external_deps/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
17 changes: 17 additions & 0 deletions tests/codegen/issues/looping-over-ne-bytes-133528.rs
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions tests/run-make/rustdoc-dep-info/bar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include!("foo.rs");
1 change: 1 addition & 0 deletions tests/run-make/rustdoc-dep-info/doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blablabla
1 change: 1 addition & 0 deletions tests/run-make/rustdoc-dep-info/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub fn foo() {}
6 changes: 6 additions & 0 deletions tests/run-make/rustdoc-dep-info/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![crate_name = "foo"]

#[cfg_attr(doc, doc = include_str!("doc.md"))]
pub struct Bar;

mod bar;
21 changes: 21 additions & 0 deletions tests/run-make/rustdoc-dep-info/rmake.rs
Original file line number Diff line number Diff line change
@@ -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());
}
Loading
Loading