Move collect_crate_types to rustc_interface, and use new attribute parser

This commit is contained in:
Jamie Hill-Daniel 2026-01-21 17:27:35 +00:00
parent 66b78b700b
commit e73dfaa62f
9 changed files with 124 additions and 133 deletions

View file

@ -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(

View file

@ -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}`

View file

@ -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,
}

View file

@ -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<T, F: for<'tcx> 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<CrateType> {
// 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::<Early>::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,

View file

@ -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

View file

@ -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,

View file

@ -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<CrateType> {
// 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
}

View file

@ -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"};

View file

@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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