diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index ed95bd34c685..38ee87601614 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -42,6 +42,7 @@ use rustc_feature::find_gated_cfg; // `rust_index` isn't used in this crate's code, but it must be named in the // `Cargo.toml` for the `rustc_randomized_layouts` feature. use rustc_index as _; +use rustc_interface::passes::collect_crate_types; use rustc_interface::util::{self, get_codegen_backend}; use rustc_interface::{Linker, create_and_enter_global_ctxt, interface, passes}; use rustc_lint::unerased_lint_store; @@ -56,10 +57,10 @@ use rustc_session::config::{ }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; -use rustc_session::output::{collect_crate_types, invalid_output_for_target}; +use rustc_session::output::invalid_output_for_target; use rustc_session::{EarlyDiagCtxt, Session, config}; -use rustc_span::FileName; use rustc_span::def_id::LOCAL_CRATE; +use rustc_span::{DUMMY_SP, FileName}; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTuple}; use tracing::trace; @@ -698,6 +699,7 @@ fn print_crate_info( &codegen_backend.supported_crate_types(sess), codegen_backend.name(), attrs, + DUMMY_SP, ); for &style in &crate_types { let fname = rustc_session::output::filename_for_input( diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index e1ef6c12fb0f..d898e9bf7d1e 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -48,3 +48,9 @@ interface_proc_macro_crate_panic_abort = interface_temps_dir_error = failed to find or create the directory specified by `--temps-dir` + +interface_unsupported_crate_type_for_codegen_backend = + dropping unsupported crate type `{$crate_type}` for codegen backend `{$codegen_backend}` + +interface_unsupported_crate_type_for_target = + dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index d1082eaf6173..aee8ec20e14d 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -1,8 +1,10 @@ use std::io; use std::path::Path; +use rustc_hir::attrs::CrateType; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; +use rustc_target::spec::TargetTuple; #[derive(Diagnostic)] #[diag(interface_crate_name_does_not_match)] @@ -108,3 +110,17 @@ pub(crate) struct AbiRequiredTargetFeature<'a> { pub feature: &'a str, pub enabled: &'a str, } + +#[derive(Diagnostic)] +#[diag(interface_unsupported_crate_type_for_codegen_backend)] +pub(crate) struct UnsupportedCrateTypeForCodegenBackend { + pub(crate) crate_type: CrateType, + pub(crate) codegen_backend: &'static str, +} + +#[derive(Diagnostic)] +#[diag(interface_unsupported_crate_type_for_target)] +pub(crate) struct UnsupportedCrateTypeForTarget<'a> { + pub(crate) crate_type: CrateType, + pub(crate) target_triple: &'a TargetTuple, +} diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 57eed76a5c25..3228a0499acc 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -5,8 +5,8 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, LazyLock, OnceLock}; use std::{env, fs, iter}; -use rustc_ast as ast; -use rustc_attr_parsing::{AttributeParser, ShouldEmit}; +use rustc_ast::{self as ast, CRATE_NODE_ID}; +use rustc_attr_parsing::{AttributeParser, Early, ShouldEmit}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenResults, CrateInfo}; use rustc_data_structures::jobserver::Proxy; @@ -17,6 +17,7 @@ use rustc_errors::timings::TimingSection; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; +use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; @@ -35,7 +36,7 @@ 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::{collect_crate_types, filename_for_input}; +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_span::{ @@ -927,6 +928,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( &compiler.codegen_backend.supported_crate_types(sess), compiler.codegen_backend.name(), &pre_configured_attrs, + krate.spans.inner_span, ); let stable_crate_id = StableCrateId::new( crate_name, @@ -1345,6 +1347,94 @@ pub(crate) fn parse_crate_name( Some((name, name_span)) } +pub fn collect_crate_types( + session: &Session, + backend_crate_types: &[CrateType], + codegen_backend_name: &'static str, + attrs: &[ast::Attribute], + crate_span: Span, +) -> Vec { + // If we're generating a test executable, then ignore all other output + // styles at all other locations + if session.opts.test { + if !session.target.executables { + session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { + crate_type: CrateType::Executable, + target_triple: &session.opts.target_triple, + }); + return Vec::new(); + } + return vec![CrateType::Executable]; + } + + // Shadow `sdylib` crate type in interface build. + if session.opts.unstable_opts.build_sdylib_interface { + return vec![CrateType::Rlib]; + } + + // Only check command line flags if present. If no types are specified by + // command line, then reuse the empty `base` Vec to hold the types that + // will be found in crate attributes. + // JUSTIFICATION: before wrapper fn is available + #[allow(rustc::bad_opt_access)] + let mut base = session.opts.crate_types.clone(); + if base.is_empty() { + if let Some(Attribute::Parsed(AttributeKind::CrateType(crate_type))) = + AttributeParser::::parse_limited_should_emit( + session, + attrs, + sym::crate_type, + crate_span, + CRATE_NODE_ID, + None, + ShouldEmit::EarlyFatal { also_emit_lints: false }, + ) + { + base.extend(crate_type); + } + + if base.is_empty() { + base.push(default_output_for_target(session)); + } else { + base.sort(); + base.dedup(); + } + } + + base.retain(|crate_type| { + if invalid_output_for_target(session, *crate_type) { + session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { + crate_type: *crate_type, + target_triple: &session.opts.target_triple, + }); + false + } else if !backend_crate_types.contains(crate_type) { + session.dcx().emit_warn(errors::UnsupportedCrateTypeForCodegenBackend { + crate_type: *crate_type, + codegen_backend: codegen_backend_name, + }); + false + } else { + true + } + }); + + base +} + +/// Returns default crate type for target +/// +/// Default crate type is used when crate type isn't provided neither +/// through cmd line arguments nor through crate attributes +/// +/// It is CrateType::Executable for all platforms but iOS as there is no +/// way to run iOS binaries anyway without jailbreaking and +/// interaction with Rust code through static library is the only +/// option for now +fn default_output_for_target(sess: &Session) -> CrateType { + if !sess.target.executables { CrateType::StaticLib } else { CrateType::Executable } +} + fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { let attr = AttributeParser::parse_limited_should_emit( sess, diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index eff55e8e02a2..5c851cb90a66 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -141,12 +141,6 @@ session_unleashed_feature_help_unnamed = skipping check that does not even have session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` -session_unsupported_crate_type_for_codegen_backend = - dropping unsupported crate type `{$crate_type}` for codegen backend `{$codegen_backend}` - -session_unsupported_crate_type_for_target = - dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` - session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is not supported session_unsupported_dwarf_version_help = supported DWARF versions are 2, 3, 4 and 5 diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 6fd86aec7ad9..54e792fd7b59 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -11,7 +11,6 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTuple}; -use crate::config::CrateType; use crate::parse::ParseSess; #[derive(Diagnostic)] @@ -376,20 +375,6 @@ struct BinaryFloatLiteralNotSupported { span: Span, } -#[derive(Diagnostic)] -#[diag(session_unsupported_crate_type_for_codegen_backend)] -pub(crate) struct UnsupportedCrateTypeForCodegenBackend { - pub(crate) crate_type: CrateType, - pub(crate) codegen_backend: &'static str, -} - -#[derive(Diagnostic)] -#[diag(session_unsupported_crate_type_for_target)] -pub(crate) struct UnsupportedCrateTypeForTarget<'a> { - pub(crate) crate_type: CrateType, - pub(crate) target_triple: &'a TargetTuple, -} - pub fn report_lit_error( psess: &ParseSess, err: LitError, diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 9b8913523f74..9224368f90d6 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -2,12 +2,11 @@ use std::path::Path; -use rustc_ast as ast; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use crate::Session; use crate::config::{CrateType, OutFileName, OutputFilenames, OutputType}; -use crate::errors::{self, CrateNameEmpty, FileIsNotWriteable, InvalidCharacterInCrateName}; +use crate::errors::{CrateNameEmpty, FileIsNotWriteable, InvalidCharacterInCrateName}; pub fn out_filename( sess: &Session, @@ -121,19 +120,6 @@ pub fn filename_for_input( } } -/// Returns default crate type for target -/// -/// Default crate type is used when crate type isn't provided neither -/// through cmd line arguments nor through crate attributes -/// -/// It is CrateType::Executable for all platforms but iOS as there is no -/// way to run iOS binaries anyway without jailbreaking and -/// interaction with Rust code through static library is the only -/// option for now -pub fn default_output_for_target(sess: &Session) -> CrateType { - if !sess.target.executables { CrateType::StaticLib } else { CrateType::Executable } -} - /// Checks if target supports crate_type as output pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool { if let CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro = crate_type { @@ -157,73 +143,3 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool false } - -pub fn collect_crate_types( - session: &Session, - backend_crate_types: &[CrateType], - codegen_backend_name: &'static str, - attrs: &[ast::Attribute], -) -> Vec { - // If we're generating a test executable, then ignore all other output - // styles at all other locations - if session.opts.test { - if !session.target.executables { - session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { - crate_type: CrateType::Executable, - target_triple: &session.opts.target_triple, - }); - return Vec::new(); - } - return vec![CrateType::Executable]; - } - - // Shadow `sdylib` crate type in interface build. - if session.opts.unstable_opts.build_sdylib_interface { - return vec![CrateType::Rlib]; - } - - // Only check command line flags if present. If no types are specified by - // command line, then reuse the empty `base` Vec to hold the types that - // will be found in crate attributes. - // JUSTIFICATION: before wrapper fn is available - #[allow(rustc::bad_opt_access)] - let mut base = session.opts.crate_types.clone(); - if base.is_empty() { - let attr_types = attrs.iter().filter_map(|a| { - if a.has_name(sym::crate_type) - && let Some(s) = a.value_str() - { - CrateType::try_from(s).ok() - } else { - None - } - }); - base.extend(attr_types); - if base.is_empty() { - base.push(default_output_for_target(session)); - } else { - base.sort(); - base.dedup(); - } - } - - base.retain(|crate_type| { - if invalid_output_for_target(session, *crate_type) { - session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { - crate_type: *crate_type, - target_triple: &session.opts.target_triple, - }); - false - } else if !backend_crate_types.contains(crate_type) { - session.dcx().emit_warn(errors::UnsupportedCrateTypeForCodegenBackend { - crate_type: *crate_type, - codegen_backend: codegen_backend_name, - }); - false - } else { - true - } - }); - - base -} diff --git a/tests/ui/attributes/crate-type-macro-call.rs b/tests/ui/attributes/crate-type-macro-call.rs index f885aa6d3091..0d074422d951 100644 --- a/tests/ui/attributes/crate-type-macro-call.rs +++ b/tests/ui/attributes/crate-type-macro-call.rs @@ -1,6 +1,5 @@ #![crate_type = foo!()] -//~^ ERROR cannot find macro `foo` -//~| WARN this was previously accepted +//~^ ERROR attribute value must be a literal macro_rules! foo { () => {"rlib"}; diff --git a/tests/ui/attributes/crate-type-macro-call.stderr b/tests/ui/attributes/crate-type-macro-call.stderr index 4253b8c5b5f6..690f09984710 100644 --- a/tests/ui/attributes/crate-type-macro-call.stderr +++ b/tests/ui/attributes/crate-type-macro-call.stderr @@ -1,25 +1,8 @@ -error: cannot find macro `foo` in the current scope when looking from the crate root +error: attribute value must be a literal --> $DIR/crate-type-macro-call.rs:1:17 | LL | #![crate_type = foo!()] - | ^^^ not found from the crate root - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124535 - = help: import `macro_rules` with `use` to make it callable above its definition - = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default + | ^^^^^^ error: aborting due to 1 previous error -Future incompatibility report: Future breakage diagnostic: -error: cannot find macro `foo` in the current scope when looking from the crate root - --> $DIR/crate-type-macro-call.rs:1:17 - | -LL | #![crate_type = foo!()] - | ^^^ not found from the crate root - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124535 - = help: import `macro_rules` with `use` to make it callable above its definition - = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default -