diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 7a3d5a6bb2248..1b95376040201 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -107,14 +107,14 @@ pub fn link_binary( }); if outputs.outputs.should_link() { - let output = out_filename(sess, crate_type, outputs, crate_info.local_crate_name); + let output = out_filename(sess, crate_type, outputs); let tmpdir = TempDirBuilder::new() .prefix("rustc") .tempdir_in(output.parent().unwrap_or_else(|| Path::new("."))) .unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error })); let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps); - let crate_name = format!("{}", crate_info.local_crate_name); + let crate_name = format!("{}", sess.crate_name()); let out_filename = output.file_for_writing( outputs, OutputType::Exe, @@ -2747,12 +2747,8 @@ fn add_order_independent_options( cmd.optimize(); // Gather the set of NatVis files, if any, and write them out to a temp directory. - let natvis_visualizers = collect_natvis_visualizers( - tmpdir, - sess, - &crate_info.local_crate_name, - &crate_info.natvis_debugger_visualizers, - ); + let natvis_visualizers = + collect_natvis_visualizers(tmpdir, sess, &crate_info.natvis_debugger_visualizers); // Pass debuginfo, NatVis debugger visualizers and strip flags down to the linker. cmd.debuginfo(sess.opts.cg.strip, &natvis_visualizers); @@ -2783,13 +2779,12 @@ fn add_order_independent_options( fn collect_natvis_visualizers( tmpdir: &Path, sess: &Session, - crate_name: &Symbol, natvis_debugger_visualizers: &BTreeSet, ) -> Vec { let mut visualizer_paths = Vec::with_capacity(natvis_debugger_visualizers.len()); for (index, visualizer) in natvis_debugger_visualizers.iter().enumerate() { - let visualizer_out_file = tmpdir.join(format!("{}-{}.natvis", crate_name.as_str(), index)); + let visualizer_out_file = tmpdir.join(format!("{}-{}.natvis", sess.crate_name(), index)); match fs::write(&visualizer_out_file, &visualizer.src) { Ok(()) => { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index bdaed5bb42ee1..a5943f1978133 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -56,7 +56,7 @@ use rustc_session::config::{ use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::output::invalid_output_for_target; -use rustc_session::{EarlyDiagCtxt, Session, config}; +use rustc_session::{CrateName, EarlyDiagCtxt, Session, config}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, FileName}; use rustc_target::json::ToJson; @@ -589,6 +589,12 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) { }; } }; + + // This is the first point at which we have both a Session and the crate name. + let name = CrateName::from_normalized(sess, crate_info.local_crate_name, None); + #[expect(deprecated, reason = "we never previously loaded the crate name")] + sess.crate_name.set(name).expect("-Zlink-only should not build a full TyCtxt"); + compiler.codegen_backend.link(sess, compiled_modules, crate_info, metadata, &outputs); } else { dcx.emit_fatal(RlinkNotAFile {}); @@ -683,8 +689,8 @@ fn print_crate_info( // no crate attributes, print out an error and exit return Compilation::Continue; }; - let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); - let crate_name = passes::get_crate_name(sess, attrs); + passes::load_crate_name(sess, attrs); + let t_outputs = rustc_interface::util::build_output_filenames(sess); let crate_types = collect_crate_types( sess, &codegen_backend.supported_crate_types(sess), @@ -693,9 +699,7 @@ fn print_crate_info( DUMMY_SP, ); for &style in &crate_types { - let fname = rustc_session::output::filename_for_input( - sess, style, crate_name, &t_outputs, - ); + let fname = rustc_session::output::filename_for_input(sess, style, &t_outputs); println_info!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); } } @@ -704,16 +708,17 @@ fn print_crate_info( // no crate attributes, print out an error and exit return Compilation::Continue; }; - println_info!("{}", passes::get_crate_name(sess, attrs)); + passes::load_crate_name(sess, attrs); + println_info!("{}", sess.crate_name()); } CrateRootLintLevels => { let Some(attrs) = attrs.as_ref() else { // no crate attributes, print out an error and exit return Compilation::Continue; }; - let crate_name = passes::get_crate_name(sess, attrs); + passes::load_crate_name(sess, attrs); let lint_store = crate::unerased_lint_store(sess); - let features = rustc_expand::config::features(sess, attrs, crate_name); + let features = rustc_expand::config::features(sess, attrs); let registered_tools = rustc_resolve::registered_tools_ast(sess.dcx(), attrs, sess, &features); let lint_levels = rustc_lint::LintLevelsBuilder::crate_root( diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8e4039b32d942..ca4d3c372eef7 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -46,7 +46,8 @@ pub struct StripUnconfigured<'a> { pub lint_node_id: NodeId, } -pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features { +pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { + let crate_name = sess.crate_name(); let mut features = Features::default(); if let Some(hir::Attribute::Parsed(AttributeKind::Feature(feature_idents, _))) = diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index f73cc4d43e8c5..88dfaf3cf3412 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -117,7 +117,6 @@ use rustc_data_structures::{base_n, flock}; use rustc_fs_util::{LinkOrCopy, link_or_copy, try_canonicalize}; use rustc_middle::bug; use rustc_session::{Session, StableCrateId}; -use rustc_span::Symbol; use tracing::debug; use crate::errors; @@ -210,11 +209,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu /// The garbage collection will take care of it. /// /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph -pub(crate) fn prepare_session_directory( - sess: &Session, - crate_name: Symbol, - stable_crate_id: StableCrateId, -) { +pub(crate) fn prepare_session_directory(sess: &Session, stable_crate_id: StableCrateId) { if sess.opts.incremental.is_none() { return; } @@ -224,7 +219,7 @@ pub(crate) fn prepare_session_directory( debug!("prepare_session_directory"); // {incr-comp-dir}/{crate-name-and-disambiguator} - let crate_dir = crate_path(sess, crate_name, stable_crate_id); + let crate_dir = crate_path(sess, stable_crate_id); debug!("crate-dir: {}", crate_dir.display()); create_dir(sess, &crate_dir, "crate"); @@ -597,11 +592,14 @@ fn string_to_timestamp(s: &str) -> Result { Ok(UNIX_EPOCH + duration) } -fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf { +fn crate_path(sess: &Session, stable_crate_id: StableCrateId) -> PathBuf { let incr_dir = sess.opts.incremental.as_ref().unwrap().clone(); - let crate_name = - format!("{crate_name}-{}", stable_crate_id.as_u64().to_base_fixed_len(CASE_INSENSITIVE)); + let crate_name = format!( + "{}-{}", + sess.crate_name(), + stable_crate_id.as_u64().to_base_fixed_len(CASE_INSENSITIVE) + ); incr_dir.join(crate_name) } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index f7182e3614dc8..5a5cb023929cb 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -12,7 +12,6 @@ use rustc_serialize::Decodable; use rustc_serialize::opaque::MemDecoder; use rustc_session::config::IncrementalStateAssertion; use rustc_session::{Session, StableCrateId}; -use rustc_span::Symbol; use tracing::{debug, warn}; use super::data::*; @@ -205,13 +204,9 @@ pub fn load_query_result_cache(sess: &Session) -> Option { /// Setups the dependency graph by loading an existing graph from disk and set up streaming of a /// new graph to an incremental session directory. -pub fn setup_dep_graph( - sess: &Session, - crate_name: Symbol, - stable_crate_id: StableCrateId, -) -> DepGraph { +pub fn setup_dep_graph(sess: &Session, stable_crate_id: StableCrateId) -> DepGraph { // `load_dep_graph` can only be called after `prepare_session_directory`. - prepare_session_directory(sess, crate_name, stable_crate_id); + prepare_session_directory(sess, stable_crate_id); let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess)); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 5cf4b1546320f..e720972d6bda6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -33,12 +33,12 @@ use rustc_parse::lexer::StripTokens; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::{Resolver, ResolverOutputs}; -use rustc_session::Session; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; use rustc_session::output::{filename_for_input, invalid_output_for_target}; use rustc_session::parse::feature_err; use rustc_session::search_paths::PathKind; +use rustc_session::{CrateName, Session}; use rustc_span::{ DUMMY_SP, ErrorGuaranteed, ExpnKind, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, }; @@ -309,14 +309,13 @@ fn configure_and_expand( fn print_macro_stats(ecx: &ExtCtxt<'_>) { use std::fmt::Write; - let crate_name = ecx.ecfg.crate_name.as_str(); - let crate_name = if crate_name == "build_script_build" { + let crate_name = if ecx.ecfg.crate_name == sym::build_script_build { // This is a build script. Get the package name from the environment. let pkg_name = std::env::var("CARGO_PKG_NAME").unwrap_or_else(|_| "".to_string()); format!("{pkg_name} build script") } else { - crate_name.to_string() + ecx.ecfg.crate_name.to_string() }; // No instability because we immediately sort the produced vector. @@ -508,7 +507,6 @@ fn generated_output_paths( tcx: TyCtxt<'_>, outputs: &OutputFilenames, exact_name: bool, - crate_name: Symbol, ) -> Vec { let sess = tcx.sess; let mut out_filenames = Vec::new(); @@ -520,7 +518,7 @@ fn generated_output_paths( // by appending `.rlib`, `.exe`, etc., so we can skip this transformation. OutputType::Exe if !exact_name => { for crate_type in tcx.crate_types().iter() { - let p = filename_for_input(sess, *crate_type, crate_name, outputs); + let p = filename_for_input(sess, *crate_type, outputs); out_filenames.push(p.as_path().to_path_buf()); } } @@ -814,11 +812,9 @@ pub fn write_dep_info(tcx: TyCtxt<'_>) { let sess = tcx.sess; let _timer = sess.timer("write_dep_info"); - let crate_name = tcx.crate_name(LOCAL_CRATE); let outputs = tcx.output_filenames(()); - let output_paths = - generated_output_paths(tcx, outputs, sess.io.output_file.is_some(), crate_name); + let output_paths = generated_output_paths(tcx, outputs, sess.io.output_file.is_some()); // Ensure the source file isn't accidentally overwritten during compilation. if let Some(input_path) = sess.io.input.opt_path() { @@ -920,7 +916,8 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); - let crate_name = get_crate_name(sess, &pre_configured_attrs); + load_crate_name(sess, &pre_configured_attrs); + let crate_types = collect_crate_types( sess, &compiler.codegen_backend.supported_crate_types(sess), @@ -929,15 +926,15 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( krate.spans.inner_span, ); let stable_crate_id = StableCrateId::new( - crate_name, + sess.crate_name(), crate_types.contains(&CrateType::Executable), sess.opts.cg.metadata.clone(), sess.cfg_version, ); - let outputs = util::build_output_filenames(&pre_configured_attrs, sess); + let outputs = util::build_output_filenames(sess); - let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id); + let dep_graph = setup_dep_graph(sess, stable_crate_id); let cstore = FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _); @@ -1001,14 +998,12 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( |tcx| { let feed = tcx.create_crate_num(stable_crate_id).unwrap(); assert_eq!(feed.key(), LOCAL_CRATE); - feed.crate_name(crate_name); + feed.crate_name(sess.crate_name()); let feed = tcx.feed_unit_query(); - feed.features_query(tcx.arena.alloc(rustc_expand::config::features( - tcx.sess, - &pre_configured_attrs, - crate_name, - ))); + feed.features_query( + tcx.arena.alloc(rustc_expand::config::features(tcx.sess, &pre_configured_attrs)), + ); feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); feed.output_filenames(Arc::new(outputs)); @@ -1257,8 +1252,25 @@ pub(crate) fn start_codegen<'tcx>( (codegen, crate_info, metadata) } -/// Compute and validate the crate name. -pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol { +/// Compute and validate the crate name, then store it on the Session. +/// +/// NOTE: this function will panic if called more than once in the same Session. +#[expect(deprecated, reason = "initial crate name loading")] +#[track_caller] +pub fn load_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) { + let new_name = get_crate_name(sess, krate_attrs); + + // When we have `--print=file-names,crate-name`, we try to load the crate name more than once. + // Rather than panicking, just allow that as long as we'd use the same name both times. + if let Some(existing) = sess.crate_name.get() + && *existing == new_name + { + return; + } + sess.crate_name.set(new_name).expect("`load_crate_name` called more than once!"); +} + +fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> CrateName { // We validate *all* occurrences of `#![crate_name]`, pick the first find and // if a crate name was passed on the command line via `--crate-name` we enforce // that they match. @@ -1269,11 +1281,7 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol let attr_crate_name = parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal { also_emit_lints: true }); - let validate = |name, span| { - rustc_session::output::validate_crate_name(sess, name, span); - name - }; - + #[expect(deprecated, reason = "sess.crate_name isn't set yet")] if let Some(crate_name) = &sess.opts.crate_name { let crate_name = Symbol::intern(crate_name); if let Some((attr_crate_name, span)) = attr_crate_name @@ -1285,11 +1293,11 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol attr_crate_name, }); } - return validate(crate_name, None); + return CrateName::from_normalized(sess, crate_name, None); } if let Some((crate_name, span)) = attr_crate_name { - return validate(crate_name, Some(span)); + return CrateName::from_normalized(sess, crate_name, Some(span)); } if let Input::File(ref path) = sess.io.input @@ -1298,11 +1306,11 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol if file_stem.starts_with('-') { sess.dcx().emit_err(errors::CrateNameInvalid { crate_name: file_stem }); } else { - return validate(Symbol::intern(&file_stem.replace('-', "_")), None); + return CrateName::from_unnormalized(sess, file_stem, None); } } - sym::rust_out + CrateName::from_normalized(sess, sym::rust_out, None) } pub(crate) fn parse_crate_name( diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index bacdad25c50b3..72c63f8bba2f7 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,8 +5,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; use std::{env, thread}; -use rustc_ast as ast; -use rustc_attr_parsing::ShouldEmit; use rustc_codegen_ssa::back::archive::{ArArchiveBuilderBuilder, ArchiveBuilderBuilder}; use rustc_codegen_ssa::back::link::link_binary; use rustc_codegen_ssa::target_features::cfg_target_feature; @@ -30,7 +28,6 @@ use rustc_target::spec::Target; use tracing::info; use crate::errors; -use crate::passes::parse_crate_name; /// Function pointer type that constructs a new CodegenBackend. type MakeBackendFn = fn() -> Box; @@ -601,7 +598,7 @@ fn multiple_output_types_to_stdout( } } -pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> OutputFilenames { +pub fn build_output_filenames(sess: &Session) -> OutputFilenames { if multiple_output_types_to_stdout( &sess.opts.output_types, sess.io.output_file == Some(OutFileName::Stdout), @@ -609,10 +606,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu sess.dcx().emit_fatal(errors::MultipleOutputTypesToStdout); } - let crate_name = - sess.opts.crate_name.clone().or_else(|| { - parse_crate_name(sess, attrs, ShouldEmit::Nothing).map(|i| i.0.to_string()) - }); + let file_stem = sess.filestem().to_owned(); match sess.io.output_file { None => { @@ -621,13 +615,10 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu // We want to toss everything after the final '.' let dirpath = sess.io.output_dir.clone().unwrap_or_default(); - // If a crate name is present, we use it as the link name - let stem = crate_name.clone().unwrap_or_else(|| sess.io.input.filestem().to_owned()); - OutputFilenames::new( dirpath, - crate_name.unwrap_or_else(|| stem.replace('-', "_")), - stem, + sess.crate_name().to_string(), + file_stem, None, sess.io.temps_dir.clone(), sess.opts.unstable_opts.split_dwarf_out_dir.clone(), @@ -656,7 +647,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(); OutputFilenames::new( out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), - crate_name.unwrap_or_else(|| out_filestem.replace('-', "_")), + sess.crate_name().to_string(), out_filestem, ofile, sess.io.temps_dir.clone(), diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index fab0e9e863dc5..855069f23b182 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -65,12 +65,9 @@ fn cargo_help_sub( sess: &Session, inst: &impl Fn(EscapeQuotes) -> String, ) -> lints::UnexpectedCfgCargoHelp { - // We don't want to suggest the `build.rs` way to expected cfgs if we are already in a - // `build.rs`. We therefor do a best effort check (looking if the `--crate-name` is - // `build_script_build`) to try to figure out if we are building a Cargo build script - + // Don't suggest the `build.rs` way to expected cfgs if we are already in a `build.rs`. let unescaped = &inst(EscapeQuotes::No); - if let Some("build_script_build") = sess.opts.crate_name.as_deref() { + if sess.is_build_script() { lints::UnexpectedCfgCargoHelp::lint_cfg(unescaped) } else { lints::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes)) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 1fd6699e2506e..3c9729d575484 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::AssocContainer; use rustc_session::config::CrateType; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::{BytePos, Ident, Span, sym}; +use rustc_span::{Ident, Span, sym}; use crate::lints::{ NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub, @@ -320,34 +320,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { return; } - let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { - Some(Ident::from_str(name)) - } else { - find_attr!(cx.tcx, crate, CrateName{name, name_span,..} => (name, name_span)).map( - |(&name, &span)| { - // Discard the double quotes surrounding the literal. - let sp = cx - .sess() - .source_map() - .span_to_snippet(span) - .ok() - .and_then(|snippet| { - let left = snippet.find('"')?; - let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?; - - Some( - span.with_lo(span.lo() + BytePos(left as u32 + 1)) - .with_hi(span.hi() - BytePos(right as u32)), - ) - }) - .unwrap_or(span); - - Ident::new(name, sp) - }, - ) - }; - - if let Some(ident) = &crate_ident { + if let Some(ident) = &cx.tcx.local_crate_ident() { self.check_snake_case(cx, "crate", ident); } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index d4c61441bcea7..38645f00b6f69 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -492,7 +492,7 @@ pub struct CannotFindCrate { pub crate_name: Symbol, pub add_info: String, pub missing_core: bool, - pub current_crate: String, + pub current_crate: Symbol, pub is_nightly_build: bool, pub profiler_runtime: Symbol, pub locator_triple: TargetTuple, diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 5af60e9f19da7..ffebd90b03c62 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -1186,11 +1186,7 @@ impl CrateError { crate_name, add_info, missing_core, - current_crate: sess - .opts - .crate_name - .clone() - .unwrap_or_else(|| "".to_string()), + current_crate: sess.crate_name(), is_nightly_build: sess.is_nightly_build(), profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime), locator_triple: locator.triple, @@ -1212,11 +1208,7 @@ impl CrateError { crate_name, add_info: String::new(), missing_core, - current_crate: sess - .opts - .crate_name - .clone() - .unwrap_or_else(|| "".to_string()), + current_crate: sess.crate_name(), is_nightly_build: sess.is_nightly_build(), profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime), locator_triple: sess.opts.target_triple.clone(), diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 44ac747726a61..5989e14a90ba4 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -158,7 +158,7 @@ pub(crate) struct Reentrant; #[note( "an ideal reproduction consists of the code before and some patch that then triggers the bug when applied and compiled again" )] -#[note("as a workaround, you can run {$run_cmd} to allow your project to compile")] +#[note("as a workaround, you can {$run_cmd} to allow your project to compile")] pub(crate) struct IncrementCompilation { pub run_cmd: String, pub dep_node: String, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 91105f416c8f8..e087a2131f104 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -44,7 +44,7 @@ use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; use rustc_session::lint::Lint; use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw}; use rustc_type_ir::TyKind::*; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::{CollectAndApply, TypeFlags, WithCachedTypeInfo, elaborate, search_graph}; @@ -1495,6 +1495,40 @@ impl<'tcx> TyCtxt<'tcx> { f(StableHashingContext::new(self.sess, &self.untracked)) } + /// For use in diagnostics only. + pub fn local_crate_ident(self) -> Option { + #[expect( + deprecated, + reason = "we care about the difference between the option and the attribute for diagnostics" + )] + if let Some(name) = &self.sess.opts.crate_name { + return Some(Ident::from_str(name)); + } + + find_attr!(self, crate, CrateName{name, name_span,..} => (name, name_span)).map( + |(&name, &span)| { + // Discard the double quotes surrounding the literal. + let sp = self + .sess + .source_map() + .span_to_snippet(span) + .ok() + .and_then(|snippet| { + let left = snippet.find('"')?; + let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?; + + Some( + span.with_lo(span.lo() + BytePos(left as u32 + 1)) + .with_hi(span.hi() - BytePos(right as u32)), + ) + }) + .unwrap_or(span); + + Ident::new(name, sp) + }, + ) + } + #[inline] pub fn local_crate_exports_generics(self) -> bool { // compiler-builtins has some special treatment in codegen, which can result in confusing diff --git a/compiler/rustc_middle/src/verify_ich.rs b/compiler/rustc_middle/src/verify_ich.rs index a1ab4d8cc4d00..5aa7a1d91f800 100644 --- a/compiler/rustc_middle/src/verify_ich.rs +++ b/compiler/rustc_middle/src/verify_ich.rs @@ -1,6 +1,8 @@ use std::cell::Cell; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_session::utils::was_invoked_from_cargo; use tracing::instrument; use crate::dep_graph::{DepGraphData, SerializedDepNodeIndex}; @@ -66,10 +68,10 @@ fn incremental_verify_ich_failed<'tcx>( if old_in_panic { tcx.dcx().emit_err(crate::error::Reentrant); } else { - let run_cmd = if let Some(crate_name) = &tcx.sess.opts.crate_name { - format!("`cargo clean -p {crate_name}` or `cargo clean`") + let run_cmd = if was_invoked_from_cargo() { + format!("run `cargo clean -p {}` or `cargo clean`", tcx.crate_name(LOCAL_CRATE)) } else { - "`cargo clean`".to_string() + "clean your build cache".to_owned() }; let dep_node = tcx.dep_graph.data().unwrap().prev_node_of(prev_index); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0677ca0fddbaa..49d8550f6844c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1012,6 +1012,8 @@ pub enum Input { } impl Input { + #[deprecated = "Use [`Session::filestem`] instead"] + /// This exists for rustdoc, but should probably just be inlined there at some point. pub fn filestem(&self) -> &str { if let Input::File(ifile) = self { // If for some reason getting the file stem as a UTF-8 string fails, @@ -1204,6 +1206,7 @@ impl OutputFilenames { } pub fn interface_path(&self) -> PathBuf { + debug!("using crate_name={} for interface_path", self.crate_stem); self.out_directory.join(format!("lib{}.rs", self.crate_stem)) } @@ -1213,6 +1216,7 @@ impl OutputFilenames { let extension = flavor.extension(); match flavor { OutputType::Metadata => { + debug!("using crate_name={} for {extension}", self.crate_stem); self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension)) } _ => self.with_directory_and_extension(&self.out_directory, extension), @@ -1287,6 +1291,7 @@ impl OutputFilenames { } pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf { + debug!("using filestem={} for {extension}", self.filestem); let mut path = directory.join(&self.filestem); path.set_extension(extension); path @@ -1425,6 +1430,7 @@ impl Default for Options { error_format: ErrorOutputType::default(), diagnostic_width: None, externs: Externs(BTreeMap::new()), + #[expect(deprecated)] crate_name: None, libs: Vec::new(), unstable_features: UnstableFeatures::Disallow, @@ -2780,6 +2786,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M diagnostic_width, externs, unstable_features, + #[expect(deprecated)] crate_name, libs, debug_assertions, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 0bc432a0ff06c..b71b019d9a42e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -323,6 +323,7 @@ macro_rules! top_level_options { } impl Options { + #[expect(deprecated, reason = "need to hash all CLI options even if they're not present")] pub fn dep_tracking_hash(&self, for_crate_hash: bool) -> Hash64 { let mut sub_hashes = BTreeMap::new(); $({ @@ -428,6 +429,7 @@ top_level_options!( prints: Vec [UNTRACKED], cg: CodegenOptions [SUBSTRUCT CodegenOptionsTargetModifiers CodegenOptions], externs: Externs [UNTRACKED], + #[deprecated = "use `Session::crate_name()` instead, which accounts for `#![crate_name]`"] crate_name: Option [TRACKED], /// Indicates how the compiler should treat unstable features. unstable_features: UnstableFeatures [TRACKED], diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 9224368f90d6e..53831048e8f8d 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -12,9 +12,8 @@ pub fn out_filename( sess: &Session, crate_type: CrateType, outputs: &OutputFilenames, - crate_name: Symbol, ) -> OutFileName { - let default_filename = filename_for_input(sess, crate_type, crate_name, outputs); + let default_filename = filename_for_input(sess, crate_type, outputs); let out_filename = outputs .outputs .get(&OutputType::Exe) @@ -87,10 +86,9 @@ pub fn filename_for_metadata(sess: &Session, outputs: &OutputFilenames) -> OutFi pub fn filename_for_input( sess: &Session, crate_type: CrateType, - crate_name: Symbol, outputs: &OutputFilenames, ) -> OutFileName { - let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename); + let libname = format!("{}{}", sess.crate_name(), sess.opts.cg.extra_filename); match crate_type { CrateType::Rlib => { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 0548380331bef..169e03ec0d906 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,8 +1,8 @@ use std::any::Any; use std::path::PathBuf; use std::str::FromStr; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicUsize}; +use std::sync::{Arc, OnceLock}; use std::{env, io}; use rand::{RngCore, rng}; @@ -41,6 +41,7 @@ use crate::config::{ }; use crate::filesearch::FileSearch; use crate::lint::LintId; +use crate::output::validate_crate_name; use crate::parse::{ParseSess, add_feature_diagnostics}; use crate::search_paths::SearchPath; use crate::{errors, filesearch, lint}; @@ -83,9 +84,39 @@ pub trait DynLintStore: Any + DynSync + DynSend { fn lint_groups_iter(&self) -> Box + '_>; } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct CrateName { + pub normalized: Symbol, + /// See [`Session::filestem`] for why this exists. + pub unnormalized: Symbol, +} + +impl CrateName { + pub fn from_normalized(sess: &Session, name: Symbol, span: Option) -> Self { + validate_crate_name(sess, name, span); + CrateName { normalized: name, unnormalized: name } + } + + pub fn from_unnormalized(sess: &Session, unnormalized: &str, span: Option) -> Self { + let normalized = Symbol::intern(&unnormalized.replace('-', "_")); + validate_crate_name(sess, normalized, span); + + CrateName { normalized, unnormalized: Symbol::intern(unnormalized) } + } +} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { + #[deprecated = "use `Session::crate_name()` instead"] + /// The name of the current crate. + /// + /// We need a `OnceLock` here because we may not have the crate name available extremely early + /// in `Session` construction. I tried moving `#![crate_attr]` parsing earlier before the + /// Session was constructed, but that didn't have a way to support mutating the `ast::Crate` in + /// `Callbacks::after_crate_root_parsing`. + pub crate_name: OnceLock, + pub target: Target, pub host: Target, pub opts: config::Options, @@ -1021,6 +1052,7 @@ pub fn build_session( let profiler = SelfProfiler::new( directory, + #[expect(deprecated, reason = "need a profiler before we parse the crate attributes")] sopts.crate_name.as_deref(), sopts.unstable_opts.self_profile_events.as_deref(), &sopts.unstable_opts.self_profile_counter, @@ -1076,6 +1108,8 @@ pub fn build_session( let timings = TimingSectionHandler::new(sopts.json_timings); let sess = Session { + #[expect(deprecated, reason = "session construction")] + crate_name: OnceLock::new(), target, host, opts: sopts, diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index c64d9bc1efefb..a65eae725618d 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -5,6 +5,7 @@ use rustc_data_structures::profiling::VerboseTimingGuard; use rustc_fs_util::try_canonicalize; use rustc_hir::attrs::NativeLibKind; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_span::{Symbol, sym}; use crate::session::Session; @@ -16,6 +17,53 @@ impl Session { pub fn time(&self, what: &'static str, f: impl FnOnce() -> R) -> R { self.prof.verbose_generic_activity(what).run(f) } + + /// Return the normalized final crate name. + /// + /// Crate name precedence is as follows: + /// - `#![crate_name]` must match `--crate-name` if both are present. + /// - Both `#![crate_name]` and `--crate-name` are validated. + /// - If neither are present, the input comes from an on-disk file, and the file is valid + /// UTF-8, the normalized filename. The normalized filename is not validated. + /// - Otherwise, `rust_out`. + /// + /// If you don't want the crate name to be normalized, use [`Session::filestem`]. + /// + /// Note that `#![cfg_attr(..., crate_name = "...")]` is a hard error. + /// Note that the normalization applied to input filestem is very incomplete and cannot be + /// relied upon to produce a valid Rust ientifier. + /// + /// See `rustc_interface::passes::get_crate_name` for more info. + #[track_caller] + pub fn crate_name(&self) -> Symbol { + #[expect(deprecated, reason = "can't use crate_name(), we are crate_name()")] + self.crate_name.get().expect("call `load_crate_name` before crate_name").normalized + } + + /// Get the unnormalized crate name, as suitable for an [`OutFileName`]. + /// If no crate name was present, fall back to the filestem of the input. + /// + /// Note that no normalization is applied and the stem may be an invalid Rust identifier. + /// + /// Usually you don't want this and should use [`Session::crate_name`] instead. + /// See its docs for more information. + /// + /// I don't know why some existing code depends on this behavior but it does. + #[track_caller] + pub fn filestem(&self) -> &str { + #[expect(deprecated, reason = "can't use crate_name(), we are crate_name()")] + self.crate_name + .get() + .as_ref() + .expect("call `load_crate_name` before crate_name") + .unnormalized + .as_str() + } + + /// Check if this a Cargo build script. If so, it will be named `build_script_build`. + pub fn is_build_script(&self) -> bool { + self.crate_name() == sym::build_script_build + } } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cd437357456e1..8b437278c3087 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -539,6 +539,7 @@ symbols! { breakpoint, bridge, bswap, + build_script_build, built, builtin_syntax, bundle, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 89b4df1a51ce5..a430c85e8b63d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -270,6 +270,7 @@ pub(crate) fn create_config( diagnostic_width, edition, describe_lints, + #[expect(deprecated)] crate_name, test, remap_path_prefix, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a61f85bd40074..5af8dce213ed2 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -22,7 +22,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxHasher, FxIndexMap, FxIn use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; use rustc_hir::attrs::AttributeKind; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{Attribute, CRATE_HIR_ID}; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; @@ -77,8 +76,16 @@ impl MergedDoctestTimes { /// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`). #[derive(Clone)] pub(crate) struct GlobalTestOptions { - /// Name of the crate (for regular `rustdoc`) or Markdown file (for `rustdoc foo.md`). - pub(crate) crate_name: String, + /// Name of the crate (when invoked on a Rust file) + /// + /// This can't be a `Symbol` because it's used outside the thread-local context of an + /// interner. + pub(crate) crate_name: Option, + /// Filestem of the output. + /// + /// When invoked on a Rust file, this is based on crate name and input filestem. + /// When invoked on a Markdown file, this is only based on filestem. + pub(crate) filestem: String, /// Whether to disable the default `extern crate my_crate;` when creating doctests. pub(crate) no_crate_inject: bool, /// Whether inserting extra indent spaces in code block, @@ -88,6 +95,18 @@ pub(crate) struct GlobalTestOptions { pub(crate) args_file: PathBuf, } +impl GlobalTestOptions { + /// Suitable for passing to [`BuildDocTestBuilder::crate_name`]. + /// + /// NOTE: the returned name is not normalized and may not be a valid Rust identifier. + fn name_for_doctest(&self) -> &str { + match &self.crate_name { + Some(input_name) => input_name.as_str(), + None => &self.filestem, + } + } +} + pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> { let mut file = File::create(file_path) .map_err(|error| format!("failed to create args file: {error:?}"))?; @@ -169,6 +188,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions actually_rustdoc: true, edition: options.edition, target_triple: options.target.clone(), + #[expect(deprecated)] crate_name: options.crate_name.clone(), remap_path_prefix: options.remap_path_prefix.clone(), unstable_opts: options.unstable_opts.clone(), @@ -217,8 +237,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions let krate = rustc_interface::passes::parse(&compiler.sess); let collector = rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| { - let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); - let opts = scrape_test_config(tcx, crate_name, args_path); + let opts = scrape_test_config(tcx, args_path); let hir_collector = HirCollector::new( ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), @@ -392,7 +411,6 @@ pub(crate) fn run_tests( &scraped_test.text, scraped_test.langstr.test_harness, &opts, - Some(&opts.crate_name), ); standalone_tests.push(generate_test_desc_and_fn( doctest, @@ -432,13 +450,10 @@ pub(crate) fn run_tests( } // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. -fn scrape_test_config( - tcx: TyCtxt<'_>, - crate_name: String, - args_file: PathBuf, -) -> GlobalTestOptions { +fn scrape_test_config(tcx: TyCtxt<'_>, args_file: PathBuf) -> GlobalTestOptions { let mut opts = GlobalTestOptions { - crate_name, + crate_name: Some(tcx.sess.crate_name().to_string()), + filestem: tcx.sess.filestem().to_owned(), no_crate_inject: false, insert_indent_space: false, args_file, @@ -1047,7 +1062,7 @@ impl CreateRunnableDocTests { let edition = scraped_test.edition(&self.rustdoc_options); let doctest = BuildDocTestBuilder::new(&scraped_test.text) - .crate_name(&self.opts.crate_name) + .crate_name(self.opts.name_for_doctest()) .global_crate_attrs(scraped_test.global_crate_attrs.clone()) .edition(edition) .can_merge_doctests(self.can_merge_doctests) @@ -1155,7 +1170,6 @@ fn doctest_run_fn( &scraped_test.text, scraped_test.langstr.test_harness, &global_opts, - Some(&global_opts.crate_name), ); let runnable_test = RunnableDocTest { full_test_code: wrapped.to_string(), diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs index a3eb03f7c839a..3534ec2ad5bdc 100644 --- a/src/librustdoc/doctest/extracted.rs +++ b/src/librustdoc/doctest/extracted.rs @@ -51,17 +51,12 @@ impl ExtractedDocTests { scraped_test; let doctest = BuildDocTestBuilder::new(&text) - .crate_name(&opts.crate_name) + .crate_name(&opts.name_for_doctest()) .global_crate_attrs(global_crate_attrs) .edition(edition) .lang_str(&langstr) .build(None); - let (wrapped, _size) = doctest.generate_unique_doctest( - &text, - langstr.test_harness, - opts, - Some(&opts.crate_name), - ); + let (wrapped, _size) = doctest.generate_unique_doctest(&text, langstr.test_harness, opts); self.doctests.push(ExtractedDocTest { file: filename.display(RemapPathScopeComponents::DOCUMENTATION).to_string(), line, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 7dd738abca433..65273e5ba7ad0 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -312,7 +312,6 @@ impl DocTestBuilder { test_code: &str, dont_insert_main: bool, opts: &GlobalTestOptions, - crate_name: Option<&str>, ) -> (DocTestWrapResult, usize) { if self.invalid_ast { // If the AST failed to compile, no need to go generate a complete doctest, the error @@ -363,7 +362,7 @@ impl DocTestBuilder { // compiler. if !self.already_has_extern_crate && !opts.no_crate_inject && - let Some(crate_name) = crate_name && + let Some(crate_name) = &opts.crate_name && crate_name != "std" && // Don't inject `extern crate` if the crate is never used. // NOTE: this is terribly inaccurate because it doesn't actually diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index f02e0d6df1983..7078f1781de68 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -88,15 +88,16 @@ pub(crate) fn test(input: &Input, options: Options, dcx: DiagCtxtHandle<'_>) -> Input::Str { name: _, input } => input.clone(), }; - // Obviously not a real crate name, but close enough for purposes of doctests. - let crate_name = input.filestem().to_string(); + #[expect(deprecated, reason = "don't have a Session when running markdown files")] + let filestem = input.filestem().to_string(); let temp_dir = tempdir().map_err(|error| format!("failed to create temporary directory: {error:?}"))?; let args_file = temp_dir.path().join("rustdoc-cfgs"); generate_args_file(&args_file, &options)?; let opts = GlobalTestOptions { - crate_name, + crate_name: None, + filestem, no_crate_inject: true, insert_indent_space: false, args_file, diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index ccc3e55a33122..fd1694bd63d56 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -24,15 +24,16 @@ fn make_test( builder = builder.test_id(test_id.to_string()); } let doctest = builder.build(None); - let (wrapped, line_offset) = - doctest.generate_unique_doctest(test_code, dont_insert_main, opts, crate_name); + let (wrapped, line_offset) = doctest.generate_unique_doctest(test_code, dont_insert_main, opts); (wrapped.to_string(), line_offset) } /// Default [`GlobalTestOptions`] for these unit tests. fn default_global_opts(crate_name: impl Into) -> GlobalTestOptions { + let crate_name = crate_name.into(); GlobalTestOptions { - crate_name: crate_name.into(), + crate_name: Some(crate_name.clone()), + filestem: crate_name, no_crate_inject: false, insert_indent_space: false, args_file: PathBuf::new(), diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 858545bd09847..d68422b0f6877 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -45,8 +45,8 @@ use rustc_resolve::rustdoc::may_be_doc_link; use rustc_resolve::rustdoc::pulldown_cmark::{ self, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, TagEnd, html, }; +use rustc_span::Span; use rustc_span::edition::Edition; -use rustc_span::{Span, Symbol}; use tracing::{debug, trace}; use crate::clean::RenderedLink; @@ -204,7 +204,10 @@ fn slugify(c: char) -> Option { #[derive(Debug)] pub struct Playground { - pub crate_name: Option, + /// See [`GlobalTestOptions::crate_name`]. + pub crate_name: Option, + /// See [`GlobalTestOptions::filestem`]. + pub filestem: String, pub url: String, } @@ -287,7 +290,6 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { let edition = edition.unwrap_or(self.edition); let playground_button = self.playground.as_ref().and_then(|playground| { - let krate = &playground.crate_name; let url = &playground.url; if url.is_empty() { return None; @@ -297,22 +299,22 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .map(|l| map_line(l).for_code()) .intersperse("\n".into()) .collect::(); - let krate = krate.as_ref().map(|s| s.as_str()); // FIXME: separate out the code to make a code block into runnable code // from the complicated doctest logic let opts = GlobalTestOptions { - crate_name: krate.map(String::from).unwrap_or_default(), + crate_name: playground.crate_name.clone(), + filestem: playground.filestem.clone(), no_crate_inject: false, insert_indent_space: true, args_file: PathBuf::new(), }; let mut builder = doctest::BuildDocTestBuilder::new(&test).edition(edition); - if let Some(krate) = krate { - builder = builder.crate_name(krate); + if let Some(krate) = &playground.crate_name { + builder = builder.crate_name(krate.as_str()); } let doctest = builder.build(None); - let (wrapped, _) = doctest.generate_unique_doctest(&test, false, &opts, krate); + let (wrapped, _) = doctest.generate_unique_doctest(&test, false, &opts); let test = wrapped.to_string(); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 4a7b1d1d6c563..9dd9c3ce82880 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -517,8 +517,14 @@ impl<'tcx> Context<'tcx> { }; // If user passed in `--playground-url` arg, we fill in crate name here let mut playground = None; + let crate_name = Some(tcx.sess.crate_name().to_string()); + let filestem = tcx.sess.filestem(); if let Some(url) = playground_url { - playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url }); + playground = Some(markdown::Playground { + crate_name: crate_name.clone(), + filestem: filestem.to_owned(), + url, + }); } let krate_version = cache.crate_version.as_deref().unwrap_or_default(); let mut layout = layout::Layout { @@ -546,7 +552,9 @@ impl<'tcx> Context<'tcx> { } if let Some((html_playground_url, _)) = d.html_playground_url { playground = Some(markdown::Playground { - crate_name: Some(krate.name(tcx)), + crate_name: crate_name.clone(), + filestem: filestem.to_owned(), + // FIXME: is it intentional that this overrides `--playground-url`? url: html_playground_url.to_string(), }); } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 4ca2c104888bb..6646ee4a889b9 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -66,7 +66,11 @@ pub(crate) fn render_and_write>( let input_str = read_to_string(input).map_err(|err| format!("{input}: {err}", input = input.display()))?; let playground_url = options.markdown_playground_url.or(options.playground_url); - let playground = playground_url.map(|url| markdown::Playground { crate_name: None, url }); + let playground = playground_url.map(|url| markdown::Playground { + crate_name: None, + filestem: input.file_stem().unwrap_or_default().to_string_lossy().to_string(), + url, + }); let mut out = File::create(&output).map_err(|e| format!("{output}: {e}", output = output.display()))?; diff --git a/src/tools/clippy/clippy_lints/src/write/mod.rs b/src/tools/clippy/clippy_lints/src/write/mod.rs index 8d896046200b4..981d145f3e1fb 100644 --- a/src/tools/clippy/clippy_lints/src/write/mod.rs +++ b/src/tools/clippy/clippy_lints/src/write/mod.rs @@ -294,17 +294,10 @@ impl<'tcx> LateLintPass<'tcx> for Write { return; }; - let is_build_script = cx - .sess() - .opts - .crate_name - .as_ref() - .is_some_and(|crate_name| crate_name == "build_script_build"); - let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id); match diag_name { sym::print_macro | sym::println_macro if !allowed_in_tests => { - if !is_build_script { + if !cx.sess().is_build_script() { span_lint(cx, PRINT_STDOUT, macro_call.span, format!("use of `{name}!`")); } }, diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 3766debb159d0..a1bd9e76614c8 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -67,7 +67,7 @@ use rustc_middle::query::LocalCrate; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::EarlyDiagCtxt; -use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options}; +use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options, OutputType}; use rustc_span::def_id::DefId; use rustc_target::spec::Target; @@ -224,7 +224,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // Obtain and complete the Miri configuration. let mut config = self.miri_config.take().expect("after_analysis must only be called once"); // Add filename to `miri` arguments. - config.args.insert(0, tcx.sess.io.input.filestem().to_string()); + let exe_path = tcx.output_filenames(()).path(OutputType::Exe); + let exe_stem = exe_path.filestem().unwrap().to_string_lossy(); + config.args.insert(0, exe_stem.to_string()); // Adjust working directory for interpretation. if let Some(cwd) = env::var_os("MIRI_CWD") { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 000f4ac4cecaa..b50ce3d39b98f 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -673,8 +673,7 @@ impl<'tcx> MiriMachine<'tcx> { let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); let profiler = config.measureme_out.as_ref().map(|out| { - let crate_name = - tcx.sess.opts.crate_name.clone().unwrap_or_else(|| "unknown-crate".to_string()); + let crate_name = tcx.sess.crate_name(); let pid = process::id(); // We adopt the same naming scheme for the profiler output that rustc uses. In rustc, // the PID is padded so that the nondeterministic value of the PID does not spread diff --git a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs index 5dd11b0a016e3..523bd14bec4b3 100644 --- a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs +++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs @@ -57,7 +57,7 @@ impl CodegenBackend for TheBackend { &self, sess: &Session, _compiled_modules: CompiledModules, - crate_info: CrateInfo, + _crate_info: CrateInfo, _metadata: EncodedMetadata, outputs: &OutputFilenames, ) { @@ -66,12 +66,11 @@ impl CodegenBackend for TheBackend { use rustc_session::config::{CrateType, OutFileName}; use rustc_session::output::out_filename; - let crate_name = crate_info.local_crate_name; for &crate_type in sess.opts.crate_types.iter() { if crate_type != CrateType::Rlib { sess.dcx().fatal(format!("Crate type is {:?}", crate_type)); } - let output_name = out_filename(sess, crate_type, &outputs, crate_name); + let output_name = out_filename(sess, crate_type, &outputs); match output_name { OutFileName::Real(ref path) => { let mut out_file = ::std::fs::File::create(path).unwrap(); diff --git a/tests/ui-fulldeps/internal-lints/bad_opt_access.rs b/tests/ui-fulldeps/internal-lints/bad_opt_access.rs index a2a94db919d8b..00424093f2421 100644 --- a/tests/ui-fulldeps/internal-lints/bad_opt_access.rs +++ b/tests/ui-fulldeps/internal-lints/bad_opt_access.rs @@ -17,6 +17,6 @@ pub fn access_bad_option(sess: Session) { let _ = sess.opts.crate_types; //~^ ERROR use `TyCtxt::crate_types` instead of this field - let _ = sess.opts.crate_name; + let _ = sess.opts.prints; // okay! }