diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_driver_impl/src/lib.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/module.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_incremental/src/persist/fs.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_incremental/src/persist/load.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_interface/messages.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/errors.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/passes.rs | 105 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/util.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_parse/messages.ftl | 3 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/path.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_session/messages.ftl | 8 | ||||
| -rw-r--r-- | compiler/rustc_session/src/errors.rs | 27 | ||||
| -rw-r--r-- | compiler/rustc_session/src/output.rs | 89 |
16 files changed, 178 insertions, 164 deletions
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2bcc33241df..a2ddff7183e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -667,11 +667,12 @@ fn print_crate_info( return Compilation::Continue; }; let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); - let id = rustc_session::output::find_crate_name(sess, attrs); + let crate_name = passes::get_crate_name(sess, attrs); let crate_types = collect_crate_types(sess, attrs); for &style in &crate_types { - let fname = - rustc_session::output::filename_for_input(sess, style, id, &t_outputs); + let fname = rustc_session::output::filename_for_input( + sess, style, crate_name, &t_outputs, + ); println_info!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); } } @@ -680,8 +681,7 @@ fn print_crate_info( // no crate attributes, print out an error and exit return Compilation::Continue; }; - let id = rustc_session::output::find_crate_name(sess, attrs); - println_info!("{id}"); + println_info!("{}", passes::get_crate_name(sess, attrs)); } Cfg => { let mut cfgs = sess diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 9c35b26772b..e925052c607 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -183,12 +183,12 @@ pub(crate) fn mod_file_path_from_attr( let first_path = attrs.iter().find(|at| at.has_name(sym::path))?; let Some(path_sym) = first_path.value_str() else { // This check is here mainly to catch attempting to use a macro, - // such as #[path = concat!(...)]. This isn't currently supported - // because otherwise the InvocationCollector would need to defer - // loading a module until the #[path] attribute was expanded, and - // it doesn't support that (and would likely add a bit of - // complexity). Usually bad forms are checked in AstValidator (via - // `check_builtin_attribute`), but by the time that runs the macro + // such as `#[path = concat!(...)]`. This isn't supported because + // otherwise the `InvocationCollector` would need to defer loading + // a module until the `#[path]` attribute was expanded, and it + // doesn't support that (and would likely add a bit of complexity). + // Usually bad forms are checked during semantic analysis via + // `TyCtxt::check_mod_attrs`), but by the time that runs the macro // is expanded, and it doesn't give an error. validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, first_path, sym::path); }; diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 4ea171ab4a9..19cca48af61 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -117,8 +117,9 @@ use rustc_data_structures::{base_n, flock}; use rustc_fs_util::{LinkOrCopy, link_or_copy, try_canonicalize}; use rustc_middle::bug; use rustc_session::config::CrateType; -use rustc_session::output::{collect_crate_types, find_crate_name}; +use rustc_session::output::collect_crate_types; use rustc_session::{Session, StableCrateId}; +use rustc_span::Symbol; use tracing::debug; use crate::errors; @@ -211,7 +212,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) { +pub(crate) fn prepare_session_directory(sess: &Session, crate_name: Symbol) { if sess.opts.incremental.is_none() { return; } @@ -221,7 +222,7 @@ pub(crate) fn prepare_session_directory(sess: &Session) { debug!("prepare_session_directory"); // {incr-comp-dir}/{crate-name-and-disambiguator} - let crate_dir = crate_path(sess); + let crate_dir = crate_path(sess, crate_name); debug!("crate-dir: {}", crate_dir.display()); create_dir(sess, &crate_dir, "crate"); @@ -594,10 +595,9 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, &'static str> { Ok(UNIX_EPOCH + duration) } -fn crate_path(sess: &Session) -> PathBuf { +fn crate_path(sess: &Session, crate_name: Symbol) -> PathBuf { let incr_dir = sess.opts.incremental.as_ref().unwrap().clone(); - let crate_name = find_crate_name(sess, &[]); let crate_types = collect_crate_types(sess, &[]); let stable_crate_id = StableCrateId::new( crate_name, diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 48df84f3d09..7977bcc6891 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -11,6 +11,7 @@ use rustc_serialize::Decodable; use rustc_serialize::opaque::MemDecoder; use rustc_session::Session; use rustc_session::config::IncrementalStateAssertion; +use rustc_span::Symbol; use tracing::{debug, warn}; use super::data::*; @@ -203,9 +204,9 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache> { /// 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) -> DepGraph { +pub fn setup_dep_graph(sess: &Session, crate_name: Symbol) -> DepGraph { // `load_dep_graph` can only be called after `prepare_session_directory`. - prepare_session_directory(sess); + prepare_session_directory(sess, crate_name); let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess)); diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index 31123625369..43c69c8e571 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -6,6 +6,10 @@ interface_abi_required_feature_issue = for more information, see issue #116344 < interface_cant_emit_mir = could not emit MIR: {$error} +interface_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$crate_name}` != `{$attr_crate_name}` + +interface_crate_name_invalid = crate names cannot start with a `-`, but `{$crate_name}` has a leading hyphen + interface_emoji_identifier = identifiers cannot contain emoji: `{$ident}` diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index b62950d6709..c3b858d4f2e 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -5,6 +5,21 @@ use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] +#[diag(interface_crate_name_does_not_match)] +pub(crate) struct CrateNameDoesNotMatch { + #[primary_span] + pub(crate) span: Span, + pub(crate) crate_name: Symbol, + pub(crate) attr_crate_name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(interface_crate_name_invalid)] +pub(crate) struct CrateNameInvalid<'a> { + pub(crate) crate_name: &'a str, +} + +#[derive(Diagnostic)] #[diag(interface_ferris_identifier)] pub struct FerrisIdentifier { #[primary_span] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e5adcdb244f..fcebca3ecc9 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -28,10 +28,12 @@ use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::Resolver; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; -use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name}; +use rustc_session::output::{collect_crate_types, filename_for_input}; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; -use rustc_span::{ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Symbol, sym}; +use rustc_span::{ + ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, +}; use rustc_target::spec::PanicStrategy; use rustc_trait_selection::traits; use tracing::{info, instrument}; @@ -725,8 +727,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>( let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); - // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. - let crate_name = find_crate_name(sess, &pre_configured_attrs); + let crate_name = get_crate_name(sess, &pre_configured_attrs); let crate_types = collect_crate_types(sess, &pre_configured_attrs); let stable_crate_id = StableCrateId::new( crate_name, @@ -735,7 +736,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>( sess.cfg_version, ); let outputs = util::build_output_filenames(&pre_configured_attrs, sess); - let dep_graph = setup_dep_graph(sess); + let dep_graph = setup_dep_graph(sess, crate_name); let cstore = FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _); @@ -1080,23 +1081,85 @@ pub(crate) fn start_codegen<'tcx>( codegen } -fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { - if let Some(attr) = krate_attrs - .iter() - .find(|attr| attr.has_name(sym::recursion_limit) && attr.value_str().is_none()) +/// Compute and validate the crate name. +pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol { + // 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. + // We perform the validation step here instead of later to ensure it gets run + // in all code paths that require the crate name very early on, namely before + // macro expansion. + + let attr_crate_name = + validate_and_find_value_str_builtin_attr(sym::crate_name, sess, krate_attrs); + + let validate = |name, span| { + rustc_session::output::validate_crate_name(sess, name, span); + name + }; + + 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 + && attr_crate_name != crate_name + { + sess.dcx().emit_err(errors::CrateNameDoesNotMatch { + span, + crate_name, + attr_crate_name, + }); + } + return validate(crate_name, None); + } + + if let Some((crate_name, span)) = attr_crate_name { + return validate(crate_name, Some(span)); + } + + if let Input::File(ref path) = sess.io.input + && let Some(file_stem) = path.file_stem().and_then(|s| s.to_str()) { - // This is here mainly to check for using a macro, such as - // #![recursion_limit = foo!()]. That is not supported since that - // would require expanding this while in the middle of expansion, - // which needs to know the limit before expanding. Otherwise, - // validation would normally be caught in AstValidator (via - // `check_builtin_attribute`), but by the time that runs the macro - // is expanded, and it doesn't give an error. - validate_attr::emit_fatal_malformed_builtin_attribute( - &sess.psess, - attr, - sym::recursion_limit, - ); + if file_stem.starts_with('-') { + sess.dcx().emit_err(errors::CrateNameInvalid { crate_name: file_stem }); + } else { + return validate(Symbol::intern(&file_stem.replace('-', "_")), None); + } } + + sym::rust_out +} + +fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { + // We don't permit macro calls inside of the attribute (e.g., #![recursion_limit = `expand!()`]) + // because that would require expanding this while in the middle of expansion, which needs to + // know the limit before expanding. + let _ = validate_and_find_value_str_builtin_attr(sym::recursion_limit, sess, krate_attrs); rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess) } + +/// Validate *all* occurrences of the given "[value-str]" built-in attribute and return the first find. +/// +/// This validator is intended for built-in attributes whose value needs to be known very early +/// during compilation (namely, before macro expansion) and it mainly exists to reject macro calls +/// inside of the attributes, such as in `#![name = expand!()]`. Normal attribute validation happens +/// during semantic analysis via [`TyCtxt::check_mod_attrs`] which happens *after* macro expansion +/// when such macro calls (here: `expand`) have already been expanded and we can no longer check for +/// their presence. +/// +/// [value-str]: ast::Attribute::value_str +fn validate_and_find_value_str_builtin_attr( + name: Symbol, + sess: &Session, + krate_attrs: &[ast::Attribute], +) -> Option<(Symbol, Span)> { + let mut result = None; + // Validate *all* relevant attributes, not just the first occurrence. + for attr in ast::attr::filter_by_name(krate_attrs, name) { + let Some(value) = attr.value_str() else { + validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, attr, name) + }; + // Choose the first occurrence as our result. + result.get_or_insert((value, attr.span)); + } + result +} diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index e900ec14fca..bc2aae7cd87 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -433,11 +433,11 @@ pub(crate) fn check_attr_crate_type( } } else { // This is here mainly to check for using a macro, such as - // #![crate_type = foo!()]. That is not supported since the + // `#![crate_type = foo!()]`. That is not supported since the // crate type needs to be known very early in compilation long // before expansion. Otherwise, validation would normally be - // caught in AstValidator (via `check_builtin_attribute`), but - // by the time that runs the macro is expanded, and it doesn't + // caught during semantic analysis via `TyCtxt::check_mod_attrs`, + // but by the time that runs the macro is expanded, and it doesn't // give an error. validate_attr::emit_fatal_malformed_builtin_attribute( &sess.psess, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index d50bd18a1d7..563081c7240 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -743,9 +743,6 @@ parse_single_colon_import_path = expected `::`, found `:` .suggestion = use double colon .note = import paths are delimited using `::` -parse_single_colon_struct_type = found single colon in a struct field type path - .suggestion = write a path separator here - parse_static_with_generics = static items may not have generic parameters parse_struct_literal_body_without_path = diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 8f0e29c2769..dc03d6f9521 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3072,14 +3072,6 @@ pub(crate) struct BadItemKind { } #[derive(Diagnostic)] -#[diag(parse_single_colon_struct_type)] -pub(crate) struct SingleColonStructType { - #[primary_span] - #[suggestion(code = "::", applicability = "maybe-incorrect", style = "verbose")] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(parse_macro_rules_missing_bang)] pub(crate) struct MacroRulesMissingBang { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 637ed2774a2..c923717ecaf 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2043,9 +2043,6 @@ impl<'a> Parser<'a> { } self.expect_field_ty_separator()?; let ty = self.parse_ty()?; - if self.token == token::Colon && self.look_ahead(1, |t| *t != token::Colon) { - self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span }); - } let default = if self.token == token::Eq { self.bump(); let const_expr = self.parse_expr_anon_const()?; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 64bcb1a5a36..8ce749ec814 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1472,17 +1472,6 @@ impl<'a> Parser<'a> { let mut last_non_comma_dotdot_span = None; while self.token != token::CloseDelim(Delimiter::Brace) { - let attrs = match self.parse_outer_attributes() { - Ok(attrs) => attrs, - Err(err) => { - if let Some(delayed) = delayed_err { - delayed.emit(); - } - return Err(err); - } - }; - let lo = self.token.span; - // check that a comma comes after every field if !ate_comma { let err = if self.token == token::At { @@ -1585,6 +1574,17 @@ impl<'a> Parser<'a> { } } + let attrs = match self.parse_outer_attributes() { + Ok(attrs) => attrs, + Err(err) => { + if let Some(delayed) = delayed_err { + delayed.emit(); + } + return Err(err); + } + }; + let lo = self.token.span; + let field = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { let field = match this.parse_pat_field(lo, attrs) { Ok(field) => Ok(field), diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 576711e6677..b241aa892db 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -246,8 +246,19 @@ impl<'a> Parser<'a> { segments.push(segment); if self.is_import_coupler() || !self.eat_path_sep() { - if style == PathStyle::Expr - && self.may_recover() + let ok_for_recovery = self.may_recover() + && match style { + PathStyle::Expr => true, + PathStyle::Type if let Some((ident, _)) = self.prev_token.ident() => { + self.token == token::Colon + && ident.as_str().chars().all(|c| c.is_lowercase()) + && self.token.span.lo() == self.prev_token.span.hi() + && self + .look_ahead(1, |token| self.token.span.hi() == token.span.lo()) + } + _ => false, + }; + if ok_for_recovery && self.token == token::Colon && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) { diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index e5fba8cc5a2..74b8087e077 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -8,12 +8,8 @@ session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible session_cli_feature_diagnostic_help = add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable -session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}` - session_crate_name_empty = crate name must not be empty -session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen - session_embed_source_insufficient_dwarf_version = `-Zembed-source=y` requires at least `-Z dwarf-version=5` but DWARF version is {$dwarf_version} session_embed_source_requires_debug_info = `-Zembed-source=y` requires debug information to be enabled @@ -52,8 +48,8 @@ session_instrumentation_not_supported = {$us} instrumentation is not supported f session_int_literal_too_large = integer literal is too large .note = value exceeds limit of `{$limit}` -session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}` -session_invalid_character_in_create_name_help = you can either pass `--crate-name` on the command line or add `#![crate_name="…"]` to set the crate name +session_invalid_character_in_crate_name = invalid character {$character} in crate name: `{$crate_name}` + .help = you can either pass `--crate-name` on the command line or add `#![crate_name = "…"]` to set the crate name session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal .label = invalid suffix `{$suffix}` diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 75c3b2c7a85..71d8dbe44fe 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -213,21 +213,6 @@ pub(crate) struct FileWriteFail<'a> { } #[derive(Diagnostic)] -#[diag(session_crate_name_does_not_match)] -pub(crate) struct CrateNameDoesNotMatch { - #[primary_span] - pub(crate) span: Span, - pub(crate) s: Symbol, - pub(crate) name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(session_crate_name_invalid)] -pub(crate) struct CrateNameInvalid<'a> { - pub(crate) s: &'a str, -} - -#[derive(Diagnostic)] #[diag(session_crate_name_empty)] pub(crate) struct CrateNameEmpty { #[primary_span] @@ -235,20 +220,14 @@ pub(crate) struct CrateNameEmpty { } #[derive(Diagnostic)] -#[diag(session_invalid_character_in_create_name)] +#[diag(session_invalid_character_in_crate_name)] pub(crate) struct InvalidCharacterInCrateName { #[primary_span] pub(crate) span: Option<Span>, pub(crate) character: char, pub(crate) crate_name: Symbol, - #[subdiagnostic] - pub(crate) crate_name_help: Option<InvalidCrateNameHelp>, -} - -#[derive(Subdiagnostic)] -pub(crate) enum InvalidCrateNameHelp { - #[help(session_invalid_character_in_create_name_help)] - AddCrateName, + #[help] + pub(crate) help: Option<()>, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index ff0419d06bf..b37a80274c0 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -2,15 +2,12 @@ use std::path::Path; -use rustc_ast::{self as ast, attr}; +use rustc_ast as ast; use rustc_span::{Span, Symbol, sym}; use crate::Session; -use crate::config::{self, CrateType, Input, OutFileName, OutputFilenames, OutputType}; -use crate::errors::{ - self, CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, - InvalidCharacterInCrateName, InvalidCrateNameHelp, -}; +use crate::config::{self, CrateType, OutFileName, OutputFilenames, OutputType}; +use crate::errors::{self, CrateNameEmpty, FileIsNotWriteable, InvalidCharacterInCrateName}; pub fn out_filename( sess: &Session, @@ -49,69 +46,31 @@ fn is_writeable(p: &Path) -> bool { } } -pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol { - let validate = |s: Symbol, span: Option<Span>| { - validate_crate_name(sess, s, span); - s - }; - - // Look in attributes 100% of the time to make sure the attribute is marked - // as used. After doing this, however, we still prioritize a crate name from - // the command line over one found in the #[crate_name] attribute. If we - // find both we ensure that they're the same later on as well. - let attr_crate_name = - attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s))); - - if let Some(ref s) = sess.opts.crate_name { - let s = Symbol::intern(s); - if let Some((attr, name)) = attr_crate_name { - if name != s { - sess.dcx().emit_err(CrateNameDoesNotMatch { span: attr.span, s, name }); - } - } - return validate(s, None); - } +/// Validate the given crate name. +/// +/// Note that this validation is more permissive than identifier parsing. It considers +/// non-empty sequences of alphanumeric and underscore characters to be valid crate names. +/// Most notably, it accepts names starting with a numeric character like `0`! +/// +/// Furthermore, this shouldn't be taken as the canonical crate name validator. +/// Other places may use a more restrictive grammar (e.g., identifier or ASCII identifier). +pub fn validate_crate_name(sess: &Session, crate_name: Symbol, span: Option<Span>) { + let mut guar = None; - if let Some((attr, s)) = attr_crate_name { - return validate(s, Some(attr.span)); - } - if let Input::File(ref path) = sess.io.input { - if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { - if s.starts_with('-') { - sess.dcx().emit_err(CrateNameInvalid { s }); - } else { - return validate(Symbol::intern(&s.replace('-', "_")), None); - } - } + if crate_name.is_empty() { + guar = Some(sess.dcx().emit_err(CrateNameEmpty { span })); } - sym::rust_out -} - -pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) { - let mut guar = None; - { - if s.is_empty() { - guar = Some(sess.dcx().emit_err(CrateNameEmpty { span: sp })); - } - for c in s.as_str().chars() { - if c.is_alphanumeric() { - continue; - } - if c == '_' { - continue; - } - guar = Some(sess.dcx().emit_err(InvalidCharacterInCrateName { - span: sp, - character: c, - crate_name: s, - crate_name_help: if sp.is_none() { - Some(InvalidCrateNameHelp::AddCrateName) - } else { - None - }, - })); + for c in crate_name.as_str().chars() { + if c.is_alphanumeric() || c == '_' { + continue; } + guar = Some(sess.dcx().emit_err(InvalidCharacterInCrateName { + span, + character: c, + crate_name, + help: span.is_none().then_some(()), + })); } if let Some(guar) = guar { |
